[dev.regabi] cmd/compile: introduce cmd/compile/internal/ir [generated]

If we want to break up package gc at all, we will need to move
the compiler IR it defines into a separate package that can be
imported by packages that gc itself imports. This CL does that.
It also removes the TINT8 etc aliases so that all code is clear
about which package things are coming from.

This CL is automatically generated by the script below.
See the comments in the script for details about the changes.

[git-generate]
cd src/cmd/compile/internal/gc

rf '
        # These names were never fully qualified
        # when the types package was added.
        # Do it now, to avoid confusion about where they live.
        inline -rm \
                Txxx \
                TINT8 \
                TUINT8 \
                TINT16 \
                TUINT16 \
                TINT32 \
                TUINT32 \
                TINT64 \
                TUINT64 \
                TINT \
                TUINT \
                TUINTPTR \
                TCOMPLEX64 \
                TCOMPLEX128 \
                TFLOAT32 \
                TFLOAT64 \
                TBOOL \
                TPTR \
                TFUNC \
                TSLICE \
                TARRAY \
                TSTRUCT \
                TCHAN \
                TMAP \
                TINTER \
                TFORW \
                TANY \
                TSTRING \
                TUNSAFEPTR \
                TIDEAL \
                TNIL \
                TBLANK \
                TFUNCARGS \
                TCHANARGS \
                NTYPE \
                BADWIDTH

        # esc.go and escape.go do not need to be split.
        # Append esc.go onto the end of escape.go.
        mv esc.go escape.go

        # Pull out the type format installation from func Main,
        # so it can be carried into package ir.
        mv Main:/Sconv.=/-0,/TypeLinkSym/-1 InstallTypeFormats

        # Names that need to be exported for use by code left in gc.
        mv Isconst IsConst
        mv asNode AsNode
        mv asNodes AsNodes
        mv asTypesNode AsTypesNode
        mv basicnames BasicTypeNames
        mv builtinpkg BuiltinPkg
        mv consttype ConstType
        mv dumplist DumpList
        mv fdumplist FDumpList
        mv fmtMode FmtMode
        mv goopnames OpNames
        mv inspect Inspect
        mv inspectList InspectList
        mv localpkg LocalPkg
        mv nblank BlankNode
        mv numImport NumImport
        mv opprec OpPrec
        mv origSym OrigSym
        mv stmtwithinit StmtWithInit
        mv dump DumpAny
        mv fdump FDumpAny
        mv nod Nod
        mv nodl NodAt
        mv newname NewName
        mv newnamel NewNameAt
        mv assertRepresents AssertValidTypeForConst
        mv represents ValidTypeForConst
        mv nodlit NewLiteral

        # Types and fields that need to be exported for use by gc.
        mv nowritebarrierrecCallSym SymAndPos
        mv SymAndPos.lineno SymAndPos.Pos
        mv SymAndPos.target SymAndPos.Sym

        mv Func.lsym Func.LSym
        mv Func.setWBPos Func.SetWBPos
        mv Func.numReturns Func.NumReturns
        mv Func.numDefers Func.NumDefers
        mv Func.nwbrCalls Func.NWBRCalls

        # initLSym is an algorithm left behind in gc,
        # not an operation on Func itself.
        mv Func.initLSym initLSym

        mv nodeQueue NodeQueue
        mv NodeQueue.empty NodeQueue.Empty
        mv NodeQueue.popLeft NodeQueue.PopLeft
        mv NodeQueue.pushRight NodeQueue.PushRight

        # Many methods on Node are actually algorithms that
        # would apply to any node implementation.
        # Those become plain functions.
        mv Node.funcname FuncName
        mv Node.isBlank IsBlank
        mv Node.isGoConst isGoConst
        mv Node.isNil IsNil
        mv Node.isParamHeapCopy isParamHeapCopy
        mv Node.isParamStackCopy isParamStackCopy
        mv Node.isSimpleName isSimpleName
        mv Node.mayBeShared MayBeShared
        mv Node.pkgFuncName PkgFuncName
        mv Node.backingArrayPtrLen backingArrayPtrLen
        mv Node.isterminating isTermNode
        mv Node.labeledControl labeledControl
        mv Nodes.isterminating isTermNodes
        mv Nodes.sigerr fmtSignature
        mv Node.MethodName methodExprName
        mv Node.MethodFunc methodExprFunc
        mv Node.IsMethod IsMethod

        # Every node will need to implement RawCopy;
        # Copy and SepCopy algorithms will use it.
        mv Node.rawcopy Node.RawCopy
        mv Node.copy Copy
        mv Node.sepcopy SepCopy

        # Extract Node.Format method body into func FmtNode,
        # but leave method wrapper behind.
        mv Node.Format:0,$ FmtNode

        # Formatting helpers that will apply to all node implementations.
        mv Node.Line Line
        mv Node.exprfmt exprFmt
        mv Node.jconv jconvFmt
        mv Node.modeString modeString
        mv Node.nconv nconvFmt
        mv Node.nodedump nodeDumpFmt
        mv Node.nodefmt nodeFmt
        mv Node.stmtfmt stmtFmt

	# Constant support needed for code moving to ir.
        mv okforconst OKForConst
        mv vconv FmtConst
        mv int64Val Int64Val
        mv float64Val Float64Val
        mv Node.ValueInterface ConstValue

        # Organize code into files.
        mv LocalPkg BuiltinPkg ir.go
        mv NumImport InstallTypeFormats Line fmt.go
        mv syntax.go Nod NodAt NewNameAt Class Pxxx PragmaFlag Nointerface SymAndPos \
                AsNode AsTypesNode BlankNode OrigSym \
                Node.SliceBounds Node.SetSliceBounds Op.IsSlice3 \
                IsConst Node.Int64Val Node.CanInt64 Node.Uint64Val Node.BoolVal Node.StringVal \
                Node.RawCopy SepCopy Copy \
                IsNil IsBlank IsMethod \
                Node.Typ Node.StorageClass node.go
        mv ConstType ConstValue Int64Val Float64Val AssertValidTypeForConst ValidTypeForConst NewLiteral idealType OKForConst val.go

        # Move files to new ir package.
        mv bitset.go class_string.go dump.go fmt.go \
                ir.go node.go op_string.go val.go \
                sizeof_test.go cmd/compile/internal/ir
'

: # fix mkbuiltin.go to generate the changes made to builtin.go during rf
sed -i '' '
        s/\[T/[types.T/g
        s/\*Node/*ir.Node/g
        /internal\/types/c \
                fmt.Fprintln(&b, `import (`) \
                fmt.Fprintln(&b, `      "cmd/compile/internal/ir"`) \
                fmt.Fprintln(&b, `      "cmd/compile/internal/types"`) \
                fmt.Fprintln(&b, `)`)
' mkbuiltin.go
gofmt -w mkbuiltin.go

: # update cmd/dist to add internal/ir
cd ../../../dist
sed -i '' '/compile.internal.gc/a\
        "cmd/compile/internal/ir",
' buildtool.go
gofmt -w buildtool.go

: # update cmd/compile TestFormats
cd ../..
go install std cmd
cd cmd/compile
go test -u || go test  # first one updates but fails; second passes

Change-Id: I5f7caf6b20629b51970279e81231a3574d5b51db
Reviewed-on: https://go-review.googlesource.com/c/go/+/273008
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-11-19 21:09:22 -05:00
parent 331b8b4797
commit 84e2bd611f
65 changed files with 6626 additions and 6602 deletions

View file

@ -22,14 +22,14 @@ package main_test
var knownFormats = map[string]string{ var knownFormats = map[string]string{
"*bytes.Buffer %s": "", "*bytes.Buffer %s": "",
"*cmd/compile/internal/gc.EscLocation %v": "", "*cmd/compile/internal/gc.EscLocation %v": "",
"*cmd/compile/internal/gc.Node %#v": "", "*cmd/compile/internal/ir.Node %#v": "",
"*cmd/compile/internal/gc.Node %+S": "", "*cmd/compile/internal/ir.Node %+S": "",
"*cmd/compile/internal/gc.Node %+v": "", "*cmd/compile/internal/ir.Node %+v": "",
"*cmd/compile/internal/gc.Node %L": "", "*cmd/compile/internal/ir.Node %L": "",
"*cmd/compile/internal/gc.Node %S": "", "*cmd/compile/internal/ir.Node %S": "",
"*cmd/compile/internal/gc.Node %j": "", "*cmd/compile/internal/ir.Node %j": "",
"*cmd/compile/internal/gc.Node %p": "", "*cmd/compile/internal/ir.Node %p": "",
"*cmd/compile/internal/gc.Node %v": "", "*cmd/compile/internal/ir.Node %v": "",
"*cmd/compile/internal/ssa.Block %s": "", "*cmd/compile/internal/ssa.Block %s": "",
"*cmd/compile/internal/ssa.Block %v": "", "*cmd/compile/internal/ssa.Block %v": "",
"*cmd/compile/internal/ssa.Func %s": "", "*cmd/compile/internal/ssa.Func %s": "",
@ -78,18 +78,18 @@ var knownFormats = map[string]string{
"byte %q": "", "byte %q": "",
"byte %v": "", "byte %v": "",
"cmd/compile/internal/arm.shift %d": "", "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.initKind %d": "",
"cmd/compile/internal/gc.itag %v": "", "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.BranchPrediction %d": "",
"cmd/compile/internal/ssa.Edge %v": "", "cmd/compile/internal/ssa.Edge %v": "",
"cmd/compile/internal/ssa.GCNode %v": "", "cmd/compile/internal/ssa.GCNode %v": "",
@ -162,8 +162,8 @@ var knownFormats = map[string]string{
"interface{} %q": "", "interface{} %q": "",
"interface{} %s": "", "interface{} %s": "",
"interface{} %v": "", "interface{} %v": "",
"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "", "map[*cmd/compile/internal/ir.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/ir.Node %v": "",
"map[cmd/compile/internal/ssa.ID]uint32 %v": "", "map[cmd/compile/internal/ssa.ID]uint32 %v": "",
"map[int64]uint32 %v": "", "map[int64]uint32 %v": "",
"math/big.Accuracy %s": "", "math/big.Accuracy %s": "",

View file

@ -11,6 +11,7 @@ import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/gc" "cmd/compile/internal/gc"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
@ -545,7 +546,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case *obj.LSym: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *gc.Node: case *ir.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:

View file

@ -9,6 +9,7 @@ import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/gc" "cmd/compile/internal/gc"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
@ -395,7 +396,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case *obj.LSym: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *gc.Node: case *ir.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
"fmt" "fmt"
@ -70,11 +71,11 @@ func EqCanPanic(t *types.Type) bool {
switch t.Etype { switch t.Etype {
default: default:
return false return false
case TINTER: case types.TINTER:
return true return true
case TARRAY: case types.TARRAY:
return EqCanPanic(t.Elem()) return EqCanPanic(t.Elem())
case TSTRUCT: case types.TSTRUCT:
for _, f := range t.FieldSlice() { for _, f := range t.FieldSlice() {
if !f.Sym.IsBlank() && EqCanPanic(f.Type) { if !f.Sym.IsBlank() && EqCanPanic(f.Type) {
return true return true
@ -120,45 +121,45 @@ func algtype1(t *types.Type) (AlgKind, *types.Type) {
} }
switch t.Etype { switch t.Etype {
case TANY, TFORW: case types.TANY, types.TFORW:
// will be defined later. // will be defined later.
return ANOEQ, t return ANOEQ, t
case TINT8, TUINT8, TINT16, TUINT16, case types.TINT8, types.TUINT8, types.TINT16, types.TUINT16,
TINT32, TUINT32, TINT64, TUINT64, types.TINT32, types.TUINT32, types.TINT64, types.TUINT64,
TINT, TUINT, TUINTPTR, types.TINT, types.TUINT, types.TUINTPTR,
TBOOL, TPTR, types.TBOOL, types.TPTR,
TCHAN, TUNSAFEPTR: types.TCHAN, types.TUNSAFEPTR:
return AMEM, nil return AMEM, nil
case TFUNC, TMAP: case types.TFUNC, types.TMAP:
return ANOEQ, t return ANOEQ, t
case TFLOAT32: case types.TFLOAT32:
return AFLOAT32, nil return AFLOAT32, nil
case TFLOAT64: case types.TFLOAT64:
return AFLOAT64, nil return AFLOAT64, nil
case TCOMPLEX64: case types.TCOMPLEX64:
return ACPLX64, nil return ACPLX64, nil
case TCOMPLEX128: case types.TCOMPLEX128:
return ACPLX128, nil return ACPLX128, nil
case TSTRING: case types.TSTRING:
return ASTRING, nil return ASTRING, nil
case TINTER: case types.TINTER:
if t.IsEmptyInterface() { if t.IsEmptyInterface() {
return ANILINTER, nil return ANILINTER, nil
} }
return AINTER, nil return AINTER, nil
case TSLICE: case types.TSLICE:
return ANOEQ, t return ANOEQ, t
case TARRAY: case types.TARRAY:
a, bad := algtype1(t.Elem()) a, bad := algtype1(t.Elem())
switch a { switch a {
case AMEM: case AMEM:
@ -178,7 +179,7 @@ func algtype1(t *types.Type) (AlgKind, *types.Type) {
return ASPECIAL, nil return ASPECIAL, nil
case TSTRUCT: case types.TSTRUCT:
fields := t.FieldSlice() fields := t.FieldSlice()
// One-field struct is same as that one field alone. // One-field struct is same as that one field alone.
@ -288,19 +289,19 @@ func genhash(t *types.Type) *obj.LSym {
} }
base.Pos = autogeneratedPos // less confusing than end of input base.Pos = autogeneratedPos // less confusing than end of input
dclcontext = PEXTERN dclcontext = ir.PEXTERN
// func sym(p *T, h uintptr) uintptr // func sym(p *T, h uintptr) uintptr
tfn := nod(OTFUNC, nil, nil) tfn := ir.Nod(ir.OTFUNC, nil, nil)
tfn.List.Set2( tfn.List.Set2(
namedfield("p", types.NewPtr(t)), 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) fn := dclfunc(sym, tfn)
np := asNode(tfn.Type.Params().Field(0).Nname) np := ir.AsNode(tfn.Type.Params().Field(0).Nname)
nh := asNode(tfn.Type.Params().Field(1).Nname) nh := ir.AsNode(tfn.Type.Params().Field(1).Nname)
switch t.Etype { switch t.Etype {
case types.TARRAY: case types.TARRAY:
@ -309,23 +310,23 @@ func genhash(t *types.Type) *obj.LSym {
// pure memory. // pure memory.
hashel := hashfor(t.Elem()) hashel := hashfor(t.Elem())
n := nod(ORANGE, nil, nod(ODEREF, np, nil)) n := ir.Nod(ir.ORANGE, nil, ir.Nod(ir.ODEREF, np, nil))
ni := newname(lookup("i")) ni := NewName(lookup("i"))
ni.Type = types.Types[TINT] ni.Type = types.Types[types.TINT]
n.List.Set1(ni) n.List.Set1(ni)
n.SetColas(true) n.SetColas(true)
colasdefn(n.List.Slice(), n) colasdefn(n.List.Slice(), n)
ni = n.List.First() ni = n.List.First()
// h = hashel(&p[i], h) // 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) nx.SetBounded(true)
na := nod(OADDR, nx, nil) na := ir.Nod(ir.OADDR, nx, nil)
call.List.Append(na) call.List.Append(na)
call.List.Append(nh) call.List.Append(nh)
n.Nbody.Append(nod(OAS, nh, call)) n.Nbody.Append(ir.Nod(ir.OAS, nh, call))
fn.Nbody.Append(n) fn.Nbody.Append(n)
@ -344,12 +345,12 @@ func genhash(t *types.Type) *obj.LSym {
// Hash non-memory fields with appropriate hash function. // Hash non-memory fields with appropriate hash function.
if !IsRegularMemory(f.Type) { if !IsRegularMemory(f.Type) {
hashel := hashfor(f.Type) hashel := hashfor(f.Type)
call := nod(OCALL, hashel, nil) call := ir.Nod(ir.OCALL, hashel, nil)
nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages? nx := nodSym(ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
na := nod(OADDR, nx, nil) na := ir.Nod(ir.OADDR, nx, nil)
call.List.Append(na) call.List.Append(na)
call.List.Append(nh) call.List.Append(nh)
fn.Nbody.Append(nod(OAS, nh, call)) fn.Nbody.Append(ir.Nod(ir.OAS, nh, call))
i++ i++
continue continue
} }
@ -359,24 +360,24 @@ func genhash(t *types.Type) *obj.LSym {
// h = hashel(&p.first, size, h) // h = hashel(&p.first, size, h)
hashel := hashmem(f.Type) hashel := hashmem(f.Type)
call := nod(OCALL, hashel, nil) call := ir.Nod(ir.OCALL, hashel, nil)
nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages? nx := nodSym(ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
na := nod(OADDR, nx, nil) na := ir.Nod(ir.OADDR, nx, nil)
call.List.Append(na) call.List.Append(na)
call.List.Append(nh) call.List.Append(nh)
call.List.Append(nodintconst(size)) call.List.Append(nodintconst(size))
fn.Nbody.Append(nod(OAS, nh, call)) fn.Nbody.Append(ir.Nod(ir.OAS, nh, call))
i = next i = next
} }
} }
r := nod(ORETURN, nil, nil) r := ir.Nod(ir.ORETURN, nil, nil)
r.List.Append(nh) r.List.Append(nh)
fn.Nbody.Append(r) fn.Nbody.Append(r)
if base.Flag.LowerR != 0 { if base.Flag.LowerR != 0 {
dumplist("genhash body", fn.Nbody) ir.DumpList("genhash body", fn.Nbody)
} }
funcbody() funcbody()
@ -403,7 +404,7 @@ func genhash(t *types.Type) *obj.LSym {
return closure return closure
} }
func hashfor(t *types.Type) *Node { func hashfor(t *types.Type) *ir.Node {
var sym *types.Sym var sym *types.Sym
switch a, _ := algtype1(t); a { switch a, _ := algtype1(t); a {
@ -429,13 +430,13 @@ func hashfor(t *types.Type) *Node {
sym = typesymprefix(".hash", t) sym = typesymprefix(".hash", t)
} }
n := newname(sym) n := NewName(sym)
setNodeNameFunc(n) setNodeNameFunc(n)
n.Type = functype(nil, []*Node{ n.Type = functype(nil, []*ir.Node{
anonfield(types.NewPtr(t)), anonfield(types.NewPtr(t)),
anonfield(types.Types[TUINTPTR]), anonfield(types.Types[types.TUINTPTR]),
}, []*Node{ }, []*ir.Node{
anonfield(types.Types[TUINTPTR]), anonfield(types.Types[types.TUINTPTR]),
}) })
return n return n
} }
@ -517,20 +518,20 @@ func geneq(t *types.Type) *obj.LSym {
// Autogenerate code for equality of structs and arrays. // Autogenerate code for equality of structs and arrays.
base.Pos = autogeneratedPos // less confusing than end of input base.Pos = autogeneratedPos // less confusing than end of input
dclcontext = PEXTERN dclcontext = ir.PEXTERN
// func sym(p, q *T) bool // func sym(p, q *T) bool
tfn := nod(OTFUNC, nil, nil) tfn := ir.Nod(ir.OTFUNC, nil, nil)
tfn.List.Set2( tfn.List.Set2(
namedfield("p", types.NewPtr(t)), namedfield("p", types.NewPtr(t)),
namedfield("q", 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) fn := dclfunc(sym, tfn)
np := asNode(tfn.Type.Params().Field(0).Nname) np := ir.AsNode(tfn.Type.Params().Field(0).Nname)
nq := asNode(tfn.Type.Params().Field(1).Nname) nq := ir.AsNode(tfn.Type.Params().Field(1).Nname)
nr := asNode(tfn.Type.Results().Field(0).Nname) nr := ir.AsNode(tfn.Type.Results().Field(0).Nname)
// Label to jump to if an equality test fails. // Label to jump to if an equality test fails.
neq := autolabel(".neq") neq := autolabel(".neq")
@ -542,7 +543,7 @@ func geneq(t *types.Type) *obj.LSym {
default: default:
base.Fatalf("geneq %v", t) base.Fatalf("geneq %v", t)
case TARRAY: case types.TARRAY:
nelem := t.NumElem() nelem := t.NumElem()
// checkAll generates code to check the equality of all array elements. // checkAll generates code to check the equality of all array elements.
@ -566,15 +567,15 @@ func geneq(t *types.Type) *obj.LSym {
// //
// TODO(josharian): consider doing some loop unrolling // TODO(josharian): consider doing some loop unrolling
// for larger nelem as well, processing a few elements at a time in a loop. // 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 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 := p[i]
pi := nod(OINDEX, np, i) pi := ir.Nod(ir.OINDEX, np, i)
pi.SetBounded(true) pi.SetBounded(true)
pi.Type = t.Elem() pi.Type = t.Elem()
// qi := q[i] // qi := q[i]
qi := nod(OINDEX, nq, i) qi := ir.Nod(ir.OINDEX, nq, i)
qi.SetBounded(true) qi.SetBounded(true)
qi.Type = t.Elem() qi.Type = t.Elem()
return eq(pi, qi) return eq(pi, qi)
@ -588,68 +589,68 @@ func geneq(t *types.Type) *obj.LSym {
// Generate a series of checks. // Generate a series of checks.
for i := int64(0); i < nelem; i++ { for i := int64(0); i < nelem; i++ {
// if check {} else { goto neq } // if check {} else { goto neq }
nif := nod(OIF, checkIdx(nodintconst(i)), nil) nif := ir.Nod(ir.OIF, checkIdx(nodintconst(i)), nil)
nif.Rlist.Append(nodSym(OGOTO, nil, neq)) nif.Rlist.Append(nodSym(ir.OGOTO, nil, neq))
fn.Nbody.Append(nif) fn.Nbody.Append(nif)
} }
if last { if last {
fn.Nbody.Append(nod(OAS, nr, checkIdx(nodintconst(nelem)))) fn.Nbody.Append(ir.Nod(ir.OAS, nr, checkIdx(nodintconst(nelem))))
} }
} else { } else {
// Generate a for loop. // Generate a for loop.
// for i := 0; i < nelem; i++ // for i := 0; i < nelem; i++
i := temp(types.Types[TINT]) i := temp(types.Types[types.TINT])
init := nod(OAS, i, nodintconst(0)) init := ir.Nod(ir.OAS, i, nodintconst(0))
cond := nod(OLT, i, nodintconst(nelem)) cond := ir.Nod(ir.OLT, i, nodintconst(nelem))
post := nod(OAS, i, nod(OADD, i, nodintconst(1))) post := ir.Nod(ir.OAS, i, ir.Nod(ir.OADD, i, nodintconst(1)))
loop := nod(OFOR, cond, post) loop := ir.Nod(ir.OFOR, cond, post)
loop.Ninit.Append(init) loop.Ninit.Append(init)
// if eq(pi, qi) {} else { goto neq } // if eq(pi, qi) {} else { goto neq }
nif := nod(OIF, checkIdx(i), nil) nif := ir.Nod(ir.OIF, checkIdx(i), nil)
nif.Rlist.Append(nodSym(OGOTO, nil, neq)) nif.Rlist.Append(nodSym(ir.OGOTO, nil, neq))
loop.Nbody.Append(nif) loop.Nbody.Append(nif)
fn.Nbody.Append(loop) fn.Nbody.Append(loop)
if last { if last {
fn.Nbody.Append(nod(OAS, nr, nodbool(true))) fn.Nbody.Append(ir.Nod(ir.OAS, nr, nodbool(true)))
} }
} }
} }
switch t.Elem().Etype { switch t.Elem().Etype {
case TSTRING: case types.TSTRING:
// Do two loops. First, check that all the lengths match (cheap). // Do two loops. First, check that all the lengths match (cheap).
// Second, check that all the contents match (expensive). // Second, check that all the contents match (expensive).
// TODO: when the array size is small, unroll the length match checks. // 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. // Compare lengths.
eqlen, _ := eqstring(pi, qi) eqlen, _ := eqstring(pi, qi)
return eqlen return eqlen
}) })
checkAll(1, true, func(pi, qi *Node) *Node { checkAll(1, true, func(pi, qi *ir.Node) *ir.Node {
// Compare contents. // Compare contents.
_, eqmem := eqstring(pi, qi) _, eqmem := eqstring(pi, qi)
return eqmem return eqmem
}) })
case TFLOAT32, TFLOAT64: case types.TFLOAT32, types.TFLOAT64:
checkAll(2, true, func(pi, qi *Node) *Node { checkAll(2, true, func(pi, qi *ir.Node) *ir.Node {
// p[i] == q[i] // p[i] == q[i]
return nod(OEQ, pi, qi) return ir.Nod(ir.OEQ, pi, qi)
}) })
// TODO: pick apart structs, do them piecemeal too // TODO: pick apart structs, do them piecemeal too
default: default:
checkAll(1, true, func(pi, qi *Node) *Node { checkAll(1, true, func(pi, qi *ir.Node) *ir.Node {
// p[i] == q[i] // 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. // Build a list of conditions to satisfy.
// The conditions are a list-of-lists. Conditions are reorderable // The conditions are a list-of-lists. Conditions are reorderable
// within each inner list. The outer lists must be evaluated in order. // within each inner list. The outer lists must be evaluated in order.
var conds [][]*Node var conds [][]*ir.Node
conds = append(conds, []*Node{}) conds = append(conds, []*ir.Node{})
and := func(n *Node) { and := func(n *ir.Node) {
i := len(conds) - 1 i := len(conds) - 1
conds[i] = append(conds[i], n) conds[i] = append(conds[i], n)
} }
@ -669,21 +670,21 @@ func geneq(t *types.Type) *obj.LSym {
if !IsRegularMemory(f.Type) { if !IsRegularMemory(f.Type) {
if EqCanPanic(f.Type) { if EqCanPanic(f.Type) {
// Enforce ordering by starting a new set of reorderable conditions. // 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) p := nodSym(ir.OXDOT, np, f.Sym)
q := nodSym(OXDOT, nq, f.Sym) q := nodSym(ir.OXDOT, nq, f.Sym)
switch { switch {
case f.Type.IsString(): case f.Type.IsString():
eqlen, eqmem := eqstring(p, q) eqlen, eqmem := eqstring(p, q)
and(eqlen) and(eqlen)
and(eqmem) and(eqmem)
default: default:
and(nod(OEQ, p, q)) and(ir.Nod(ir.OEQ, p, q))
} }
if EqCanPanic(f.Type) { if EqCanPanic(f.Type) {
// Also enforce ordering after something that can panic. // Also enforce ordering after something that can panic.
conds = append(conds, []*Node{}) conds = append(conds, []*ir.Node{})
} }
i++ i++
continue continue
@ -708,10 +709,10 @@ func geneq(t *types.Type) *obj.LSym {
// Sort conditions to put runtime calls last. // Sort conditions to put runtime calls last.
// Preserve the rest of the ordering. // Preserve the rest of the ordering.
var flatConds []*Node var flatConds []*ir.Node
for _, c := range conds { for _, c := range conds {
isCall := func(n *Node) bool { isCall := func(n *ir.Node) bool {
return n.Op == OCALL || n.Op == OCALLFUNC return n.Op == ir.OCALL || n.Op == ir.OCALLFUNC
} }
sort.SliceStable(c, func(i, j int) bool { sort.SliceStable(c, func(i, j int) bool {
return !isCall(c[i]) && isCall(c[j]) return !isCall(c[i]) && isCall(c[j])
@ -720,42 +721,42 @@ func geneq(t *types.Type) *obj.LSym {
} }
if len(flatConds) == 0 { if len(flatConds) == 0 {
fn.Nbody.Append(nod(OAS, nr, nodbool(true))) fn.Nbody.Append(ir.Nod(ir.OAS, nr, nodbool(true)))
} else { } else {
for _, c := range flatConds[:len(flatConds)-1] { for _, c := range flatConds[:len(flatConds)-1] {
// if cond {} else { goto neq } // if cond {} else { goto neq }
n := nod(OIF, c, nil) n := ir.Nod(ir.OIF, c, nil)
n.Rlist.Append(nodSym(OGOTO, nil, neq)) n.Rlist.Append(nodSym(ir.OGOTO, nil, neq))
fn.Nbody.Append(n) 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: // ret:
// return // return
ret := autolabel(".ret") ret := autolabel(".ret")
fn.Nbody.Append(nodSym(OLABEL, nil, ret)) fn.Nbody.Append(nodSym(ir.OLABEL, nil, ret))
fn.Nbody.Append(nod(ORETURN, nil, nil)) fn.Nbody.Append(ir.Nod(ir.ORETURN, nil, nil))
// neq: // neq:
// r = false // r = false
// return (or goto ret) // return (or goto ret)
fn.Nbody.Append(nodSym(OLABEL, nil, neq)) fn.Nbody.Append(nodSym(ir.OLABEL, nil, neq))
fn.Nbody.Append(nod(OAS, nr, nodbool(false))) fn.Nbody.Append(ir.Nod(ir.OAS, nr, nodbool(false)))
if EqCanPanic(t) || hasCall(fn) { if EqCanPanic(t) || hasCall(fn) {
// Epilogue is large, so share it with the equal case. // 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 { } else {
// Epilogue is small, so don't bother sharing. // 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. // TODO(khr): the epilogue size detection condition above isn't perfect.
// We should really do a generic CL that shares epilogues across // We should really do a generic CL that shares epilogues across
// the board. See #24936. // the board. See #24936.
if base.Flag.LowerR != 0 { if base.Flag.LowerR != 0 {
dumplist("geneq body", fn.Nbody) ir.DumpList("geneq body", fn.Nbody)
} }
funcbody() funcbody()
@ -784,8 +785,8 @@ func geneq(t *types.Type) *obj.LSym {
return closure return closure
} }
func hasCall(n *Node) bool { func hasCall(n *ir.Node) bool {
if n.Op == OCALL || n.Op == OCALLFUNC { if n.Op == ir.OCALL || n.Op == ir.OCALLFUNC {
return true return true
} }
if n.Left != nil && hasCall(n.Left) { if n.Left != nil && hasCall(n.Left) {
@ -819,10 +820,10 @@ func hasCall(n *Node) bool {
// eqfield returns the node // eqfield returns the node
// p.field == q.field // p.field == q.field
func eqfield(p *Node, q *Node, field *types.Sym) *Node { func eqfield(p *ir.Node, q *ir.Node, field *types.Sym) *ir.Node {
nx := nodSym(OXDOT, p, field) nx := nodSym(ir.OXDOT, p, field)
ny := nodSym(OXDOT, q, field) ny := nodSym(ir.OXDOT, q, field)
ne := nod(OEQ, nx, ny) ne := ir.Nod(ir.OEQ, nx, ny)
return ne return ne
} }
@ -832,23 +833,23 @@ func eqfield(p *Node, q *Node, field *types.Sym) *Node {
// memequal(s.ptr, t.ptr, len(s)) // memequal(s.ptr, t.ptr, len(s))
// which can be used to construct string equality comparison. // which can be used to construct string equality comparison.
// eqlen must be evaluated before eqmem, and shortcircuiting is required. // eqlen must be evaluated before eqmem, and shortcircuiting is required.
func eqstring(s, t *Node) (eqlen, eqmem *Node) { func eqstring(s, t *ir.Node) (eqlen, eqmem *ir.Node) {
s = conv(s, types.Types[TSTRING]) s = conv(s, types.Types[types.TSTRING])
t = conv(t, types.Types[TSTRING]) t = conv(t, types.Types[types.TSTRING])
sptr := nod(OSPTR, s, nil) sptr := ir.Nod(ir.OSPTR, s, nil)
tptr := nod(OSPTR, t, nil) tptr := ir.Nod(ir.OSPTR, t, nil)
slen := conv(nod(OLEN, s, nil), types.Types[TUINTPTR]) slen := conv(ir.Nod(ir.OLEN, s, nil), types.Types[types.TUINTPTR])
tlen := conv(nod(OLEN, t, nil), types.Types[TUINTPTR]) tlen := conv(ir.Nod(ir.OLEN, t, nil), types.Types[types.TUINTPTR])
fn := syslook("memequal") fn := syslook("memequal")
fn = substArgTypes(fn, types.Types[TUINT8], types.Types[TUINT8]) fn = substArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
call := nod(OCALL, fn, nil) call := ir.Nod(ir.OCALL, fn, nil)
call.List.Append(sptr, tptr, slen.copy()) call.List.Append(sptr, tptr, ir.Copy(slen))
call = typecheck(call, ctxExpr|ctxMultiOK) call = typecheck(call, ctxExpr|ctxMultiOK)
cmp := nod(OEQ, slen, tlen) cmp := ir.Nod(ir.OEQ, slen, tlen)
cmp = typecheck(cmp, ctxExpr) cmp = typecheck(cmp, ctxExpr)
cmp.Type = types.Types[TBOOL] cmp.Type = types.Types[types.TBOOL]
return cmp, call return cmp, call
} }
@ -858,48 +859,48 @@ func eqstring(s, t *Node) (eqlen, eqmem *Node) {
// ifaceeq(s.tab, s.data, t.data) (or efaceeq(s.typ, s.data, t.data), as appropriate) // 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. // which can be used to construct interface equality comparison.
// eqtab must be evaluated before eqdata, and shortcircuiting is required. // 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) { if !types.Identical(s.Type, t.Type) {
base.Fatalf("eqinterface %v %v", s.Type, t.Type) base.Fatalf("eqinterface %v %v", s.Type, t.Type)
} }
// func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool) // func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
// func efaceeq(typ *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() { if s.Type.IsEmptyInterface() {
fn = syslook("efaceeq") fn = syslook("efaceeq")
} else { } else {
fn = syslook("ifaceeq") fn = syslook("ifaceeq")
} }
stab := nod(OITAB, s, nil) stab := ir.Nod(ir.OITAB, s, nil)
ttab := nod(OITAB, t, nil) ttab := ir.Nod(ir.OITAB, t, nil)
sdata := nod(OIDATA, s, nil) sdata := ir.Nod(ir.OIDATA, s, nil)
tdata := nod(OIDATA, t, nil) tdata := ir.Nod(ir.OIDATA, t, nil)
sdata.Type = types.Types[TUNSAFEPTR] sdata.Type = types.Types[types.TUNSAFEPTR]
tdata.Type = types.Types[TUNSAFEPTR] tdata.Type = types.Types[types.TUNSAFEPTR]
sdata.SetTypecheck(1) sdata.SetTypecheck(1)
tdata.SetTypecheck(1) tdata.SetTypecheck(1)
call := nod(OCALL, fn, nil) call := ir.Nod(ir.OCALL, fn, nil)
call.List.Append(stab, sdata, tdata) call.List.Append(stab, sdata, tdata)
call = typecheck(call, ctxExpr|ctxMultiOK) call = typecheck(call, ctxExpr|ctxMultiOK)
cmp := nod(OEQ, stab, ttab) cmp := ir.Nod(ir.OEQ, stab, ttab)
cmp = typecheck(cmp, ctxExpr) cmp = typecheck(cmp, ctxExpr)
cmp.Type = types.Types[TBOOL] cmp.Type = types.Types[types.TBOOL]
return cmp, call return cmp, call
} }
// eqmem returns the node // eqmem returns the node
// memequal(&p.field, &q.field [, size]) // memequal(&p.field, &q.field [, size])
func eqmem(p *Node, q *Node, field *types.Sym, size int64) *Node { func eqmem(p *ir.Node, q *ir.Node, field *types.Sym, size int64) *ir.Node {
nx := nod(OADDR, nodSym(OXDOT, p, field), nil) nx := ir.Nod(ir.OADDR, nodSym(ir.OXDOT, p, field), nil)
ny := nod(OADDR, nodSym(OXDOT, q, field), nil) ny := ir.Nod(ir.OADDR, nodSym(ir.OXDOT, q, field), nil)
nx = typecheck(nx, ctxExpr) nx = typecheck(nx, ctxExpr)
ny = typecheck(ny, ctxExpr) ny = typecheck(ny, ctxExpr)
fn, needsize := eqmemfunc(size, nx.Type.Elem()) 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(nx)
call.List.Append(ny) call.List.Append(ny)
if needsize { if needsize {
@ -909,7 +910,7 @@ func eqmem(p *Node, q *Node, field *types.Sym, size int64) *Node {
return call 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 { switch size {
default: default:
fn = syslook("memequal") fn = syslook("memequal")

View file

@ -7,6 +7,7 @@ package gc
import ( import (
"bytes" "bytes"
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"fmt" "fmt"
"sort" "sort"
@ -117,7 +118,7 @@ func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 {
o = Rnd(o, int64(f.Type.Align)) o = Rnd(o, int64(f.Type.Align))
} }
f.Offset = o 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. // addrescapes has similar code to update these offsets.
// Usually addrescapes runs after widstruct, // Usually addrescapes runs after widstruct,
// in which case we could drop this, // in which case we could drop this,
@ -197,7 +198,7 @@ func findTypeLoop(t *types.Type, path *[]*types.Type) bool {
} }
*path = append(*path, t) *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 return true
} }
*path = (*path)[:len(*path)-1] *path = (*path)[:len(*path)-1]
@ -205,17 +206,17 @@ func findTypeLoop(t *types.Type, path *[]*types.Type) bool {
// Anonymous type. Recurse on contained types. // Anonymous type. Recurse on contained types.
switch t.Etype { switch t.Etype {
case TARRAY: case types.TARRAY:
if findTypeLoop(t.Elem(), path) { if findTypeLoop(t.Elem(), path) {
return true return true
} }
case TSTRUCT: case types.TSTRUCT:
for _, f := range t.Fields().Slice() { for _, f := range t.Fields().Slice() {
if findTypeLoop(f.Type, path) { if findTypeLoop(f.Type, path) {
return true return true
} }
} }
case TINTER: case types.TINTER:
for _, m := range t.Methods().Slice() { for _, m := range t.Methods().Slice() {
if m.Type.IsInterface() { // embedded interface if m.Type.IsInterface() { // embedded interface
if findTypeLoop(m.Type, path) { if findTypeLoop(m.Type, path) {
@ -306,8 +307,8 @@ func dowidth(t *types.Type) {
defercheckwidth() defercheckwidth()
lno := base.Pos lno := base.Pos
if asNode(t.Nod) != nil { if ir.AsNode(t.Nod) != nil {
base.Pos = asNode(t.Nod).Pos base.Pos = ir.AsNode(t.Nod).Pos
} }
t.Width = -2 t.Width = -2
@ -315,7 +316,7 @@ func dowidth(t *types.Type) {
et := t.Etype et := t.Etype
switch et { switch et {
case TFUNC, TCHAN, TMAP, TSTRING: case types.TFUNC, types.TCHAN, types.TMAP, types.TSTRING:
break break
// simtype == 0 during bootstrap // simtype == 0 during bootstrap
@ -331,41 +332,41 @@ func dowidth(t *types.Type) {
base.Fatalf("dowidth: unknown type: %v", t) base.Fatalf("dowidth: unknown type: %v", t)
// compiler-specific stuff // compiler-specific stuff
case TINT8, TUINT8, TBOOL: case types.TINT8, types.TUINT8, types.TBOOL:
// bool is int8 // bool is int8
w = 1 w = 1
case TINT16, TUINT16: case types.TINT16, types.TUINT16:
w = 2 w = 2
case TINT32, TUINT32, TFLOAT32: case types.TINT32, types.TUINT32, types.TFLOAT32:
w = 4 w = 4
case TINT64, TUINT64, TFLOAT64: case types.TINT64, types.TUINT64, types.TFLOAT64:
w = 8 w = 8
t.Align = uint8(Widthreg) t.Align = uint8(Widthreg)
case TCOMPLEX64: case types.TCOMPLEX64:
w = 8 w = 8
t.Align = 4 t.Align = 4
case TCOMPLEX128: case types.TCOMPLEX128:
w = 16 w = 16
t.Align = uint8(Widthreg) t.Align = uint8(Widthreg)
case TPTR: case types.TPTR:
w = int64(Widthptr) w = int64(Widthptr)
checkwidth(t.Elem()) checkwidth(t.Elem())
case TUNSAFEPTR: case types.TUNSAFEPTR:
w = int64(Widthptr) w = int64(Widthptr)
case TINTER: // implemented as 2 pointers case types.TINTER: // implemented as 2 pointers
w = 2 * int64(Widthptr) w = 2 * int64(Widthptr)
t.Align = uint8(Widthptr) t.Align = uint8(Widthptr)
expandiface(t) expandiface(t)
case TCHAN: // implemented as pointer case types.TCHAN: // implemented as pointer
w = int64(Widthptr) w = int64(Widthptr)
checkwidth(t.Elem()) checkwidth(t.Elem())
@ -375,7 +376,7 @@ func dowidth(t *types.Type) {
t1 := types.NewChanArgs(t) t1 := types.NewChanArgs(t)
checkwidth(t1) checkwidth(t1)
case TCHANARGS: case types.TCHANARGS:
t1 := t.ChanArgs() t1 := t.ChanArgs()
dowidth(t1) // just in case dowidth(t1) // just in case
if t1.Elem().Width >= 1<<16 { if t1.Elem().Width >= 1<<16 {
@ -383,27 +384,27 @@ func dowidth(t *types.Type) {
} }
w = 1 // anything will do w = 1 // anything will do
case TMAP: // implemented as pointer case types.TMAP: // implemented as pointer
w = int64(Widthptr) w = int64(Widthptr)
checkwidth(t.Elem()) checkwidth(t.Elem())
checkwidth(t.Key()) checkwidth(t.Key())
case TFORW: // should have been filled in case types.TFORW: // should have been filled in
reportTypeLoop(t) reportTypeLoop(t)
w = 1 // anything will do w = 1 // anything will do
case TANY: case types.TANY:
// not a real type; should be replaced before use. // not a real type; should be replaced before use.
base.Fatalf("dowidth any") base.Fatalf("dowidth any")
case TSTRING: case types.TSTRING:
if sizeofString == 0 { if sizeofString == 0 {
base.Fatalf("early dowidth string") base.Fatalf("early dowidth string")
} }
w = sizeofString w = sizeofString
t.Align = uint8(Widthptr) t.Align = uint8(Widthptr)
case TARRAY: case types.TARRAY:
if t.Elem() == nil { if t.Elem() == nil {
break break
} }
@ -418,7 +419,7 @@ func dowidth(t *types.Type) {
w = t.NumElem() * t.Elem().Width w = t.NumElem() * t.Elem().Width
t.Align = t.Elem().Align t.Align = t.Elem().Align
case TSLICE: case types.TSLICE:
if t.Elem() == nil { if t.Elem() == nil {
break break
} }
@ -426,7 +427,7 @@ func dowidth(t *types.Type) {
checkwidth(t.Elem()) checkwidth(t.Elem())
t.Align = uint8(Widthptr) t.Align = uint8(Widthptr)
case TSTRUCT: case types.TSTRUCT:
if t.IsFuncArgStruct() { if t.IsFuncArgStruct() {
base.Fatalf("dowidth fn struct %v", t) base.Fatalf("dowidth fn struct %v", t)
} }
@ -434,14 +435,14 @@ func dowidth(t *types.Type) {
// make fake type to check later to // make fake type to check later to
// trigger function argument computation. // trigger function argument computation.
case TFUNC: case types.TFUNC:
t1 := types.NewFuncArgs(t) t1 := types.NewFuncArgs(t)
checkwidth(t1) checkwidth(t1)
w = int64(Widthptr) // width of func type is pointer w = int64(Widthptr) // width of func type is pointer
// function is 3 cated structures; // function is 3 cated structures;
// compute their widths as side-effect. // compute their widths as side-effect.
case TFUNCARGS: case types.TFUNCARGS:
t1 := t.FuncArgs() t1 := t.FuncArgs()
w = widstruct(t1, t1.Recvs(), 0, 0) w = widstruct(t1, t1.Recvs(), 0, 0)
w = widstruct(t1, t1.Params(), w, Widthreg) w = widstruct(t1, t1.Params(), w, Widthreg)

View file

@ -5,6 +5,7 @@
package gc package gc
import ( import (
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
) )
@ -13,8 +14,8 @@ type exporter struct {
} }
// markObject visits a reachable object. // markObject visits a reachable object.
func (p *exporter) markObject(n *Node) { func (p *exporter) markObject(n *ir.Node) {
if n.Op == ONAME && n.Class() == PFUNC { if n.Op == ir.ONAME && n.Class() == ir.PFUNC {
inlFlood(n) inlFlood(n)
} }
@ -34,10 +35,10 @@ func (p *exporter) markType(t *types.Type) {
// only their unexpanded method set (i.e., exclusive of // only their unexpanded method set (i.e., exclusive of
// interface embeddings), and the switch statement below // interface embeddings), and the switch statement below
// handles their full method set. // 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() { for _, m := range t.Methods().Slice() {
if types.IsExported(m.Sym.Name) { if types.IsExported(m.Sym.Name) {
p.markObject(asNode(m.Nname)) p.markObject(ir.AsNode(m.Nname))
} }
} }
} }
@ -52,31 +53,31 @@ func (p *exporter) markType(t *types.Type) {
// the user already needs some way to construct values of // the user already needs some way to construct values of
// those types. // those types.
switch t.Etype { switch t.Etype {
case TPTR, TARRAY, TSLICE: case types.TPTR, types.TARRAY, types.TSLICE:
p.markType(t.Elem()) p.markType(t.Elem())
case TCHAN: case types.TCHAN:
if t.ChanDir().CanRecv() { if t.ChanDir().CanRecv() {
p.markType(t.Elem()) p.markType(t.Elem())
} }
case TMAP: case types.TMAP:
p.markType(t.Key()) p.markType(t.Key())
p.markType(t.Elem()) p.markType(t.Elem())
case TSTRUCT: case types.TSTRUCT:
for _, f := range t.FieldSlice() { for _, f := range t.FieldSlice() {
if types.IsExported(f.Sym.Name) || f.Embedded != 0 { if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
p.markType(f.Type) p.markType(f.Type)
} }
} }
case TFUNC: case types.TFUNC:
for _, f := range t.Results().FieldSlice() { for _, f := range t.Results().FieldSlice() {
p.markType(f.Type) p.markType(f.Type)
} }
case TINTER: case types.TINTER:
for _, f := range t.FieldSlice() { for _, f := range t.FieldSlice() {
if types.IsExported(f.Sym.Name) { if types.IsExported(f.Sym.Name) {
p.markType(f.Type) p.markType(f.Type)
@ -133,23 +134,23 @@ func predeclared() []*types.Type {
// elements have been initialized before // elements have been initialized before
predecl = []*types.Type{ predecl = []*types.Type{
// basic types // basic types
types.Types[TBOOL], types.Types[types.TBOOL],
types.Types[TINT], types.Types[types.TINT],
types.Types[TINT8], types.Types[types.TINT8],
types.Types[TINT16], types.Types[types.TINT16],
types.Types[TINT32], types.Types[types.TINT32],
types.Types[TINT64], types.Types[types.TINT64],
types.Types[TUINT], types.Types[types.TUINT],
types.Types[TUINT8], types.Types[types.TUINT8],
types.Types[TUINT16], types.Types[types.TUINT16],
types.Types[TUINT32], types.Types[types.TUINT32],
types.Types[TUINT64], types.Types[types.TUINT64],
types.Types[TUINTPTR], types.Types[types.TUINTPTR],
types.Types[TFLOAT32], types.Types[types.TFLOAT32],
types.Types[TFLOAT64], types.Types[types.TFLOAT64],
types.Types[TCOMPLEX64], types.Types[types.TCOMPLEX64],
types.Types[TCOMPLEX128], types.Types[types.TCOMPLEX128],
types.Types[TSTRING], types.Types[types.TSTRING],
// basic type aliases // basic type aliases
types.Bytetype, types.Bytetype,
@ -165,16 +166,16 @@ func predeclared() []*types.Type {
types.UntypedFloat, types.UntypedFloat,
types.UntypedComplex, types.UntypedComplex,
types.UntypedString, types.UntypedString,
types.Types[TNIL], types.Types[types.TNIL],
// package unsafe // package unsafe
types.Types[TUNSAFEPTR], types.Types[types.TUNSAFEPTR],
// invalid type (package contains errors) // invalid type (package contains errors)
types.Types[Txxx], types.Types[types.Txxx],
// any type, for builtin export data // any type, for builtin export data
types.Types[TANY], types.Types[types.TANY],
} }
} }
return predecl return predecl

View file

@ -5,20 +5,15 @@
package gc package gc
import ( import (
"cmd/compile/internal/ir"
"cmd/internal/src" "cmd/internal/src"
) )
// numImport tracks how often a package with a given name is imported. func npos(pos src.XPos, n *ir.Node) *ir.Node {
// 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 {
n.Pos = pos n.Pos = pos
return n return n
} }
func builtinCall(op Op) *Node { func builtinCall(op ir.Op) *ir.Node {
return nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil) return ir.Nod(ir.OCALL, mkname(ir.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
} }

View file

@ -2,7 +2,10 @@
package gc package gc
import "cmd/compile/internal/types" import (
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
)
var runtimeDecls = [...]struct { var runtimeDecls = [...]struct {
name string name string
@ -205,134 +208,134 @@ func runtimeTypes() []*types.Type {
var typs [131]*types.Type var typs [131]*types.Type
typs[0] = types.Bytetype typs[0] = types.Bytetype
typs[1] = types.NewPtr(typs[0]) typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[TANY] typs[2] = types.Types[types.TANY]
typs[3] = types.NewPtr(typs[2]) typs[3] = types.NewPtr(typs[2])
typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])}) typs[4] = functype(nil, []*ir.Node{anonfield(typs[1])}, []*ir.Node{anonfield(typs[3])})
typs[5] = types.Types[TUINTPTR] typs[5] = types.Types[types.TUINTPTR]
typs[6] = types.Types[TBOOL] typs[6] = types.Types[types.TBOOL]
typs[7] = types.Types[TUNSAFEPTR] typs[7] = types.Types[types.TUNSAFEPTR]
typs[8] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*Node{anonfield(typs[7])}) 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[9] = functype(nil, nil, nil)
typs[10] = types.Types[TINTER] typs[10] = types.Types[types.TINTER]
typs[11] = functype(nil, []*Node{anonfield(typs[10])}, nil) typs[11] = functype(nil, []*ir.Node{anonfield(typs[10])}, nil)
typs[12] = types.Types[TINT32] typs[12] = types.Types[types.TINT32]
typs[13] = types.NewPtr(typs[12]) typs[13] = types.NewPtr(typs[12])
typs[14] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[10])}) typs[14] = functype(nil, []*ir.Node{anonfield(typs[13])}, []*ir.Node{anonfield(typs[10])})
typs[15] = types.Types[TINT] typs[15] = types.Types[types.TINT]
typs[16] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, nil) typs[16] = functype(nil, []*ir.Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
typs[17] = types.Types[TUINT] typs[17] = types.Types[types.TUINT]
typs[18] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[15])}, nil) typs[18] = functype(nil, []*ir.Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
typs[19] = functype(nil, []*Node{anonfield(typs[6])}, nil) typs[19] = functype(nil, []*ir.Node{anonfield(typs[6])}, nil)
typs[20] = types.Types[TFLOAT64] typs[20] = types.Types[types.TFLOAT64]
typs[21] = functype(nil, []*Node{anonfield(typs[20])}, nil) typs[21] = functype(nil, []*ir.Node{anonfield(typs[20])}, nil)
typs[22] = types.Types[TINT64] typs[22] = types.Types[types.TINT64]
typs[23] = functype(nil, []*Node{anonfield(typs[22])}, nil) typs[23] = functype(nil, []*ir.Node{anonfield(typs[22])}, nil)
typs[24] = types.Types[TUINT64] typs[24] = types.Types[types.TUINT64]
typs[25] = functype(nil, []*Node{anonfield(typs[24])}, nil) typs[25] = functype(nil, []*ir.Node{anonfield(typs[24])}, nil)
typs[26] = types.Types[TCOMPLEX128] typs[26] = types.Types[types.TCOMPLEX128]
typs[27] = functype(nil, []*Node{anonfield(typs[26])}, nil) typs[27] = functype(nil, []*ir.Node{anonfield(typs[26])}, nil)
typs[28] = types.Types[TSTRING] typs[28] = types.Types[types.TSTRING]
typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil) typs[29] = functype(nil, []*ir.Node{anonfield(typs[28])}, nil)
typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil) typs[30] = functype(nil, []*ir.Node{anonfield(typs[2])}, nil)
typs[31] = functype(nil, []*Node{anonfield(typs[5])}, nil) typs[31] = functype(nil, []*ir.Node{anonfield(typs[5])}, nil)
typs[32] = types.NewArray(typs[0], 32) typs[32] = types.NewArray(typs[0], 32)
typs[33] = types.NewPtr(typs[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[34] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28])}, []*ir.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[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, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*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, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*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[38] = types.NewSlice(typs[28])
typs[39] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[38])}, []*Node{anonfield(typs[28])}) typs[39] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[38])}, []*ir.Node{anonfield(typs[28])})
typs[40] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])}) 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[41] = types.NewArray(typs[0], 4)
typs[42] = types.NewPtr(typs[41]) typs[42] = types.NewPtr(typs[41])
typs[43] = functype(nil, []*Node{anonfield(typs[42]), anonfield(typs[22])}, []*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, []*Node{anonfield(typs[33]), anonfield(typs[1]), anonfield(typs[15])}, []*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, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*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[46] = types.Runetype
typs[47] = types.NewSlice(typs[46]) 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[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[51] = types.NewArray(typs[46], 32)
typs[52] = types.NewPtr(typs[51]) typs[52] = types.NewPtr(typs[51])
typs[53] = functype(nil, []*Node{anonfield(typs[52]), anonfield(typs[28])}, []*Node{anonfield(typs[47])}) typs[53] = functype(nil, []*ir.Node{anonfield(typs[52]), anonfield(typs[28])}, []*ir.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[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, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[46]), 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, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])}) typs[56] = functype(nil, []*ir.Node{anonfield(typs[28])}, []*ir.Node{anonfield(typs[15])})
typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])}) typs[57] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[2])}, []*ir.Node{anonfield(typs[2])})
typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])}) typs[58] = functype(nil, []*ir.Node{anonfield(typs[2])}, []*ir.Node{anonfield(typs[7])})
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])}) typs[59] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[2])})
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])}) typs[60] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[2])}, []*ir.Node{anonfield(typs[2]), anonfield(typs[6])})
typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil) typs[61] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil) typs[62] = functype(nil, []*ir.Node{anonfield(typs[1])}, nil)
typs[63] = types.NewPtr(typs[5]) 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[64] = functype(nil, []*ir.Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*ir.Node{anonfield(typs[6])})
typs[65] = types.Types[TUINT32] typs[65] = types.Types[types.TUINT32]
typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])}) typs[66] = functype(nil, nil, []*ir.Node{anonfield(typs[65])})
typs[67] = types.NewMap(typs[2], typs[2]) 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[68] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[67])})
typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*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, []*Node{anonfield(typs[67])}) typs[70] = functype(nil, nil, []*ir.Node{anonfield(typs[67])})
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])}) typs[71] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[3])})
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*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, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*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, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])}) 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, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*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, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*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, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil) typs[77] = functype(nil, []*ir.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[78] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil) typs[79] = functype(nil, []*ir.Node{anonfield(typs[3])}, nil)
typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil) typs[80] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
typs[81] = types.NewChan(typs[2], types.Cboth) typs[81] = types.NewChan(typs[2], types.Cboth)
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*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, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*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[84] = types.NewChan(typs[2], types.Crecv)
typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil) typs[85] = functype(nil, []*ir.Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])}) 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[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[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[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, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil) typs[91] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil) typs[92] = functype(nil, []*ir.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[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, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])}) typs[94] = functype(nil, []*ir.Node{anonfield(typs[87]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[6])})
typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*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[96] = types.NewPtr(typs[6])
typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])}) typs[97] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*ir.Node{anonfield(typs[6])})
typs[98] = functype(nil, []*Node{anonfield(typs[63])}, nil) typs[98] = functype(nil, []*ir.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[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, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])}) typs[100] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[7])})
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*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, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*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[103] = types.NewSlice(typs[2])
typs[104] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[103]), anonfield(typs[15])}, []*Node{anonfield(typs[103])}) typs[104] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[103]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[103])})
typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil) typs[105] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
typs[106] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil) typs[106] = functype(nil, []*ir.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[107] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*ir.Node{anonfield(typs[6])})
typs[108] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*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, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*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, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])}) typs[110] = functype(nil, []*ir.Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*ir.Node{anonfield(typs[5])})
typs[111] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*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, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])}) typs[112] = functype(nil, []*ir.Node{anonfield(typs[22]), anonfield(typs[22])}, []*ir.Node{anonfield(typs[22])})
typs[113] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])}) typs[113] = functype(nil, []*ir.Node{anonfield(typs[24]), anonfield(typs[24])}, []*ir.Node{anonfield(typs[24])})
typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])}) typs[114] = functype(nil, []*ir.Node{anonfield(typs[20])}, []*ir.Node{anonfield(typs[22])})
typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])}) typs[115] = functype(nil, []*ir.Node{anonfield(typs[20])}, []*ir.Node{anonfield(typs[24])})
typs[116] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])}) typs[116] = functype(nil, []*ir.Node{anonfield(typs[20])}, []*ir.Node{anonfield(typs[65])})
typs[117] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])}) typs[117] = functype(nil, []*ir.Node{anonfield(typs[22])}, []*ir.Node{anonfield(typs[20])})
typs[118] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])}) typs[118] = functype(nil, []*ir.Node{anonfield(typs[24])}, []*ir.Node{anonfield(typs[20])})
typs[119] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])}) typs[119] = functype(nil, []*ir.Node{anonfield(typs[65])}, []*ir.Node{anonfield(typs[20])})
typs[120] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])}) typs[120] = functype(nil, []*ir.Node{anonfield(typs[26]), anonfield(typs[26])}, []*ir.Node{anonfield(typs[26])})
typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil) typs[121] = functype(nil, []*ir.Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), 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[123] = types.NewSlice(typs[7])
typs[124] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[123])}, nil) typs[124] = functype(nil, []*ir.Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
typs[125] = types.Types[TUINT8] typs[125] = types.Types[types.TUINT8]
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil) typs[126] = functype(nil, []*ir.Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
typs[127] = types.Types[TUINT16] typs[127] = types.Types[types.TUINT16]
typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil) typs[128] = functype(nil, []*ir.Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil) typs[129] = functype(nil, []*ir.Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil) typs[130] = functype(nil, []*ir.Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
return typs[:] return typs[:]
} }

View file

@ -6,24 +6,25 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax" "cmd/compile/internal/syntax"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src" "cmd/internal/src"
"fmt" "fmt"
) )
func (p *noder) funcLit(expr *syntax.FuncLit) *Node { func (p *noder) funcLit(expr *syntax.FuncLit) *ir.Node {
xtype := p.typeExpr(expr.Type) xtype := p.typeExpr(expr.Type)
ntype := 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 := dcl.Func
fn.SetIsHiddenClosure(Curfn != nil) 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.Param.Ntype = xtype
fn.Nname.Name.Defn = dcl fn.Nname.Name.Defn = dcl
clo := p.nod(expr, OCLOSURE, nil, nil) clo := p.nod(expr, ir.OCLOSURE, nil, nil)
clo.Func = fn clo.Func = fn
fn.ClosureType = ntype fn.ClosureType = ntype
fn.OClosure = clo fn.OClosure = clo
@ -77,7 +78,7 @@ func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
// function associated with the closure. // function associated with the closure.
// TODO: This creation of the named function should probably really be done in a // TODO: This creation of the named function should probably really be done in a
// separate pass from type-checking. // separate pass from type-checking.
func typecheckclosure(clo *Node, top int) { func typecheckclosure(clo *ir.Node, top int) {
fn := clo.Func fn := clo.Func
dcl := fn.Decl dcl := fn.Decl
// Set current associated iota value, so iota can be used inside // Set current associated iota value, so iota can be used inside
@ -139,7 +140,7 @@ var globClosgen int
// closurename generates a new unique name for a closure within // closurename generates a new unique name for a closure within
// outerfunc. // outerfunc.
func closurename(outerfunc *Node) *types.Sym { func closurename(outerfunc *ir.Node) *types.Sym {
outer := "glob." outer := "glob."
prefix := "func" prefix := "func"
gen := &globClosgen gen := &globClosgen
@ -149,12 +150,12 @@ func closurename(outerfunc *Node) *types.Sym {
prefix = "" prefix = ""
} }
outer = outerfunc.funcname() outer = ir.FuncName(outerfunc)
// There may be multiple functions named "_". In those // There may be multiple functions named "_". In those
// cases, we can't use their individual Closgens as it // cases, we can't use their individual Closgens as it
// would lead to name clashes. // would lead to name clashes.
if !outerfunc.Func.Nname.isBlank() { if !ir.IsBlank(outerfunc.Func.Nname) {
gen = &outerfunc.Func.Closgen gen = &outerfunc.Func.Closgen
} }
} }
@ -171,7 +172,7 @@ var capturevarscomplete bool
// by value or by reference. // by value or by reference.
// We use value capturing for values <= 128 bytes that are never reassigned // We use value capturing for values <= 128 bytes that are never reassigned
// after capturing (effectively constant). // after capturing (effectively constant).
func capturevars(dcl *Node) { func capturevars(dcl *ir.Node) {
lno := base.Pos lno := base.Pos
base.Pos = dcl.Pos base.Pos = dcl.Pos
fn := dcl.Func fn := dcl.Func
@ -197,11 +198,11 @@ func capturevars(dcl *Node) {
outermost := v.Name.Defn outermost := v.Name.Defn
// out parameters will be assigned to implicitly upon return. // 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) v.Name.SetByval(true)
} else { } else {
outermost.Name.SetAddrtaken(true) outermost.Name.SetAddrtaken(true)
outer = nod(OADDR, outer, nil) outer = ir.Nod(ir.OADDR, outer, nil)
} }
if base.Flag.LowerM > 1 { if base.Flag.LowerM > 1 {
@ -226,7 +227,7 @@ func capturevars(dcl *Node) {
// transformclosure is called in a separate phase after escape analysis. // transformclosure is called in a separate phase after escape analysis.
// It transform closure bodies to properly reference captured variables. // It transform closure bodies to properly reference captured variables.
func transformclosure(dcl *Node) { func transformclosure(dcl *ir.Node) {
lno := base.Pos lno := base.Pos
base.Pos = dcl.Pos base.Pos = dcl.Pos
fn := dcl.Func fn := dcl.Func
@ -252,24 +253,24 @@ func transformclosure(dcl *Node) {
// We are going to insert captured variables before input args. // We are going to insert captured variables before input args.
var params []*types.Field var params []*types.Field
var decls []*Node var decls []*ir.Node
for _, v := range fn.ClosureVars.Slice() { for _, v := range fn.ClosureVars.Slice() {
if !v.Name.Byval() { if !v.Name.Byval() {
// If v of type T is captured by reference, // If v of type T is captured by reference,
// we introduce function param &v *T // we introduce function param &v *T
// and v remains PAUTOHEAP with &v heapaddr // and v remains PAUTOHEAP with &v heapaddr
// (accesses will implicitly deref &v). // (accesses will implicitly deref &v).
addr := newname(lookup("&" + v.Sym.Name)) addr := NewName(lookup("&" + v.Sym.Name))
addr.Type = types.NewPtr(v.Type) addr.Type = types.NewPtr(v.Type)
v.Name.Param.Heapaddr = addr v.Name.Param.Heapaddr = addr
v = addr v = addr
} }
v.SetClass(PPARAM) v.SetClass(ir.PPARAM)
decls = append(decls, v) decls = append(decls, v)
fld := types.NewField(src.NoXPos, v.Sym, v.Type) fld := types.NewField(src.NoXPos, v.Sym, v.Type)
fld.Nname = asTypesNode(v) fld.Nname = ir.AsTypesNode(v)
params = append(params, fld) params = append(params, fld)
} }
@ -283,11 +284,11 @@ func transformclosure(dcl *Node) {
dcl.Type = f.Type // update type of ODCLFUNC dcl.Type = f.Type // update type of ODCLFUNC
} else { } else {
// The closure is not called, so it is going to stay as closure. // The closure is not called, so it is going to stay as closure.
var body []*Node var body []*ir.Node
offset := int64(Widthptr) offset := int64(Widthptr)
for _, v := range fn.ClosureVars.Slice() { for _, v := range fn.ClosureVars.Slice() {
// cv refers to the field inside of closure OSTRUCTLIT. // 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 cv.Type = v.Type
if !v.Name.Byval() { if !v.Name.Byval() {
@ -299,23 +300,23 @@ func transformclosure(dcl *Node) {
if v.Name.Byval() && v.Type.Width <= int64(2*Widthptr) { if v.Name.Byval() && v.Type.Width <= int64(2*Widthptr) {
// If it is a small variable captured by value, downgrade it to PAUTO. // 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) fn.Dcl = append(fn.Dcl, v)
body = append(body, nod(OAS, v, cv)) body = append(body, ir.Nod(ir.OAS, v, cv))
} else { } else {
// Declare variable holding addresses taken from closure // Declare variable holding addresses taken from closure
// and initialize in entry prologue. // and initialize in entry prologue.
addr := newname(lookup("&" + v.Sym.Name)) addr := NewName(lookup("&" + v.Sym.Name))
addr.Type = types.NewPtr(v.Type) addr.Type = types.NewPtr(v.Type)
addr.SetClass(PAUTO) addr.SetClass(ir.PAUTO)
addr.Name.SetUsed(true) addr.Name.SetUsed(true)
addr.Name.Curfn = dcl addr.Name.Curfn = dcl
fn.Dcl = append(fn.Dcl, addr) fn.Dcl = append(fn.Dcl, addr)
v.Name.Param.Heapaddr = addr v.Name.Param.Heapaddr = addr
if v.Name.Byval() { 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))
} }
} }
@ -331,13 +332,13 @@ func transformclosure(dcl *Node) {
// hasemptycvars reports whether closure clo has an // hasemptycvars reports whether closure clo has an
// empty list of captured vars. // empty list of captured vars.
func hasemptycvars(clo *Node) bool { func hasemptycvars(clo *ir.Node) bool {
return clo.Func.ClosureVars.Len() == 0 return clo.Func.ClosureVars.Len() == 0
} }
// closuredebugruntimecheck applies boilerplate checks for debug flags // closuredebugruntimecheck applies boilerplate checks for debug flags
// and compiling runtime // and compiling runtime
func closuredebugruntimecheck(clo *Node) { func closuredebugruntimecheck(clo *ir.Node) {
if base.Debug.Closure > 0 { if base.Debug.Closure > 0 {
if clo.Esc == EscHeap { if clo.Esc == EscHeap {
base.WarnfAt(clo.Pos, "heap closure, captured vars = %v", clo.Func.ClosureVars) base.WarnfAt(clo.Pos, "heap closure, captured vars = %v", clo.Func.ClosureVars)
@ -353,7 +354,7 @@ func closuredebugruntimecheck(clo *Node) {
// closureType returns the struct type used to hold all the information // closureType returns the struct type used to hold all the information
// needed in the closure for clo (clo must be a OCLOSURE node). // 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. // 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. // Create closure in the form of a composite literal.
// supposing the closure captures an int i and a string s // supposing the closure captures an int i and a string s
// and has one float64 argument and no results, // and has one float64 argument and no results,
@ -367,8 +368,8 @@ func closureType(clo *Node) *types.Type {
// The information appears in the binary in the form of type descriptors; // The information appears in the binary in the form of type descriptors;
// the struct is unnamed so that closures in multiple packages with the // the struct is unnamed so that closures in multiple packages with the
// same struct type can share the descriptor. // same struct type can share the descriptor.
fields := []*Node{ fields := []*ir.Node{
namedfield(".F", types.Types[TUINTPTR]), namedfield(".F", types.Types[types.TUINTPTR]),
} }
for _, v := range clo.Func.ClosureVars.Slice() { for _, v := range clo.Func.ClosureVars.Slice() {
typ := v.Type typ := v.Type
@ -382,7 +383,7 @@ func closureType(clo *Node) *types.Type {
return typ return typ
} }
func walkclosure(clo *Node, init *Nodes) *Node { func walkclosure(clo *ir.Node, init *ir.Nodes) *ir.Node {
fn := clo.Func fn := clo.Func
// If no closure vars, don't bother wrapping. // If no closure vars, don't bother wrapping.
@ -396,11 +397,11 @@ func walkclosure(clo *Node, init *Nodes) *Node {
typ := closureType(clo) typ := closureType(clo)
clos := nod(OCOMPLIT, nil, typenod(typ)) clos := ir.Nod(ir.OCOMPLIT, nil, typenod(typ))
clos.Esc = clo.Esc 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 clos.Esc = clo.Esc
// Force type conversion from *struct to the func type. // Force type conversion from *struct to the func type.
@ -418,9 +419,9 @@ func walkclosure(clo *Node, init *Nodes) *Node {
return walkexpr(clos, init) return walkexpr(clos, init)
} }
func typecheckpartialcall(dot *Node, sym *types.Sym) { func typecheckpartialcall(dot *ir.Node, sym *types.Sym) {
switch dot.Op { switch dot.Op {
case ODOTINTER, ODOTMETH: case ir.ODOTINTER, ir.ODOTMETH:
break break
default: default:
@ -430,8 +431,8 @@ func typecheckpartialcall(dot *Node, sym *types.Sym) {
// Create top-level function. // Create top-level function.
dcl := makepartialcall(dot, dot.Type, sym) dcl := makepartialcall(dot, dot.Type, sym)
dcl.Func.SetWrapper(true) dcl.Func.SetWrapper(true)
dot.Op = OCALLPART dot.Op = ir.OCALLPART
dot.Right = newname(sym) dot.Right = NewName(sym)
dot.Type = dcl.Type dot.Type = dcl.Type
dot.Func = dcl.Func dot.Func = dcl.Func
dot.SetOpt(nil) // clear types.Field from ODOTMETH dot.SetOpt(nil) // clear types.Field from ODOTMETH
@ -439,12 +440,12 @@ func typecheckpartialcall(dot *Node, sym *types.Sym) {
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed // makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
// for partial calls. // 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 rcvrtype := dot.Left.Type
sym := methodSymSuffix(rcvrtype, meth, "-fm") sym := methodSymSuffix(rcvrtype, meth, "-fm")
if sym.Uniq() { if sym.Uniq() {
return asNode(sym.Def) return ir.AsNode(sym.Def)
} }
sym.SetUniq(true) sym.SetUniq(true)
@ -463,7 +464,7 @@ func makepartialcall(dot *Node, t0 *types.Type, meth *types.Sym) *Node {
// number at the use of the method expression in this // number at the use of the method expression in this
// case. See issue 29389. // case. See issue 29389.
tfn := nod(OTFUNC, nil, nil) tfn := ir.Nod(ir.OTFUNC, nil, nil)
tfn.List.Set(structargs(t0.Params(), true)) tfn.List.Set(structargs(t0.Params(), true))
tfn.Rlist.Set(structargs(t0.Results(), false)) tfn.Rlist.Set(structargs(t0.Results(), false))
@ -476,27 +477,27 @@ func makepartialcall(dot *Node, t0 *types.Type, meth *types.Sym) *Node {
// Declare and initialize variable holding receiver. // Declare and initialize variable holding receiver.
cv := nod(OCLOSUREVAR, nil, nil) cv := ir.Nod(ir.OCLOSUREVAR, nil, nil)
cv.Type = rcvrtype cv.Type = rcvrtype
cv.Xoffset = Rnd(int64(Widthptr), int64(cv.Type.Align)) cv.Xoffset = Rnd(int64(Widthptr), int64(cv.Type.Align))
ptr := newname(lookup(".this")) ptr := NewName(lookup(".this"))
declare(ptr, PAUTO) declare(ptr, ir.PAUTO)
ptr.Name.SetUsed(true) ptr.Name.SetUsed(true)
var body []*Node var body []*ir.Node
if rcvrtype.IsPtr() || rcvrtype.IsInterface() { if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
ptr.Type = rcvrtype ptr.Type = rcvrtype
body = append(body, nod(OAS, ptr, cv)) body = append(body, ir.Nod(ir.OAS, ptr, cv))
} else { } else {
ptr.Type = types.NewPtr(rcvrtype) 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.List.Set(paramNnames(tfn.Type))
call.SetIsDDD(tfn.Type.IsVariadic()) call.SetIsDDD(tfn.Type.IsVariadic())
if t0.NumResults() != 0 { if t0.NumResults() != 0 {
n := nod(ORETURN, nil, nil) n := ir.Nod(ir.ORETURN, nil, nil)
n.List.Set1(call) n.List.Set1(call)
call = n call = n
} }
@ -510,7 +511,7 @@ func makepartialcall(dot *Node, t0 *types.Type, meth *types.Sym) *Node {
// typecheckslice() requires that Curfn is set when processing an ORETURN. // typecheckslice() requires that Curfn is set when processing an ORETURN.
Curfn = dcl Curfn = dcl
typecheckslice(dcl.Nbody.Slice(), ctxStmt) typecheckslice(dcl.Nbody.Slice(), ctxStmt)
sym.Def = asTypesNode(dcl) sym.Def = ir.AsTypesNode(dcl)
xtop = append(xtop, dcl) xtop = append(xtop, dcl)
Curfn = savecurfn Curfn = savecurfn
base.Pos = saveLineNo base.Pos = saveLineNo
@ -521,16 +522,16 @@ func makepartialcall(dot *Node, t0 *types.Type, meth *types.Sym) *Node {
// partialCallType returns the struct type used to hold all the information // partialCallType returns the struct type used to hold all the information
// needed in the closure for n (n must be a OCALLPART node). // 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. // The address of a variable of the returned type can be cast to a func.
func partialCallType(n *Node) *types.Type { func partialCallType(n *ir.Node) *types.Type {
t := tostruct([]*Node{ t := tostruct([]*ir.Node{
namedfield("F", types.Types[TUINTPTR]), namedfield("F", types.Types[types.TUINTPTR]),
namedfield("R", n.Left.Type), namedfield("R", n.Left.Type),
}) })
t.SetNoalg(true) t.SetNoalg(true)
return t 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. // Create closure in the form of a composite literal.
// For x.M with receiver (x) type T, the generated code looks like: // For x.M with receiver (x) type T, the generated code looks like:
// //
@ -544,21 +545,21 @@ func walkpartialcall(n *Node, init *Nodes) *Node {
n.Left = cheapexpr(n.Left, init) n.Left = cheapexpr(n.Left, init)
n.Left = walkexpr(n.Left, nil) n.Left = walkexpr(n.Left, nil)
tab := nod(OITAB, n.Left, nil) tab := ir.Nod(ir.OITAB, n.Left, nil)
tab = typecheck(tab, ctxExpr) tab = typecheck(tab, ctxExpr)
c := nod(OCHECKNIL, tab, nil) c := ir.Nod(ir.OCHECKNIL, tab, nil)
c.SetTypecheck(1) c.SetTypecheck(1)
init.Append(c) init.Append(c)
} }
typ := partialCallType(n) typ := partialCallType(n)
clos := nod(OCOMPLIT, nil, typenod(typ)) clos := ir.Nod(ir.OCOMPLIT, nil, typenod(typ))
clos.Esc = n.Esc 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 clos.Esc = n.Esc
// Force type conversion from *struct to the func type. // Force type conversion from *struct to the func type.
@ -578,8 +579,8 @@ func walkpartialcall(n *Node, init *Nodes) *Node {
// callpartMethod returns the *types.Field representing the method // callpartMethod returns the *types.Field representing the method
// referenced by method value n. // referenced by method value n.
func callpartMethod(n *Node) *types.Field { func callpartMethod(n *ir.Node) *types.Field {
if n.Op != OCALLPART { if n.Op != ir.OCALLPART {
base.Fatalf("expected OCALLPART, got %v", n) base.Fatalf("expected OCALLPART, got %v", n)
} }

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src" "cmd/internal/src"
"fmt" "fmt"
@ -23,51 +24,6 @@ const (
Mpprec = 512 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 { func bigFloatVal(v constant.Value) *big.Float {
f := new(big.Float) f := new(big.Float)
f.SetPrec(Mpprec) f.SetPrec(Mpprec)
@ -86,62 +42,6 @@ func bigFloatVal(v constant.Value) *big.Float {
return f 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 { func roundFloat(v constant.Value, sz int64) constant.Value {
switch sz { switch sz {
case 4: case 4:
@ -184,8 +84,8 @@ func trunccmplxlit(v constant.Value, t *types.Type) constant.Value {
} }
// TODO(mdempsky): Replace these with better APIs. // TODO(mdempsky): Replace these with better APIs.
func convlit(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 *Node, t *types.Type) *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 // convlit1 converts an untyped expression n to type t. If n already
// has a type, convlit1 has no effect. // has a type, convlit1 has no effect.
@ -198,7 +98,7 @@ func defaultlit(n *Node, t *types.Type) *Node { return convlit1(n, t, false, nil
// //
// If there's an error converting n to t, context is used in the error // If there's an error converting n to t, context is used in the error
// message. // 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 { if explicit && t == nil {
base.Fatalf("explicit conversion missing type") base.Fatalf("explicit conversion missing type")
} }
@ -215,15 +115,15 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
return n 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. // Can't always set n.Type directly on OLITERAL nodes.
// See discussion on CL 20813. // See discussion on CL 20813.
n = n.rawcopy() n = n.RawCopy()
} }
// Nil is technically not a constant, so handle it specially. // Nil is technically not a constant, so handle it specially.
if n.Type.Etype == TNIL { if n.Type.Etype == types.TNIL {
if n.Op != ONIL { if n.Op != ir.ONIL {
base.Fatalf("unexpected op: %v (%v)", n, n.Op) base.Fatalf("unexpected op: %v (%v)", n, n.Op)
} }
if t == nil { if t == nil {
@ -242,7 +142,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
return n return n
} }
if t == nil || !okforconst[t.Etype] { if t == nil || !ir.OKForConst[t.Etype] {
t = defaultType(n.Type) t = defaultType(n.Type)
} }
@ -250,7 +150,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
default: default:
base.Fatalf("unexpected untyped expression: %v", n) base.Fatalf("unexpected untyped expression: %v", n)
case OLITERAL: case ir.OLITERAL:
v := convertVal(n.Val(), t, explicit) v := convertVal(n.Val(), t, explicit)
if v.Kind() == constant.Unknown { if v.Kind() == constant.Unknown {
break break
@ -259,7 +159,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
n.SetVal(v) n.SetVal(v)
return n 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) ot := operandType(n.Op, t)
if ot == nil { if ot == nil {
n = defaultlit(n, nil) n = defaultlit(n, nil)
@ -274,7 +174,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
n.Type = t n.Type = t
return n 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) ot := operandType(n.Op, t)
if ot == nil { if ot == nil {
n = defaultlit(n, nil) n = defaultlit(n, nil)
@ -296,14 +196,14 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
n.Type = t n.Type = t
return n 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() { if !t.IsBoolean() {
break break
} }
n.Type = t n.Type = t
return n return n
case OLSH, ORSH: case ir.OLSH, ir.ORSH:
n.Left = convlit1(n.Left, t, explicit, nil) n.Left = convlit1(n.Left, t, explicit, nil)
n.Type = n.Left.Type n.Type = n.Left.Type
if n.Type != nil && !n.Type.IsInteger() { if n.Type != nil && !n.Type.IsInteger() {
@ -329,13 +229,13 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
return n return n
} }
func operandType(op Op, t *types.Type) *types.Type { func operandType(op ir.Op, t *types.Type) *types.Type {
switch op { switch op {
case OCOMPLEX: case ir.OCOMPLEX:
if t.IsComplex() { if t.IsComplex() {
return floatForComplex(t) return floatForComplex(t)
} }
case OREAL, OIMAG: case ir.OREAL, ir.OIMAG:
if t.IsFloat() { if t.IsFloat() {
return complexForFloat(t) return complexForFloat(t)
} }
@ -488,7 +388,7 @@ func overflow(v constant.Value, t *types.Type) bool {
return true return true
} }
if doesoverflow(v, t) { 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 true
} }
return false return false
@ -505,57 +405,46 @@ func tostr(v constant.Value) constant.Value {
return v 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{ var tokenForOp = [...]token.Token{
OPLUS: token.ADD, ir.OPLUS: token.ADD,
ONEG: token.SUB, ir.ONEG: token.SUB,
ONOT: token.NOT, ir.ONOT: token.NOT,
OBITNOT: token.XOR, ir.OBITNOT: token.XOR,
OADD: token.ADD, ir.OADD: token.ADD,
OSUB: token.SUB, ir.OSUB: token.SUB,
OMUL: token.MUL, ir.OMUL: token.MUL,
ODIV: token.QUO, ir.ODIV: token.QUO,
OMOD: token.REM, ir.OMOD: token.REM,
OOR: token.OR, ir.OOR: token.OR,
OXOR: token.XOR, ir.OXOR: token.XOR,
OAND: token.AND, ir.OAND: token.AND,
OANDNOT: token.AND_NOT, ir.OANDNOT: token.AND_NOT,
OOROR: token.LOR, ir.OOROR: token.LOR,
OANDAND: token.LAND, ir.OANDAND: token.LAND,
OEQ: token.EQL, ir.OEQ: token.EQL,
ONE: token.NEQ, ir.ONE: token.NEQ,
OLT: token.LSS, ir.OLT: token.LSS,
OLE: token.LEQ, ir.OLE: token.LEQ,
OGT: token.GTR, ir.OGT: token.GTR,
OGE: token.GEQ, ir.OGE: token.GEQ,
OLSH: token.SHL, ir.OLSH: token.SHL,
ORSH: token.SHR, ir.ORSH: token.SHR,
} }
// evalConst returns a constant-evaluated expression equivalent to n. // evalConst returns a constant-evaluated expression equivalent to n.
// If n is not a constant, evalConst returns n. // If n is not a constant, evalConst returns n.
// Otherwise, evalConst returns a new OLITERAL with the same value as n, // Otherwise, evalConst returns a new OLITERAL with the same value as n,
// and with .Orig pointing back to 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 nl, nr := n.Left, n.Right
// Pick off just the opcodes that can be constant evaluated. // Pick off just the opcodes that can be constant evaluated.
switch op := n.Op; op { switch op := n.Op; op {
case OPLUS, ONEG, OBITNOT, ONOT: case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
if nl.Op == OLITERAL { if nl.Op == ir.OLITERAL {
var prec uint var prec uint
if n.Type.IsUnsigned() { if n.Type.IsUnsigned() {
prec = uint(n.Type.Size() * 8) prec = uint(n.Type.Size() * 8)
@ -563,36 +452,36 @@ func evalConst(n *Node) *Node {
return origConst(n, constant.UnaryOp(tokenForOp[op], nl.Val(), prec)) return origConst(n, constant.UnaryOp(tokenForOp[op], nl.Val(), prec))
} }
case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND: 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 == OLITERAL && nr.Op == OLITERAL { if nl.Op == ir.OLITERAL && nr.Op == ir.OLITERAL {
rval := nr.Val() rval := nr.Val()
// check for divisor underflow in complex division (see issue 20227) // 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") base.Errorf("complex division by zero")
n.Type = nil n.Type = nil
return n 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") base.Errorf("division by zero")
n.Type = nil n.Type = nil
return n return n
} }
tok := tokenForOp[op] tok := tokenForOp[op]
if op == ODIV && n.Type.IsInteger() { if op == ir.ODIV && n.Type.IsInteger() {
tok = token.QUO_ASSIGN // integer division tok = token.QUO_ASSIGN // integer division
} }
return origConst(n, constant.BinaryOp(nl.Val(), tok, rval)) return origConst(n, constant.BinaryOp(nl.Val(), tok, rval))
} }
case OEQ, ONE, OLT, OLE, OGT, OGE: case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
if nl.Op == OLITERAL && nr.Op == OLITERAL { if nl.Op == ir.OLITERAL && nr.Op == ir.OLITERAL {
return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[op], nr.Val())) return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[op], nr.Val()))
} }
case OLSH, ORSH: case ir.OLSH, ir.ORSH:
if nl.Op == OLITERAL && nr.Op == OLITERAL { if nl.Op == ir.OLITERAL && nr.Op == ir.OLITERAL {
// shiftBound from go/types; "so we can express smallestFloat64" // shiftBound from go/types; "so we can express smallestFloat64"
const shiftBound = 1023 - 1 + 52 const shiftBound = 1023 - 1 + 52
s, ok := constant.Uint64Val(nr.Val()) s, ok := constant.Uint64Val(nr.Val())
@ -604,24 +493,24 @@ func evalConst(n *Node) *Node {
return origConst(n, constant.Shift(toint(nl.Val()), tokenForOp[op], uint(s))) return origConst(n, constant.Shift(toint(nl.Val()), tokenForOp[op], uint(s)))
} }
case OCONV, ORUNESTR: case ir.OCONV, ir.ORUNESTR:
if okforconst[n.Type.Etype] && nl.Op == OLITERAL { if ir.OKForConst[n.Type.Etype] && nl.Op == ir.OLITERAL {
return origConst(n, convertVal(nl.Val(), n.Type, true)) return origConst(n, convertVal(nl.Val(), n.Type, true))
} }
case OCONVNOP: case ir.OCONVNOP:
if okforconst[n.Type.Etype] && nl.Op == OLITERAL { if ir.OKForConst[n.Type.Etype] && nl.Op == ir.OLITERAL {
// set so n.Orig gets OCONV instead of OCONVNOP // set so n.Orig gets OCONV instead of OCONVNOP
n.Op = OCONV n.Op = ir.OCONV
return origConst(n, nl.Val()) return origConst(n, nl.Val())
} }
case OADDSTR: case ir.OADDSTR:
// Merge adjacent constants in the argument list. // Merge adjacent constants in the argument list.
s := n.List.Slice() s := n.List.Slice()
need := 0 need := 0
for i := 0; i < len(s); i++ { 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. // Can't merge s[i] into s[i-1]; need a slot in the list.
need++ need++
} }
@ -636,13 +525,13 @@ func evalConst(n *Node) *Node {
} }
return origConst(n, constant.MakeString(strings.Join(strs, ""))) 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++ { 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 // merge from i up to but not including i2
var strs []string var strs []string
i2 := i 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()) strs = append(strs, s[i2].StringVal())
i2++ i2++
} }
@ -656,37 +545,37 @@ func evalConst(n *Node) *Node {
} }
} }
n = n.copy() n = ir.Copy(n)
n.List.Set(newList) n.List.Set(newList)
return n return n
case OCAP, OLEN: case ir.OCAP, ir.OLEN:
switch nl.Type.Etype { switch nl.Type.Etype {
case TSTRING: case types.TSTRING:
if Isconst(nl, constant.String) { if ir.IsConst(nl, constant.String) {
return origIntConst(n, int64(len(nl.StringVal()))) return origIntConst(n, int64(len(nl.StringVal())))
} }
case TARRAY: case types.TARRAY:
if !hascallchan(nl) { if !hascallchan(nl) {
return origIntConst(n, nl.Type.NumElem()) return origIntConst(n, nl.Type.NumElem())
} }
} }
case OALIGNOF, OOFFSETOF, OSIZEOF: case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
return origIntConst(n, evalunsafe(n)) return origIntConst(n, evalunsafe(n))
case OREAL: case ir.OREAL:
if nl.Op == OLITERAL { if nl.Op == ir.OLITERAL {
return origConst(n, constant.Real(nl.Val())) return origConst(n, constant.Real(nl.Val()))
} }
case OIMAG: case ir.OIMAG:
if nl.Op == OLITERAL { if nl.Op == ir.OLITERAL {
return origConst(n, constant.Imag(nl.Val())) return origConst(n, constant.Imag(nl.Val()))
} }
case OCOMPLEX: case ir.OCOMPLEX:
if nl.Op == OLITERAL && nr.Op == OLITERAL { if nl.Op == ir.OLITERAL && nr.Op == ir.OLITERAL {
return origConst(n, makeComplex(nl.Val(), nr.Val())) return origConst(n, makeComplex(nl.Val(), nr.Val()))
} }
} }
@ -721,16 +610,16 @@ func square(x constant.Value) constant.Value {
// For matching historical "constant OP overflow" error messages. // For matching historical "constant OP overflow" error messages.
// TODO(mdempsky): Replace with error messages like go/types uses. // TODO(mdempsky): Replace with error messages like go/types uses.
var overflowNames = [...]string{ var overflowNames = [...]string{
OADD: "addition", ir.OADD: "addition",
OSUB: "subtraction", ir.OSUB: "subtraction",
OMUL: "multiplication", ir.OMUL: "multiplication",
OLSH: "shift", ir.OLSH: "shift",
OXOR: "bitwise XOR", ir.OXOR: "bitwise XOR",
OBITNOT: "bitwise complement", ir.OBITNOT: "bitwise complement",
} }
// origConst returns an OLITERAL with orig n and value v. // 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) lno := setlineno(n)
v = convertVal(v, n.Type, false) v = convertVal(v, n.Type, false)
base.Pos = lno base.Pos = lno
@ -752,81 +641,28 @@ func origConst(n *Node, v constant.Value) *Node {
} }
orig := n orig := n
n = nodl(orig.Pos, OLITERAL, nil, nil) n = ir.NodAt(orig.Pos, ir.OLITERAL, nil, nil)
n.Orig = orig n.Orig = orig
n.Type = orig.Type n.Type = orig.Type
n.SetVal(v) n.SetVal(v)
return n return n
} }
func assertRepresents(t *types.Type, v constant.Value) { func origBoolConst(n *ir.Node, v bool) *ir.Node {
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 {
return origConst(n, constant.MakeBool(v)) 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)) 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; // defaultlit on both nodes simultaneously;
// if they're both ideal going in they better // if they're both ideal going in they better
// get the same type going out. // get the same type going out.
// force means must assign concrete (non-ideal) type. // force means must assign concrete (non-ideal) type.
// The results of defaultlit2 MUST be assigned back to l and r, e.g. // The results of defaultlit2 MUST be assigned back to l and r, e.g.
// n.Left, n.Right = defaultlit2(n.Left, n.Right, force) // 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 { if l.Type == nil || r.Type == nil {
return l, r return l, r
} }
@ -851,7 +687,7 @@ func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
if l.Type.IsString() != r.Type.IsString() { if l.Type.IsString() != r.Type.IsString() {
return l, r return l, r
} }
if l.isNil() || r.isNil() { if ir.IsNil(l) || ir.IsNil(r) {
return l, r return l, r
} }
@ -888,31 +724,31 @@ func mixUntyped(t1, t2 *types.Type) *types.Type {
} }
func defaultType(t *types.Type) *types.Type { func defaultType(t *types.Type) *types.Type {
if !t.IsUntyped() || t.Etype == TNIL { if !t.IsUntyped() || t.Etype == types.TNIL {
return t return t
} }
switch t { switch t {
case types.UntypedBool: case types.UntypedBool:
return types.Types[TBOOL] return types.Types[types.TBOOL]
case types.UntypedString: case types.UntypedString:
return types.Types[TSTRING] return types.Types[types.TSTRING]
case types.UntypedInt: case types.UntypedInt:
return types.Types[TINT] return types.Types[types.TINT]
case types.UntypedRune: case types.UntypedRune:
return types.Runetype return types.Runetype
case types.UntypedFloat: case types.UntypedFloat:
return types.Types[TFLOAT64] return types.Types[types.TFLOAT64]
case types.UntypedComplex: case types.UntypedComplex:
return types.Types[TCOMPLEX128] return types.Types[types.TCOMPLEX128]
} }
base.Fatalf("bad type %v", t) base.Fatalf("bad type %v", t)
return nil return nil
} }
func smallintconst(n *Node) bool { func smallintconst(n *ir.Node) bool {
if n.Op == OLITERAL { if n.Op == ir.OLITERAL {
v, ok := constant.Int64Val(n.Val()) v, ok := constant.Int64Val(n.Val())
return ok && int64(int32(v)) == v return ok && int64(int32(v)) == v
} }
@ -924,11 +760,11 @@ func smallintconst(n *Node) bool {
// If n is not a constant expression, not representable as an // If n is not a constant expression, not representable as an
// integer, or negative, it returns -1. If n is too large, it // integer, or negative, it returns -1. If n is too large, it
// returns -2. // returns -2.
func indexconst(n *Node) int64 { func indexconst(n *ir.Node) int64 {
if n.Op != OLITERAL { if n.Op != ir.OLITERAL {
return -1 return -1
} }
if !n.Type.IsInteger() && n.Type.Etype != TIDEAL { if !n.Type.IsInteger() && n.Type.Etype != types.TIDEAL {
return -1 return -1
} }
@ -936,10 +772,10 @@ func indexconst(n *Node) int64 {
if v.Kind() != constant.Int || constant.Sign(v) < 0 { if v.Kind() != constant.Int || constant.Sign(v) < 0 {
return -1 return -1
} }
if doesoverflow(v, types.Types[TINT]) { if doesoverflow(v, types.Types[types.TINT]) {
return -2 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 // isGoConst reports whether n is a Go language constant (as opposed to a
@ -947,35 +783,35 @@ func indexconst(n *Node) int64 {
// //
// Expressions derived from nil, like string([]byte(nil)), while they // Expressions derived from nil, like string([]byte(nil)), while they
// may be known at compile time, are not Go language constants. // may be known at compile time, are not Go language constants.
func (n *Node) isGoConst() bool { func isGoConst(n *ir.Node) bool {
return n.Op == OLITERAL return n.Op == ir.OLITERAL
} }
func hascallchan(n *Node) bool { func hascallchan(n *ir.Node) bool {
if n == nil { if n == nil {
return false return false
} }
switch n.Op { switch n.Op {
case OAPPEND, case ir.OAPPEND,
OCALL, ir.OCALL,
OCALLFUNC, ir.OCALLFUNC,
OCALLINTER, ir.OCALLINTER,
OCALLMETH, ir.OCALLMETH,
OCAP, ir.OCAP,
OCLOSE, ir.OCLOSE,
OCOMPLEX, ir.OCOMPLEX,
OCOPY, ir.OCOPY,
ODELETE, ir.ODELETE,
OIMAG, ir.OIMAG,
OLEN, ir.OLEN,
OMAKE, ir.OMAKE,
ONEW, ir.ONEW,
OPANIC, ir.OPANIC,
OPRINT, ir.OPRINT,
OPRINTN, ir.OPRINTN,
OREAL, ir.OREAL,
ORECOVER, ir.ORECOVER,
ORECV: ir.ORECV:
return true return true
} }
@ -1015,12 +851,12 @@ type constSetKey struct {
// where are used in the error message. // where are used in the error message.
// //
// n must not be an untyped constant. // n must not be an untyped constant.
func (s *constSet) add(pos src.XPos, n *Node, what, where string) { func (s *constSet) add(pos src.XPos, n *ir.Node, what, where string) {
if n.Op == OCONVIFACE && n.Implicit() { if n.Op == ir.OCONVIFACE && n.Implicit() {
n = n.Left n = n.Left
} }
if !n.isGoConst() { if !isGoConst(n) {
return return
} }
if n.Type.IsUntyped() { if n.Type.IsUntyped() {
@ -1045,11 +881,11 @@ func (s *constSet) add(pos src.XPos, n *Node, what, where string) {
typ := n.Type typ := n.Type
switch typ { switch typ {
case types.Bytetype: case types.Bytetype:
typ = types.Types[TUINT8] typ = types.Types[types.TUINT8]
case types.Runetype: 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) { if hasUniquePos(n) {
pos = n.Pos pos = n.Pos
@ -1072,9 +908,9 @@ func (s *constSet) add(pos src.XPos, n *Node, what, where string) {
// the latter is non-obvious. // the latter is non-obvious.
// //
// TODO(mdempsky): This could probably be a fmt.go flag. // TODO(mdempsky): This could probably be a fmt.go flag.
func nodeAndVal(n *Node) string { func nodeAndVal(n *ir.Node) string {
show := n.String() show := n.String()
val := n.ValueInterface() val := ir.ConstValue(n)
if s := fmt.Sprintf("%#v", val); show != s { if s := fmt.Sprintf("%#v", val); show != s {
show += " (value " + s + ")" show += " (value " + s + ")"
} }

View file

@ -7,6 +7,7 @@ package gc
import ( import (
"bytes" "bytes"
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
@ -17,7 +18,7 @@ import (
// Declaration stack & operations // Declaration stack & operations
var externdcl []*Node var externdcl []*ir.Node
func testdclstack() { func testdclstack() {
if !types.IsDclstackValid() { if !types.IsDclstackValid() {
@ -58,25 +59,25 @@ var declare_typegen int
// declare records that Node n declares symbol n.Sym in the specified // declare records that Node n declares symbol n.Sym in the specified
// declaration context. // declaration context.
func declare(n *Node, ctxt Class) { func declare(n *ir.Node, ctxt ir.Class) {
if n.isBlank() { if ir.IsBlank(n) {
return return
} }
if n.Name == nil { if n.Name == nil {
// named OLITERAL needs Name; most OLITERALs don't. // named OLITERAL needs Name; most OLITERALs don't.
n.Name = new(Name) n.Name = new(ir.Name)
} }
s := n.Sym s := n.Sym
// kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later. // 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) base.ErrorfAt(n.Pos, "cannot declare name %v", s)
} }
gen := 0 gen := 0
if ctxt == PEXTERN { if ctxt == ir.PEXTERN {
if s.Name == "init" { if s.Name == "init" {
base.ErrorfAt(n.Pos, "cannot declare init - must be func") base.ErrorfAt(n.Pos, "cannot declare init - must be func")
} }
@ -85,17 +86,17 @@ func declare(n *Node, ctxt Class) {
} }
externdcl = append(externdcl, n) externdcl = append(externdcl, n)
} else { } else {
if Curfn == nil && ctxt == PAUTO { if Curfn == nil && ctxt == ir.PAUTO {
base.Pos = n.Pos base.Pos = n.Pos
base.Fatalf("automatic outside function") base.Fatalf("automatic outside function")
} }
if Curfn != nil && ctxt != PFUNC { if Curfn != nil && ctxt != ir.PFUNC {
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
} }
if n.Op == OTYPE { if n.Op == ir.OTYPE {
declare_typegen++ declare_typegen++
gen = 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++ vargen++
gen = vargen gen = vargen
} }
@ -103,58 +104,58 @@ func declare(n *Node, ctxt Class) {
n.Name.Curfn = Curfn n.Name.Curfn = Curfn
} }
if ctxt == PAUTO { if ctxt == ir.PAUTO {
n.Xoffset = 0 n.Xoffset = 0
} }
if s.Block == types.Block { if s.Block == types.Block {
// functype will print errors about duplicate function arguments. // functype will print errors about duplicate function arguments.
// Don't repeat the error here. // 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") redeclare(n.Pos, s, "in this block")
} }
} }
s.Block = types.Block s.Block = types.Block
s.Lastlineno = base.Pos s.Lastlineno = base.Pos
s.Def = asTypesNode(n) s.Def = ir.AsTypesNode(n)
n.Name.Vargen = int32(gen) n.Name.Vargen = int32(gen)
n.SetClass(ctxt) n.SetClass(ctxt)
if ctxt == PFUNC { if ctxt == ir.PFUNC {
n.Sym.SetFunc(true) n.Sym.SetFunc(true)
} }
autoexport(n, ctxt) autoexport(n, ctxt)
} }
func addvar(n *Node, t *types.Type, ctxt Class) { func addvar(n *ir.Node, t *types.Type, ctxt ir.Class) {
if n == nil || n.Sym == nil || (n.Op != ONAME && n.Op != ONONAME) || t == nil { 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) base.Fatalf("addvar: n=%v t=%v nil", n, t)
} }
n.Op = ONAME n.Op = ir.ONAME
declare(n, ctxt) declare(n, ctxt)
n.Type = t n.Type = t
} }
// declare variables from grammar // declare variables from grammar
// new_name_list (type | [type] = expr_list) // new_name_list (type | [type] = expr_list)
func variter(vl []*Node, t *Node, el []*Node) []*Node { func variter(vl []*ir.Node, t *ir.Node, el []*ir.Node) []*ir.Node {
var init []*Node var init []*ir.Node
doexpr := len(el) > 0 doexpr := len(el) > 0
if len(el) == 1 && len(vl) > 1 { if len(el) == 1 && len(vl) > 1 {
e := el[0] e := el[0]
as2 := nod(OAS2, nil, nil) as2 := ir.Nod(ir.OAS2, nil, nil)
as2.List.Set(vl) as2.List.Set(vl)
as2.Rlist.Set1(e) as2.Rlist.Set1(e)
for _, v := range vl { for _, v := range vl {
v.Op = ONAME v.Op = ir.ONAME
declare(v, dclcontext) declare(v, dclcontext)
v.Name.Param.Ntype = t v.Name.Param.Ntype = t
v.Name.Defn = as2 v.Name.Defn = as2
if Curfn != nil { if Curfn != nil {
init = append(init, nod(ODCL, v, nil)) init = append(init, ir.Nod(ir.ODCL, v, nil))
} }
} }
@ -163,7 +164,7 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
nel := len(el) nel := len(el)
for _, v := range vl { for _, v := range vl {
var e *Node var e *ir.Node
if doexpr { if doexpr {
if len(el) == 0 { if len(el) == 0 {
base.Errorf("assignment mismatch: %d variables but %d values", len(vl), nel) base.Errorf("assignment mismatch: %d variables but %d values", len(vl), nel)
@ -173,15 +174,15 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
el = el[1:] el = el[1:]
} }
v.Op = ONAME v.Op = ir.ONAME
declare(v, dclcontext) declare(v, dclcontext)
v.Name.Param.Ntype = t v.Name.Param.Ntype = t
if e != nil || Curfn != nil || v.isBlank() { if e != nil || Curfn != nil || ir.IsBlank(v) {
if Curfn != nil { 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) init = append(init, e)
if e.Right != nil { if e.Right != nil {
v.Name.Defn = e v.Name.Defn = e
@ -196,22 +197,22 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
} }
// newnoname returns a new ONONAME Node associated with symbol s. // 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 { if s == nil {
base.Fatalf("newnoname nil") base.Fatalf("newnoname nil")
} }
n := nod(ONONAME, nil, nil) n := ir.Nod(ir.ONONAME, nil, nil)
n.Sym = s n.Sym = s
n.Xoffset = 0 n.Xoffset = 0
return n return n
} }
// newfuncnamel generates a new name node for a function or method. // 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 { if fn.Nname != nil {
base.Fatalf("newfuncnamel - already have name") base.Fatalf("newfuncnamel - already have name")
} }
n := newnamel(pos, s) n := ir.NewNameAt(pos, s)
n.Func = fn n.Func = fn
fn.Nname = n fn.Nname = n
return n return n
@ -219,39 +220,39 @@ func newfuncnamel(pos src.XPos, s *types.Sym, fn *Func) *Node {
// this generates a new name node for a name // this generates a new name node for a name
// being declared. // being declared.
func dclname(s *types.Sym) *Node { func dclname(s *types.Sym) *ir.Node {
n := newname(s) n := NewName(s)
n.Op = ONONAME // caller will correct it n.Op = ir.ONONAME // caller will correct it
return n return n
} }
func typenod(t *types.Type) *Node { func typenod(t *types.Type) *ir.Node {
return typenodl(src.NoXPos, t) 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 // if we copied another type with *t = *u
// then t->nod might be out of date, so // then t->nod might be out of date, so
// check t->nod->type too // check t->nod->type too
if asNode(t.Nod) == nil || asNode(t.Nod).Type != t { if ir.AsNode(t.Nod) == nil || ir.AsNode(t.Nod).Type != t {
t.Nod = asTypesNode(nodl(pos, OTYPE, nil, nil)) t.Nod = ir.AsTypesNode(ir.NodAt(pos, ir.OTYPE, nil, nil))
asNode(t.Nod).Type = t ir.AsNode(t.Nod).Type = t
asNode(t.Nod).Sym = t.Sym 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) 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) return symfield(lookup(s), typ)
} }
func symfield(s *types.Sym, typ *types.Type) *Node { func symfield(s *types.Sym, typ *types.Type) *ir.Node {
n := nodSym(ODCLFIELD, nil, s) n := nodSym(ir.ODCLFIELD, nil, s)
n.Type = typ n.Type = typ
return n return n
} }
@ -260,8 +261,8 @@ func symfield(s *types.Sym, typ *types.Type) *Node {
// If no such Node currently exists, an ONONAME Node is returned instead. // If no such Node currently exists, an ONONAME Node is returned instead.
// Automatically creates a new closure variable if the referenced symbol was // Automatically creates a new closure variable if the referenced symbol was
// declared in a different (containing) function. // declared in a different (containing) function.
func oldname(s *types.Sym) *Node { func oldname(s *types.Sym) *ir.Node {
n := asNode(s.Def) n := ir.AsNode(s.Def)
if n == nil { if n == nil {
// Maybe a top-level declaration will come along later to // Maybe a top-level declaration will come along later to
// define s. resolve will check s.Def again once all input // define s. resolve will check s.Def again once all input
@ -269,7 +270,7 @@ func oldname(s *types.Sym) *Node {
return newnoname(s) 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. // Inner func is referring to var in outer func.
// //
// TODO(rsc): If there is an outer variable x and we // TODO(rsc): If there is an outer variable x and we
@ -279,8 +280,8 @@ func oldname(s *types.Sym) *Node {
c := n.Name.Param.Innermost c := n.Name.Param.Innermost
if c == nil || c.Name.Curfn != Curfn { if c == nil || c.Name.Curfn != Curfn {
// Do not have a closure var for the active closure yet; make one. // Do not have a closure var for the active closure yet; make one.
c = newname(s) c = NewName(s)
c.SetClass(PAUTOHEAP) c.SetClass(ir.PAUTOHEAP)
c.Name.SetIsClosureVar(true) c.Name.SetIsClosureVar(true)
c.SetIsDDD(n.IsDDD()) c.SetIsDDD(n.IsDDD())
c.Name.Defn = n c.Name.Defn = n
@ -301,9 +302,9 @@ func oldname(s *types.Sym) *Node {
} }
// importName is like oldname, but it reports an error if sym is from another package and not exported. // 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) n := oldname(sym)
if !types.IsExported(sym.Name) && sym.Pkg != localpkg { if !types.IsExported(sym.Name) && sym.Pkg != ir.LocalPkg {
n.SetDiag(true) n.SetDiag(true)
base.Errorf("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name) base.Errorf("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name)
} }
@ -311,20 +312,20 @@ func importName(sym *types.Sym) *Node {
} }
// := declarations // := declarations
func colasname(n *Node) bool { func colasname(n *ir.Node) bool {
switch n.Op { switch n.Op {
case ONAME, case ir.ONAME,
ONONAME, ir.ONONAME,
OPACK, ir.OPACK,
OTYPE, ir.OTYPE,
OLITERAL: ir.OLITERAL:
return n.Sym != nil return n.Sym != nil
} }
return false return false
} }
func colasdefn(left []*Node, defn *Node) { func colasdefn(left []*ir.Node, defn *ir.Node) {
for _, n := range left { for _, n := range left {
if n.Sym != nil { if n.Sym != nil {
n.Sym.SetUniq(true) n.Sym.SetUniq(true)
@ -333,7 +334,7 @@ func colasdefn(left []*Node, defn *Node) {
var nnew, nerr int var nnew, nerr int
for i, n := range left { for i, n := range left {
if n.isBlank() { if ir.IsBlank(n) {
continue continue
} }
if !colasname(n) { if !colasname(n) {
@ -355,10 +356,10 @@ func colasdefn(left []*Node, defn *Node) {
} }
nnew++ nnew++
n = newname(n.Sym) n = NewName(n.Sym)
declare(n, dclcontext) declare(n, dclcontext)
n.Name.Defn = defn n.Name.Defn = defn
defn.Ninit.Append(nod(ODCL, n, nil)) defn.Ninit.Append(ir.Nod(ir.ODCL, n, nil))
left[i] = n left[i] = n
} }
@ -369,8 +370,8 @@ func colasdefn(left []*Node, defn *Node) {
// declare the arguments in an // declare the arguments in an
// interface field declaration. // interface field declaration.
func ifacedcl(n *Node) { func ifacedcl(n *ir.Node) {
if n.Op != ODCLFIELD || n.Left == nil { if n.Op != ir.ODCLFIELD || n.Left == nil {
base.Fatalf("ifacedcl") base.Fatalf("ifacedcl")
} }
@ -383,11 +384,11 @@ func ifacedcl(n *Node) {
// and declare the arguments. // and declare the arguments.
// called in extern-declaration context // called in extern-declaration context
// returns in auto-declaration context. // returns in auto-declaration context.
func funchdr(n *Node) { func funchdr(n *ir.Node) {
// change the declaration context from extern to auto // change the declaration context from extern to auto
funcStack = append(funcStack, funcStackEnt{Curfn, dclcontext}) funcStack = append(funcStack, funcStackEnt{Curfn, dclcontext})
Curfn = n Curfn = n
dclcontext = PAUTO dclcontext = ir.PAUTO
types.Markdcl() types.Markdcl()
@ -398,8 +399,8 @@ func funchdr(n *Node) {
} }
} }
func funcargs(nt *Node) { func funcargs(nt *ir.Node) {
if nt.Op != OTFUNC { if nt.Op != ir.OTFUNC {
base.Fatalf("funcargs %v", nt.Op) base.Fatalf("funcargs %v", nt.Op)
} }
@ -414,10 +415,10 @@ func funcargs(nt *Node) {
// declare the receiver and in arguments. // declare the receiver and in arguments.
if nt.Left != nil { if nt.Left != nil {
funcarg(nt.Left, PPARAM) funcarg(nt.Left, ir.PPARAM)
} }
for _, n := range nt.List.Slice() { for _, n := range nt.List.Slice() {
funcarg(n, PPARAM) funcarg(n, ir.PPARAM)
} }
oldvargen := vargen oldvargen := vargen
@ -442,21 +443,21 @@ func funcargs(nt *Node) {
gen++ gen++
} }
funcarg(n, PPARAMOUT) funcarg(n, ir.PPARAMOUT)
} }
vargen = oldvargen vargen = oldvargen
} }
func funcarg(n *Node, ctxt Class) { func funcarg(n *ir.Node, ctxt ir.Class) {
if n.Op != ODCLFIELD { if n.Op != ir.ODCLFIELD {
base.Fatalf("funcarg %v", n.Op) base.Fatalf("funcarg %v", n.Op)
} }
if n.Sym == nil { if n.Sym == nil {
return 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.Name.Param.Ntype = n.Left
n.Right.SetIsDDD(n.IsDDD()) n.Right.SetIsDDD(n.IsDDD())
declare(n.Right, ctxt) declare(n.Right, ctxt)
@ -469,27 +470,27 @@ func funcarg(n *Node, ctxt Class) {
// This happens during import, where the hidden_fndcl rule has // This happens during import, where the hidden_fndcl rule has
// used functype directly to parse the function's type. // used functype directly to parse the function's type.
func funcargs2(t *types.Type) { func funcargs2(t *types.Type) {
if t.Etype != TFUNC { if t.Etype != types.TFUNC {
base.Fatalf("funcargs2 %v", t) base.Fatalf("funcargs2 %v", t)
} }
for _, f := range t.Recvs().Fields().Slice() { for _, f := range t.Recvs().Fields().Slice() {
funcarg2(f, PPARAM) funcarg2(f, ir.PPARAM)
} }
for _, f := range t.Params().Fields().Slice() { for _, f := range t.Params().Fields().Slice() {
funcarg2(f, PPARAM) funcarg2(f, ir.PPARAM)
} }
for _, f := range t.Results().Fields().Slice() { 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 { if f.Sym == nil {
return return
} }
n := newnamel(f.Pos, f.Sym) n := ir.NewNameAt(f.Pos, f.Sym)
f.Nname = asTypesNode(n) f.Nname = ir.AsTypesNode(n)
n.Type = f.Type n.Type = f.Type
n.SetIsDDD(f.IsDDD()) n.SetIsDDD(f.IsDDD())
declare(n, ctxt) declare(n, ctxt)
@ -498,8 +499,8 @@ func funcarg2(f *types.Field, ctxt Class) {
var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
type funcStackEnt struct { type funcStackEnt struct {
curfn *Node curfn *ir.Node
dclcontext Class dclcontext ir.Class
} }
// finish the body. // finish the body.
@ -529,16 +530,16 @@ func checkembeddedtype(t *types.Type) {
if t.IsPtr() || t.IsUnsafePtr() { if t.IsPtr() || t.IsUnsafePtr() {
base.Errorf("embedded type cannot be a pointer") 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 t.ForwardType().Embedlineno = base.Pos
} }
} }
func structfield(n *Node) *types.Field { func structfield(n *ir.Node) *types.Field {
lno := base.Pos lno := base.Pos
base.Pos = n.Pos base.Pos = n.Pos
if n.Op != ODCLFIELD { if n.Op != ir.ODCLFIELD {
base.Fatalf("structfield: oops %v\n", n) base.Fatalf("structfield: oops %v\n", n)
} }
@ -581,8 +582,8 @@ func checkdupfields(what string, fss ...[]*types.Field) {
// convert a parsed id/type list into // convert a parsed id/type list into
// a type for struct/interface/arglist // a type for struct/interface/arglist
func tostruct(l []*Node) *types.Type { func tostruct(l []*ir.Node) *types.Type {
t := types.New(TSTRUCT) t := types.New(types.TSTRUCT)
fields := make([]*types.Field, len(l)) fields := make([]*types.Field, len(l))
for i, n := range l { for i, n := range l {
@ -603,8 +604,8 @@ func tostruct(l []*Node) *types.Type {
return t return t
} }
func tofunargs(l []*Node, funarg types.Funarg) *types.Type { func tofunargs(l []*ir.Node, funarg types.Funarg) *types.Type {
t := types.New(TSTRUCT) t := types.New(types.TSTRUCT)
t.StructType().Funarg = funarg t.StructType().Funarg = funarg
fields := make([]*types.Field, len(l)) fields := make([]*types.Field, len(l))
@ -613,7 +614,7 @@ func tofunargs(l []*Node, funarg types.Funarg) *types.Type {
f.SetIsDDD(n.IsDDD()) f.SetIsDDD(n.IsDDD())
if n.Right != nil { if n.Right != nil {
n.Right.Type = f.Type n.Right.Type = f.Type
f.Nname = asTypesNode(n.Right) f.Nname = ir.AsTypesNode(n.Right)
} }
if f.Broke() { if f.Broke() {
t.SetBroke(true) t.SetBroke(true)
@ -625,17 +626,17 @@ func tofunargs(l []*Node, funarg types.Funarg) *types.Type {
} }
func tofunargsfield(fields []*types.Field, funarg types.Funarg) *types.Type { func tofunargsfield(fields []*types.Field, funarg types.Funarg) *types.Type {
t := types.New(TSTRUCT) t := types.New(types.TSTRUCT)
t.StructType().Funarg = funarg t.StructType().Funarg = funarg
t.SetFields(fields) t.SetFields(fields)
return t return t
} }
func interfacefield(n *Node) *types.Field { func interfacefield(n *ir.Node) *types.Field {
lno := base.Pos lno := base.Pos
base.Pos = n.Pos base.Pos = n.Pos
if n.Op != ODCLFIELD { if n.Op != ir.ODCLFIELD {
base.Fatalf("interfacefield: oops %v\n", n) base.Fatalf("interfacefield: oops %v\n", n)
} }
@ -660,11 +661,11 @@ func interfacefield(n *Node) *types.Field {
return f return f
} }
func tointerface(l []*Node) *types.Type { func tointerface(l []*ir.Node) *types.Type {
if len(l) == 0 { 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 var fields []*types.Field
for _, n := range l { for _, n := range l {
f := interfacefield(n) f := interfacefield(n)
@ -677,7 +678,7 @@ func tointerface(l []*Node) *types.Type {
return t return t
} }
func fakeRecv() *Node { func fakeRecv() *ir.Node {
return anonfield(types.FakeRecvType()) return anonfield(types.FakeRecvType())
} }
@ -693,12 +694,12 @@ func isifacemethod(f *types.Type) bool {
} }
// turn a parsed function declaration into a type // turn a parsed function declaration into a type
func functype(this *Node, in, out []*Node) *types.Type { func functype(this *ir.Node, in, out []*ir.Node) *types.Type {
t := types.New(TFUNC) t := types.New(types.TFUNC)
var rcvr []*Node var rcvr []*ir.Node
if this != nil { if this != nil {
rcvr = []*Node{this} rcvr = []*ir.Node{this}
} }
t.FuncType().Receiver = tofunargs(rcvr, types.FunargRcvr) t.FuncType().Receiver = tofunargs(rcvr, types.FunargRcvr)
t.FuncType().Params = tofunargs(in, types.FunargParams) t.FuncType().Params = tofunargs(in, types.FunargParams)
@ -710,13 +711,13 @@ func functype(this *Node, in, out []*Node) *types.Type {
t.SetBroke(true) 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 return t
} }
func functypefield(this *types.Field, in, out []*types.Field) *types.Type { func functypefield(this *types.Field, in, out []*types.Field) *types.Type {
t := types.New(TFUNC) t := types.New(types.TFUNC)
var rcvr []*types.Field var rcvr []*types.Field
if this != nil { if this != nil {
@ -726,36 +727,11 @@ func functypefield(this *types.Field, in, out []*types.Field) *types.Type {
t.FuncType().Params = tofunargsfield(in, types.FunargParams) t.FuncType().Params = tofunargsfield(in, types.FunargParams)
t.FuncType().Results = tofunargsfield(out, types.FunargResults) 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 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 // methodSym returns the method symbol representing a method name
// associated with a specific receiver type. // associated with a specific receiver type.
// //
@ -823,7 +799,7 @@ func methodSymSuffix(recv *types.Type, msym *types.Sym, suffix string) *types.Sy
// - msym is the method symbol // - msym is the method symbol
// - t is function type (with receiver) // - t is function type (with receiver)
// Returns a pointer to the existing or added Field; or nil if there's an error. // 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 { if msym == nil {
base.Fatalf("no method symbol") base.Fatalf("no method symbol")
} }
@ -864,7 +840,7 @@ func addmethod(n *Node, msym *types.Sym, t *types.Type, local, nointerface bool)
return nil 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) base.Errorf("cannot define new methods on non-local type %v", mt)
return nil return nil
} }
@ -896,7 +872,7 @@ func addmethod(n *Node, msym *types.Sym, t *types.Type, local, nointerface bool)
} }
f := types.NewField(base.Pos, msym, t) f := types.NewField(base.Pos, msym, t)
f.Nname = asTypesNode(n.Func.Nname) f.Nname = ir.AsTypesNode(n.Func.Nname)
f.SetNointerface(nointerface) f.SetNointerface(nointerface)
mt.Methods().Append(f) mt.Methods().Append(f)
@ -959,21 +935,21 @@ func makefuncsym(s *types.Sym) {
} }
// setNodeNameFunc marks a node as a function. // setNodeNameFunc marks a node as a function.
func setNodeNameFunc(n *Node) { func setNodeNameFunc(n *ir.Node) {
if n.Op != ONAME || n.Class() != Pxxx { if n.Op != ir.ONAME || n.Class() != ir.Pxxx {
base.Fatalf("expected ONAME/Pxxx node, got %v", n) base.Fatalf("expected ONAME/Pxxx node, got %v", n)
} }
n.SetClass(PFUNC) n.SetClass(ir.PFUNC)
n.Sym.SetFunc(true) n.Sym.SetFunc(true)
} }
func dclfunc(sym *types.Sym, tfn *Node) *Node { func dclfunc(sym *types.Sym, tfn *ir.Node) *ir.Node {
if tfn.Op != OTFUNC { if tfn.Op != ir.OTFUNC {
base.Fatalf("expected OTFUNC node, got %v", tfn) 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 = newfuncnamel(base.Pos, sym, fn.Func)
fn.Func.Nname.Name.Defn = fn fn.Func.Nname.Name.Defn = fn
fn.Func.Nname.Name.Param.Ntype = tfn fn.Func.Nname.Name.Param.Ntype = tfn
@ -987,27 +963,22 @@ type nowritebarrierrecChecker struct {
// extraCalls contains extra function calls that may not be // extraCalls contains extra function calls that may not be
// visible during later analysis. It maps from the ODCLFUNC of // visible during later analysis. It maps from the ODCLFUNC of
// the caller to a list of callees. // 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 is the current function during AST walks.
curfn *Node curfn *ir.Node
} }
type nowritebarrierrecCall struct { type nowritebarrierrecCall struct {
target *Node // ODCLFUNC of caller or callee target *ir.Node // ODCLFUNC of caller or callee
lineno src.XPos // line of call 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 // newNowritebarrierrecChecker creates a nowritebarrierrecChecker. It
// must be called before transformclosure and walk. // must be called before transformclosure and walk.
func newNowritebarrierrecChecker() *nowritebarrierrecChecker { func newNowritebarrierrecChecker() *nowritebarrierrecChecker {
c := &nowritebarrierrecChecker{ c := &nowritebarrierrecChecker{
extraCalls: make(map[*Node][]nowritebarrierrecCall), extraCalls: make(map[*ir.Node][]nowritebarrierrecCall),
} }
// Find all systemstack calls and record their targets. In // Find all systemstack calls and record their targets. In
@ -1016,39 +987,39 @@ func newNowritebarrierrecChecker() *nowritebarrierrecChecker {
// directly. This has to happen before transformclosure since // directly. This has to happen before transformclosure since
// it's a lot harder to work out the argument after. // it's a lot harder to work out the argument after.
for _, n := range xtop { for _, n := range xtop {
if n.Op != ODCLFUNC { if n.Op != ir.ODCLFUNC {
continue continue
} }
c.curfn = n c.curfn = n
inspect(n, c.findExtraCalls) ir.Inspect(n, c.findExtraCalls)
} }
c.curfn = nil c.curfn = nil
return c return c
} }
func (c *nowritebarrierrecChecker) findExtraCalls(n *Node) bool { func (c *nowritebarrierrecChecker) findExtraCalls(n *ir.Node) bool {
if n.Op != OCALLFUNC { if n.Op != ir.OCALLFUNC {
return true return true
} }
fn := n.Left 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 return true
} }
if !isRuntimePkg(fn.Sym.Pkg) || fn.Sym.Name != "systemstack" { if !isRuntimePkg(fn.Sym.Pkg) || fn.Sym.Name != "systemstack" {
return true return true
} }
var callee *Node var callee *ir.Node
arg := n.List.First() arg := n.List.First()
switch arg.Op { switch arg.Op {
case ONAME: case ir.ONAME:
callee = arg.Name.Defn callee = arg.Name.Defn
case OCLOSURE: case ir.OCLOSURE:
callee = arg.Func.Decl callee = arg.Func.Decl
default: default:
base.Fatalf("expected ONAME or OCLOSURE node, got %+v", arg) 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) base.Fatalf("expected ODCLFUNC node, got %+v", callee)
} }
c.extraCalls[c.curfn] = append(c.extraCalls[c.curfn], nowritebarrierrecCall{callee, n.Pos}) c.extraCalls[c.curfn] = append(c.extraCalls[c.curfn], nowritebarrierrecCall{callee, n.Pos})
@ -1063,17 +1034,17 @@ func (c *nowritebarrierrecChecker) findExtraCalls(n *Node) bool {
// because that's all we know after we start SSA. // because that's all we know after we start SSA.
// //
// This can be called concurrently for different from Nodes. // This can be called concurrently for different from Nodes.
func (c *nowritebarrierrecChecker) recordCall(from *Node, to *obj.LSym, pos src.XPos) { func (c *nowritebarrierrecChecker) recordCall(from *ir.Node, to *obj.LSym, pos src.XPos) {
if from.Op != ODCLFUNC { if from.Op != ir.ODCLFUNC {
base.Fatalf("expected ODCLFUNC, got %v", from) base.Fatalf("expected ODCLFUNC, got %v", from)
} }
// We record this information on the *Func so this is // We record this information on the *Func so this is
// concurrent-safe. // concurrent-safe.
fn := from.Func fn := from.Func
if fn.nwbrCalls == nil { if fn.NWBRCalls == nil {
fn.nwbrCalls = new([]nowritebarrierrecCallSym) 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() { func (c *nowritebarrierrecChecker) check() {
@ -1081,39 +1052,39 @@ func (c *nowritebarrierrecChecker) check() {
// capture all calls created by lowering, but this means we // capture all calls created by lowering, but this means we
// only get to see the obj.LSyms of calls. symToFunc lets us // only get to see the obj.LSyms of calls. symToFunc lets us
// get back to the ODCLFUNCs. // 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 // funcs records the back-edges of the BFS call graph walk. It
// maps from the ODCLFUNC of each function that must not have // maps from the ODCLFUNC of each function that must not have
// write barriers to the call that inhibits them. Functions // write barriers to the call that inhibits them. Functions
// that are directly marked go:nowritebarrierrec are in this // that are directly marked go:nowritebarrierrec are in this
// map with a zero-valued nowritebarrierrecCall. This also // map with a zero-valued nowritebarrierrecCall. This also
// acts as the set of marks for the BFS of the call graph. // 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. // q is the queue of ODCLFUNC Nodes to visit in BFS order.
var q nodeQueue var q ir.NodeQueue
for _, n := range xtop { for _, n := range xtop {
if n.Op != ODCLFUNC { if n.Op != ir.ODCLFUNC {
continue continue
} }
symToFunc[n.Func.lsym] = n symToFunc[n.Func.LSym] = n
// Make nowritebarrierrec functions BFS roots. // Make nowritebarrierrec functions BFS roots.
if n.Func.Pragma&Nowritebarrierrec != 0 { if n.Func.Pragma&ir.Nowritebarrierrec != 0 {
funcs[n] = nowritebarrierrecCall{} funcs[n] = nowritebarrierrecCall{}
q.pushRight(n) q.PushRight(n)
} }
// Check go:nowritebarrier functions. // 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") base.ErrorfAt(n.Func.WBPos, "write barrier prohibited")
} }
} }
// Perform a BFS of the call graph from all // Perform a BFS of the call graph from all
// go:nowritebarrierrec functions. // go:nowritebarrierrec functions.
enqueue := func(src, target *Node, pos src.XPos) { enqueue := func(src, target *ir.Node, pos src.XPos) {
if target.Func.Pragma&Yeswritebarrierrec != 0 { if target.Func.Pragma&ir.Yeswritebarrierrec != 0 {
// Don't flow into this function. // Don't flow into this function.
return return
} }
@ -1124,10 +1095,10 @@ func (c *nowritebarrierrecChecker) check() {
// Record the path. // Record the path.
funcs[target] = nowritebarrierrecCall{target: src, lineno: pos} funcs[target] = nowritebarrierrecCall{target: src, lineno: pos}
q.pushRight(target) q.PushRight(target)
} }
for !q.empty() { for !q.Empty() {
fn := q.popLeft() fn := q.PopLeft()
// Check fn. // Check fn.
if fn.Func.WBPos.IsKnown() { if fn.Func.WBPos.IsKnown() {
@ -1145,13 +1116,13 @@ func (c *nowritebarrierrecChecker) check() {
for _, callee := range c.extraCalls[fn] { for _, callee := range c.extraCalls[fn] {
enqueue(fn, callee.target, callee.lineno) enqueue(fn, callee.target, callee.lineno)
} }
if fn.Func.nwbrCalls == nil { if fn.Func.NWBRCalls == nil {
continue continue
} }
for _, callee := range *fn.Func.nwbrCalls { for _, callee := range *fn.Func.NWBRCalls {
target := symToFunc[callee.target] target := symToFunc[callee.Sym]
if target != nil { if target != nil {
enqueue(fn, target, callee.lineno) enqueue(fn, target, callee.Pos)
} }
} }
} }

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax" "cmd/compile/internal/syntax"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
@ -16,7 +17,7 @@ import (
"strings" "strings"
) )
var embedlist []*Node var embedlist []*ir.Node
const ( const (
embedUnknown = iota embedUnknown = iota
@ -27,7 +28,7 @@ const (
var numLocalEmbed int 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 haveEmbed := false
for _, decl := range p.file.DeclList { for _, decl := range p.file.DeclList {
imp, ok := decl.(*syntax.ImportDecl) imp, ok := decl.(*syntax.ImportDecl)
@ -110,14 +111,14 @@ func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []Pragma
} }
v := names[0] v := names[0]
if dclcontext != PEXTERN { if dclcontext != ir.PEXTERN {
numLocalEmbed++ numLocalEmbed++
v = newnamel(v.Pos, lookupN("embed.", numLocalEmbed)) v = ir.NewNameAt(v.Pos, lookupN("embed.", numLocalEmbed))
v.Sym.Def = asTypesNode(v) v.Sym.Def = ir.AsTypesNode(v)
v.Name.Param.Ntype = typ v.Name.Param.Ntype = typ
v.SetClass(PEXTERN) v.SetClass(ir.PEXTERN)
externdcl = append(externdcl, v) externdcl = append(externdcl, v)
exprs = []*Node{v} exprs = []*ir.Node{v}
} }
v.Name.Param.SetEmbedFiles(list) v.Name.Param.SetEmbedFiles(list)
@ -129,18 +130,18 @@ func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []Pragma
// The match is approximate because we haven't done scope resolution yet and // 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". // can't tell whether "string" and "byte" really mean "string" and "byte".
// The result must be confirmed later, after type checking, using embedKind. // The result must be confirmed later, after type checking, using embedKind.
func embedKindApprox(typ *Node) int { func embedKindApprox(typ *ir.Node) 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 return embedFiles
} }
// These are not guaranteed to match only string and []byte - // These are not guaranteed to match only string and []byte -
// maybe the local package has redefined one of those words. // maybe the local package has redefined one of those words.
// But it's the best we can do now during the noder. // But it's the best we can do now during the noder.
// The stricter check happens later, in initEmbed calling embedKind. // 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 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 embedBytes
} }
return embedUnknown return embedUnknown
@ -148,10 +149,10 @@ func embedKindApprox(typ *Node) int {
// embedKind determines the kind of embedding variable. // embedKind determines the kind of embedding variable.
func embedKind(typ *types.Type) int { 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 return embedFiles
} }
if typ == types.Types[TSTRING] { if typ == types.Types[types.TSTRING] {
return embedString return embedString
} }
if typ.Sym == nil && typ.IsSlice() && typ.Elem() == types.Bytetype { if typ.Sym == nil && typ.IsSlice() && typ.Elem() == types.Bytetype {
@ -191,7 +192,7 @@ func dumpembeds() {
// initEmbed emits the init data for a //go:embed variable, // initEmbed emits the init data for a //go:embed variable,
// which is either a string, a []byte, or an embed.FS. // 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() files := v.Name.Param.EmbedFiles()
switch kind := embedKind(v.Type); kind { switch kind := embedKind(v.Type); kind {
case embedUnknown: case embedUnknown:

View file

@ -1,474 +0,0 @@
// 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()
}

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/src" "cmd/internal/src"
@ -20,10 +21,10 @@ func exportf(bout *bio.Writer, format string, args ...interface{}) {
} }
} }
var asmlist []*Node var asmlist []*ir.Node
// exportsym marks n for export (or reexport). // exportsym marks n for export (or reexport).
func exportsym(n *Node) { func exportsym(n *ir.Node) {
if n.Sym.OnExportList() { if n.Sym.OnExportList() {
return return
} }
@ -40,14 +41,14 @@ func initname(s string) bool {
return s == "init" return s == "init"
} }
func autoexport(n *Node, ctxt Class) { func autoexport(n *ir.Node, ctxt ir.Class) {
if n.Sym.Pkg != localpkg { if n.Sym.Pkg != ir.LocalPkg {
return return
} }
if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN { if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || dclcontext != ir.PEXTERN {
return return
} }
if n.Type != nil && n.Type.IsKind(TFUNC) && n.IsMethod() { if n.Type != nil && n.Type.IsKind(types.TFUNC) && ir.IsMethod(n) {
return return
} }
@ -73,8 +74,8 @@ func dumpexport(bout *bio.Writer) {
} }
} }
func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node { func importsym(ipkg *types.Pkg, s *types.Sym, op ir.Op) *ir.Node {
n := asNode(s.PkgDef()) n := ir.AsNode(s.PkgDef())
if n == nil { if n == nil {
// iimport should have created a stub ONONAME // iimport should have created a stub ONONAME
// declaration for all imported symbols. The exception // declaration for all imported symbols. The exception
@ -85,10 +86,10 @@ func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node {
} }
n = dclname(s) n = dclname(s)
s.SetPkgDef(asTypesNode(n)) s.SetPkgDef(ir.AsTypesNode(n))
s.Importdef = ipkg 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)) redeclare(base.Pos, s, fmt.Sprintf("during import %q", ipkg.Path))
} }
return n return n
@ -98,16 +99,16 @@ func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node {
// If no such type has been declared yet, a forward declaration is returned. // If no such type has been declared yet, a forward declaration is returned.
// ipkg is the package being imported // ipkg is the package being imported
func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type { func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type {
n := importsym(ipkg, s, OTYPE) n := importsym(ipkg, s, ir.OTYPE)
if n.Op != OTYPE { if n.Op != ir.OTYPE {
t := types.New(TFORW) t := types.New(types.TFORW)
t.Sym = s t.Sym = s
t.Nod = asTypesNode(n) t.Nod = ir.AsTypesNode(n)
n.Op = OTYPE n.Op = ir.OTYPE
n.Pos = pos n.Pos = pos
n.Type = t n.Type = t
n.SetClass(PEXTERN) n.SetClass(ir.PEXTERN)
} }
t := n.Type t := n.Type
@ -119,9 +120,9 @@ func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type {
// importobj declares symbol s as an imported object representable by op. // importobj declares symbol s as an imported object representable by op.
// ipkg is the package being imported // 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) 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)) { if n.Op == op && (n.Class() != ctxt || !types.Identical(n.Type, t)) {
redeclare(base.Pos, s, fmt.Sprintf("during import %q", ipkg.Path)) redeclare(base.Pos, s, fmt.Sprintf("during import %q", ipkg.Path))
} }
@ -131,7 +132,7 @@ func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op, ctxt Class, t
n.Op = op n.Op = op
n.Pos = pos n.Pos = pos
n.SetClass(ctxt) n.SetClass(ctxt)
if ctxt == PFUNC { if ctxt == ir.PFUNC {
n.Sym.SetFunc(true) n.Sym.SetFunc(true)
} }
n.Type = t n.Type = t
@ -141,7 +142,7 @@ func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op, ctxt Class, t
// importconst declares symbol s as an imported constant with type t and value val. // importconst declares symbol s as an imported constant with type t and value val.
// ipkg is the package being imported // ipkg is the package being imported
func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) { 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. if n == nil { // TODO: Check that value matches.
return return
} }
@ -156,12 +157,12 @@ func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val
// importfunc declares symbol s as an imported function with type t. // importfunc declares symbol s as an imported function with type t.
// ipkg is the package being imported // ipkg is the package being imported
func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) { 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 { if n == nil {
return return
} }
n.Func = new(Func) n.Func = new(ir.Func)
if base.Flag.E != 0 { if base.Flag.E != 0 {
fmt.Printf("import func %v%S\n", s, t) fmt.Printf("import func %v%S\n", s, t)
@ -171,7 +172,7 @@ func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
// importvar declares symbol s as an imported variable with type t. // importvar declares symbol s as an imported variable with type t.
// ipkg is the package being imported // ipkg is the package being imported
func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) { 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 { if n == nil {
return return
} }
@ -184,7 +185,7 @@ func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
// importalias declares symbol s as an imported type alias with type t. // importalias declares symbol s as an imported type alias with type t.
// ipkg is the package being imported // ipkg is the package being imported
func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) { 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 { if n == nil {
return return
} }
@ -199,20 +200,20 @@ func dumpasmhdr() {
if err != nil { if err != nil {
base.Fatalf("%v", err) 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 { for _, n := range asmlist {
if n.Sym.IsBlank() { if n.Sym.IsBlank() {
continue continue
} }
switch n.Op { switch n.Op {
case OLITERAL: case ir.OLITERAL:
t := n.Val().Kind() t := n.Val().Kind()
if t == constant.Float || t == constant.Complex { if t == constant.Float || t == constant.Complex {
break break
} }
fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val()) fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
case OTYPE: case ir.OTYPE:
t := n.Type t := n.Type
if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
break break

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
@ -29,14 +30,14 @@ func sysvar(name string) *obj.LSym {
// isParamStackCopy reports whether this is the on-stack copy of a // isParamStackCopy reports whether this is the on-stack copy of a
// function parameter that moved to the heap. // function parameter that moved to the heap.
func (n *Node) isParamStackCopy() bool { func isParamStackCopy(n *ir.Node) bool {
return n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) && n.Name.Param.Heapaddr != nil 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 // isParamHeapCopy reports whether this is the on-heap copy of
// a function parameter that moved to the heap. // a function parameter that moved to the heap.
func (n *Node) isParamHeapCopy() bool { func isParamHeapCopy(n *ir.Node) bool {
return n.Op == ONAME && n.Class() == PAUTOHEAP && n.Name.Param.Stackcopy != nil return n.Op == ir.ONAME && n.Class() == ir.PAUTOHEAP && n.Name.Param.Stackcopy != nil
} }
// autotmpname returns the name for an autotmp variable numbered n. // autotmpname returns the name for an autotmp variable numbered n.
@ -51,12 +52,12 @@ func autotmpname(n int) string {
} }
// make a new Node off the books // 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 { if curfn == nil {
base.Fatalf("no curfn for tempAt") base.Fatalf("no curfn for tempAt")
} }
if curfn.Op == OCLOSURE { if curfn.Op == ir.OCLOSURE {
Dump("tempAt", curfn) ir.Dump("tempAt", curfn)
base.Fatalf("adding tempAt to wrong closure function") base.Fatalf("adding tempAt to wrong closure function")
} }
if t == nil { if t == nil {
@ -65,12 +66,12 @@ func tempAt(pos src.XPos, curfn *Node, t *types.Type) *Node {
s := &types.Sym{ s := &types.Sym{
Name: autotmpname(len(curfn.Func.Dcl)), Name: autotmpname(len(curfn.Func.Dcl)),
Pkg: localpkg, Pkg: ir.LocalPkg,
} }
n := newnamel(pos, s) n := ir.NewNameAt(pos, s)
s.Def = asTypesNode(n) s.Def = ir.AsTypesNode(n)
n.Type = t n.Type = t
n.SetClass(PAUTO) n.SetClass(ir.PAUTO)
n.Esc = EscNever n.Esc = EscNever
n.Name.Curfn = curfn n.Name.Curfn = curfn
n.Name.SetUsed(true) n.Name.SetUsed(true)
@ -82,6 +83,6 @@ func tempAt(pos src.XPos, curfn *Node, t *types.Type) *Node {
return n.Orig return n.Orig
} }
func temp(t *types.Type) *Node { func temp(t *types.Type) *ir.Node {
return tempAt(base.Pos, Curfn, t) return tempAt(base.Pos, Curfn, t)
} }

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
@ -13,10 +14,6 @@ import (
"sync" "sync"
) )
const (
BADWIDTH = types.BADWIDTH
)
var ( var (
// maximum size variable which we will allocate on the stack. // maximum size variable which we will allocate on the stack.
// This limit is for explicit variable declarations like "var x T" or "x := ...". // This limit is for explicit variable declarations like "var x T" or "x := ...".
@ -40,7 +37,7 @@ var (
// isRuntimePkg reports whether p is package runtime. // isRuntimePkg reports whether p is package runtime.
func isRuntimePkg(p *types.Pkg) bool { func isRuntimePkg(p *types.Pkg) bool {
if base.Flag.CompilingRuntime && p == localpkg { if base.Flag.CompilingRuntime && p == ir.LocalPkg {
return true return true
} }
return p.Path == "runtime" return p.Path == "runtime"
@ -48,31 +45,12 @@ func isRuntimePkg(p *types.Pkg) bool {
// isReflectPkg reports whether p is package reflect. // isReflectPkg reports whether p is package reflect.
func isReflectPkg(p *types.Pkg) bool { func isReflectPkg(p *types.Pkg) bool {
if p == localpkg { if p == ir.LocalPkg {
return base.Ctxt.Pkgpath == "reflect" return base.Ctxt.Pkgpath == "reflect"
} }
return p.Path == "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: // Slices in the runtime are represented by three components:
// //
// type slice struct { // type slice struct {
@ -102,8 +80,6 @@ var pragcgobuf [][]string
var decldepth int32 var decldepth int32
var localpkg *types.Pkg // package being compiled
var inimport bool // set during import var inimport bool // set during import
var itabpkg *types.Pkg // fake pkg for itab entries var itabpkg *types.Pkg // fake pkg for itab entries
@ -126,55 +102,51 @@ var gopkg *types.Pkg // pseudo-package for method symbols on anonymous receiver
var zerosize int64 var zerosize int64
var simtype [NTYPE]types.EType var simtype [types.NTYPE]types.EType
var ( var (
isInt [NTYPE]bool isInt [types.NTYPE]bool
isFloat [NTYPE]bool isFloat [types.NTYPE]bool
isComplex [NTYPE]bool isComplex [types.NTYPE]bool
issimple [NTYPE]bool issimple [types.NTYPE]bool
) )
var ( var (
okforeq [NTYPE]bool okforeq [types.NTYPE]bool
okforadd [NTYPE]bool okforadd [types.NTYPE]bool
okforand [NTYPE]bool okforand [types.NTYPE]bool
okfornone [NTYPE]bool okfornone [types.NTYPE]bool
okforcmp [NTYPE]bool okforcmp [types.NTYPE]bool
okforbool [NTYPE]bool okforbool [types.NTYPE]bool
okforcap [NTYPE]bool okforcap [types.NTYPE]bool
okforlen [NTYPE]bool okforlen [types.NTYPE]bool
okforarith [NTYPE]bool okforarith [types.NTYPE]bool
) )
var okforconst [NTYPE]bool
var ( var (
okfor [OEND][]bool okfor [ir.OEND][]bool
iscmp [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 ( var (
funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym) funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
funcsyms []*types.Sym 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 Widthptr int
var Widthreg int var Widthreg int
var nblank *Node
var typecheckok bool var typecheckok bool
// Whether we are adding any sort of code instrumentation, such as // Whether we are adding any sort of code instrumentation, such as
@ -184,7 +156,7 @@ var instrumenting bool
// Whether we are tracking lexical scopes for DWARF. // Whether we are tracking lexical scopes for DWARF.
var trackScopes bool var trackScopes bool
var nodfp *Node var nodfp *ir.Node
var autogeneratedPos src.XPos var autogeneratedPos src.XPos
@ -221,7 +193,7 @@ var thearch Arch
var ( var (
staticuint64s, staticuint64s,
zerobase *Node zerobase *ir.Node
assertE2I, assertE2I,
assertE2I2, assertE2I2,

View file

@ -32,6 +32,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/objabi" "cmd/internal/objabi"
@ -46,7 +47,7 @@ type Progs struct {
next *obj.Prog // next Prog next *obj.Prog // next Prog
pc int64 // virtual PC; count of Progs pc int64 // virtual PC; count of Progs
pos src.XPos // position to use for new 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 progcache []obj.Prog // local progcache
cacheidx int // first free element of progcache cacheidx int // first free element of progcache
@ -56,7 +57,7 @@ type Progs struct {
// newProgs returns a new Progs for fn. // newProgs returns a new Progs for fn.
// worker indicates which of the backend workers will use the Progs. // 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) pp := new(Progs)
if base.Ctxt.CanReuseProgs() { if base.Ctxt.CanReuseProgs() {
sz := len(sharedProgArray) / base.Flag.LowerC sz := len(sharedProgArray) / base.Flag.LowerC
@ -173,17 +174,17 @@ func (pp *Progs) Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16
return q return q
} }
func (pp *Progs) settext(fn *Node) { func (pp *Progs) settext(fn *ir.Node) {
if pp.Text != nil { if pp.Text != nil {
base.Fatalf("Progs.settext called twice") base.Fatalf("Progs.settext called twice")
} }
ptxt := pp.Prog(obj.ATEXT) ptxt := pp.Prog(obj.ATEXT)
pp.Text = ptxt pp.Text = ptxt
fn.Func.lsym.Func().Text = ptxt fn.Func.LSym.Func().Text = ptxt
ptxt.From.Type = obj.TYPE_MEM ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN 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 defines f's obj.LSym and initializes it based on the
@ -192,36 +193,36 @@ func (pp *Progs) settext(fn *Node) {
// //
// initLSym must be called exactly once per function and must be // initLSym must be called exactly once per function and must be
// called for both functions with bodies and functions without bodies. // called for both functions with bodies and functions without bodies.
func (f *Func) initLSym(hasBody bool) { func initLSym(f *ir.Func, hasBody bool) {
if f.lsym != nil { if f.LSym != nil {
base.Fatalf("Func.initLSym called twice") base.Fatalf("Func.initLSym called twice")
} }
if nam := f.Nname; !nam.isBlank() { if nam := f.Nname; !ir.IsBlank(nam) {
f.lsym = nam.Sym.Linksym() f.LSym = nam.Sym.Linksym()
if f.Pragma&Systemstack != 0 { if f.Pragma&ir.Systemstack != 0 {
f.lsym.Set(obj.AttrCFunc, true) f.LSym.Set(obj.AttrCFunc, true)
} }
var aliasABI obj.ABI var aliasABI obj.ABI
needABIAlias := false needABIAlias := false
defABI, hasDefABI := symabiDefs[f.lsym.Name] defABI, hasDefABI := symabiDefs[f.LSym.Name]
if hasDefABI && defABI == obj.ABI0 { if hasDefABI && defABI == obj.ABI0 {
// Symbol is defined as ABI0. Create an // Symbol is defined as ABI0. Create an
// Internal -> ABI0 wrapper. // Internal -> ABI0 wrapper.
f.lsym.SetABI(obj.ABI0) f.LSym.SetABI(obj.ABI0)
needABIAlias, aliasABI = true, obj.ABIInternal needABIAlias, aliasABI = true, obj.ABIInternal
} else { } else {
// No ABI override. Check that the symbol is // No ABI override. Check that the symbol is
// using the expected ABI. // using the expected ABI.
want := obj.ABIInternal want := obj.ABIInternal
if 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) 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) 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 // Either 1) this symbol is definitely
// referenced as ABI0 from this package; or 2) // referenced as ABI0 from this package; or 2)
// this symbol is defined in this package but // this symbol is defined in this package but
@ -233,7 +234,7 @@ func (f *Func) initLSym(hasBody bool) {
// since other packages may "pull" symbols // since other packages may "pull" symbols
// using linkname and we don't want to create // using linkname and we don't want to create
// duplicate ABI wrappers. // duplicate ABI wrappers.
if f.lsym.ABI() != obj.ABI0 { if f.LSym.ABI() != obj.ABI0 {
needABIAlias, aliasABI = true, obj.ABI0 needABIAlias, aliasABI = true, obj.ABI0
} }
} }
@ -244,9 +245,9 @@ func (f *Func) initLSym(hasBody bool) {
// rather than looking them up. The uniqueness // rather than looking them up. The uniqueness
// of f.lsym ensures uniqueness of asym. // of f.lsym ensures uniqueness of asym.
asym := &obj.LSym{ asym := &obj.LSym{
Name: f.lsym.Name, Name: f.LSym.Name,
Type: objabi.SABIALIAS, 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.SetABI(aliasABI)
asym.Set(obj.AttrDuplicateOK, true) asym.Set(obj.AttrDuplicateOK, true)
@ -269,7 +270,7 @@ func (f *Func) initLSym(hasBody bool) {
if f.Needctxt() { if f.Needctxt() {
flag |= obj.NEEDCTXT flag |= obj.NEEDCTXT
} }
if f.Pragma&Nosplit != 0 { if f.Pragma&ir.Nosplit != 0 {
flag |= obj.NOSPLIT flag |= obj.NOSPLIT
} }
if f.ReflectMethod() { if f.ReflectMethod() {
@ -286,10 +287,10 @@ func (f *Func) initLSym(hasBody bool) {
} }
} }
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 := nam.Sym.Linksym()
s.Gotype = ngotype(nam).Linksym() s.Gotype = ngotype(nam).Linksym()
flags := 0 flags := 0

View file

@ -205,6 +205,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/goobj" "cmd/internal/goobj"
"cmd/internal/src" "cmd/internal/src"
@ -258,8 +259,8 @@ func iexport(out *bufio.Writer) {
p := iexporter{ p := iexporter{
allPkgs: map[*types.Pkg]bool{}, allPkgs: map[*types.Pkg]bool{},
stringIndex: map[string]uint64{}, stringIndex: map[string]uint64{},
declIndex: map[*Node]uint64{}, declIndex: map[*ir.Node]uint64{},
inlineIndex: map[*Node]uint64{}, inlineIndex: map[*ir.Node]uint64{},
typIndex: map[*types.Type]uint64{}, typIndex: map[*types.Type]uint64{},
} }
@ -278,8 +279,8 @@ func iexport(out *bufio.Writer) {
// Loop until no more work. We use a queue because while // Loop until no more work. We use a queue because while
// writing out inline bodies, we may discover additional // writing out inline bodies, we may discover additional
// declarations that are needed. // declarations that are needed.
for !p.declTodo.empty() { for !p.declTodo.Empty() {
p.doDecl(p.declTodo.popLeft()) p.doDecl(p.declTodo.PopLeft())
} }
// Append indices to data0 section. // Append indices to data0 section.
@ -313,15 +314,15 @@ func iexport(out *bufio.Writer) {
// we're writing out the main index, which is also read by // we're writing out the main index, which is also read by
// non-compiler tools and includes a complete package description // non-compiler tools and includes a complete package description
// (i.e., name and height). // (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. // 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 // For the main index, make sure to include every package that
// we reference, even if we're not exporting (or reexporting) // we reference, even if we're not exporting (or reexporting)
// any symbols from it. // any symbols from it.
if mainIndex { if mainIndex {
pkgObjs[localpkg] = nil pkgObjs[ir.LocalPkg] = nil
for pkg := range w.p.allPkgs { for pkg := range w.p.allPkgs {
pkgObjs[pkg] = nil pkgObjs[pkg] = nil
} }
@ -367,14 +368,14 @@ type iexporter struct {
// main index. // main index.
allPkgs map[*types.Pkg]bool allPkgs map[*types.Pkg]bool
declTodo nodeQueue declTodo ir.NodeQueue
strings intWriter strings intWriter
stringIndex map[string]uint64 stringIndex map[string]uint64
data0 intWriter data0 intWriter
declIndex map[*Node]uint64 declIndex map[*ir.Node]uint64
inlineIndex map[*Node]uint64 inlineIndex map[*ir.Node]uint64
typIndex map[*types.Type]uint64 typIndex map[*types.Type]uint64
} }
@ -393,13 +394,13 @@ func (p *iexporter) stringOff(s string) uint64 {
} }
// pushDecl adds n to the declaration work queue, if not already present. // pushDecl adds n to the declaration work queue, if not already present.
func (p *iexporter) pushDecl(n *Node) { func (p *iexporter) pushDecl(n *ir.Node) {
if n.Sym == nil || asNode(n.Sym.Def) != n && n.Op != OTYPE { if n.Sym == nil || ir.AsNode(n.Sym.Def) != n && n.Op != ir.OTYPE {
base.Fatalf("weird Sym: %v, %v", n, n.Sym) base.Fatalf("weird Sym: %v, %v", n, n.Sym)
} }
// Don't export predeclared declarations. // 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 return
} }
@ -408,7 +409,7 @@ func (p *iexporter) pushDecl(n *Node) {
} }
p.declIndex[n] = ^uint64(0) // mark n present in work queue 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. // exportWriter handles writing out individual data section chunks.
@ -422,22 +423,22 @@ type exportWriter struct {
prevColumn int64 prevColumn int64
} }
func (p *iexporter) doDecl(n *Node) { func (p *iexporter) doDecl(n *ir.Node) {
w := p.newWriter() w := p.newWriter()
w.setPkg(n.Sym.Pkg, false) w.setPkg(n.Sym.Pkg, false)
switch n.Op { switch n.Op {
case ONAME: case ir.ONAME:
switch n.Class() { switch n.Class() {
case PEXTERN: case ir.PEXTERN:
// Variable. // Variable.
w.tag('V') w.tag('V')
w.pos(n.Pos) w.pos(n.Pos)
w.typ(n.Type) w.typ(n.Type)
w.varExt(n) w.varExt(n)
case PFUNC: case ir.PFUNC:
if n.IsMethod() { if ir.IsMethod(n) {
base.Fatalf("unexpected method: %v", n) base.Fatalf("unexpected method: %v", n)
} }
@ -451,14 +452,14 @@ func (p *iexporter) doDecl(n *Node) {
base.Fatalf("unexpected class: %v, %v", n, n.Class()) base.Fatalf("unexpected class: %v, %v", n, n.Class())
} }
case OLITERAL: case ir.OLITERAL:
// Constant. // Constant.
n = typecheck(n, ctxExpr) n = typecheck(n, ctxExpr)
w.tag('C') w.tag('C')
w.pos(n.Pos) w.pos(n.Pos)
w.value(n.Type, n.Val()) w.value(n.Type, n.Val())
case OTYPE: case ir.OTYPE:
if IsAlias(n.Sym) { if IsAlias(n.Sym) {
// Alias. // Alias.
w.tag('A') w.tag('A')
@ -514,11 +515,11 @@ func (w *exportWriter) tag(tag byte) {
w.data.WriteByte(tag) w.data.WriteByte(tag)
} }
func (p *iexporter) doInline(f *Node) { func (p *iexporter) doInline(f *ir.Node) {
w := p.newWriter() w := p.newWriter()
w.setPkg(fnpkg(f), false) 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() p.inlineIndex[f] = w.flush()
} }
@ -569,7 +570,7 @@ func (w *exportWriter) pkg(pkg *types.Pkg) {
w.string(pkg.Path) 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. // Ensure any referenced declarations are written out too.
w.p.pushDecl(n) w.p.pushDecl(n)
@ -592,7 +593,7 @@ func (w *exportWriter) selector(s *types.Sym) {
} else { } else {
pkg := w.currPkg pkg := w.currPkg
if types.IsExported(name) { if types.IsExported(name) {
pkg = localpkg pkg = ir.LocalPkg
} }
if s.Pkg != pkg { if s.Pkg != pkg {
base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path) base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
@ -633,7 +634,7 @@ func (w *exportWriter) startType(k itag) {
func (w *exportWriter) doTyp(t *types.Type) { func (w *exportWriter) doTyp(t *types.Type) {
if t.Sym != nil { 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) base.Fatalf("builtin type missing from typIndex: %v", t)
} }
@ -643,35 +644,35 @@ func (w *exportWriter) doTyp(t *types.Type) {
} }
switch t.Etype { switch t.Etype {
case TPTR: case types.TPTR:
w.startType(pointerType) w.startType(pointerType)
w.typ(t.Elem()) w.typ(t.Elem())
case TSLICE: case types.TSLICE:
w.startType(sliceType) w.startType(sliceType)
w.typ(t.Elem()) w.typ(t.Elem())
case TARRAY: case types.TARRAY:
w.startType(arrayType) w.startType(arrayType)
w.uint64(uint64(t.NumElem())) w.uint64(uint64(t.NumElem()))
w.typ(t.Elem()) w.typ(t.Elem())
case TCHAN: case types.TCHAN:
w.startType(chanType) w.startType(chanType)
w.uint64(uint64(t.ChanDir())) w.uint64(uint64(t.ChanDir()))
w.typ(t.Elem()) w.typ(t.Elem())
case TMAP: case types.TMAP:
w.startType(mapType) w.startType(mapType)
w.typ(t.Key()) w.typ(t.Key())
w.typ(t.Elem()) w.typ(t.Elem())
case TFUNC: case types.TFUNC:
w.startType(signatureType) w.startType(signatureType)
w.setPkg(t.Pkg(), true) w.setPkg(t.Pkg(), true)
w.signature(t) w.signature(t)
case TSTRUCT: case types.TSTRUCT:
w.startType(structType) w.startType(structType)
w.setPkg(t.Pkg(), true) w.setPkg(t.Pkg(), true)
@ -684,7 +685,7 @@ func (w *exportWriter) doTyp(t *types.Type) {
w.string(f.Note) w.string(f.Note)
} }
case TINTER: case types.TINTER:
var embeddeds, methods []*types.Field var embeddeds, methods []*types.Field
for _, m := range t.Methods().Slice() { for _, m := range t.Methods().Slice() {
if m.Sym != nil { if m.Sym != nil {
@ -719,7 +720,7 @@ func (w *exportWriter) setPkg(pkg *types.Pkg, write bool) {
if pkg == nil { if pkg == nil {
// TODO(mdempsky): Proactively set Pkg for types and // TODO(mdempsky): Proactively set Pkg for types and
// remove this fallback logic. // remove this fallback logic.
pkg = localpkg pkg = ir.LocalPkg
} }
if write { if write {
@ -746,7 +747,7 @@ func (w *exportWriter) paramList(fs []*types.Field) {
func (w *exportWriter) param(f *types.Field) { func (w *exportWriter) param(f *types.Field) {
w.pos(f.Pos) w.pos(f.Pos)
w.localIdent(origSym(f.Sym), 0) w.localIdent(ir.OrigSym(f.Sym), 0)
w.typ(f.Type) w.typ(f.Type)
} }
@ -761,16 +762,16 @@ func constTypeOf(typ *types.Type) constant.Kind {
} }
switch typ.Etype { switch typ.Etype {
case TBOOL: case types.TBOOL:
return constant.Bool return constant.Bool
case TSTRING: case types.TSTRING:
return constant.String return constant.String
case TINT, TINT8, TINT16, TINT32, TINT64, case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64,
TUINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINTPTR: types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
return constant.Int return constant.Int
case TFLOAT32, TFLOAT64: case types.TFLOAT32, types.TFLOAT64:
return constant.Float return constant.Float
case TCOMPLEX64, TCOMPLEX128: case types.TCOMPLEX64, types.TCOMPLEX128:
return constant.Complex return constant.Complex
} }
@ -779,7 +780,7 @@ func constTypeOf(typ *types.Type) constant.Kind {
} }
func (w *exportWriter) value(typ *types.Type, v constant.Value) { func (w *exportWriter) value(typ *types.Type, v constant.Value) {
assertRepresents(typ, v) ir.AssertValidTypeForConst(typ, v)
w.typ(typ) w.typ(typ)
// Each type has only one admissible constant representation, // Each type has only one admissible constant representation,
@ -808,9 +809,9 @@ func intSize(typ *types.Type) (signed bool, maxBytes uint) {
} }
switch typ.Etype { switch typ.Etype {
case TFLOAT32, TCOMPLEX64: case types.TFLOAT32, types.TCOMPLEX64:
return true, 3 return true, 3
case TFLOAT64, TCOMPLEX128: case types.TFLOAT64, types.TCOMPLEX128:
return true, 7 return true, 7
} }
@ -820,7 +821,7 @@ func intSize(typ *types.Type) (signed bool, maxBytes uint) {
// The go/types API doesn't expose sizes to importers, so they // The go/types API doesn't expose sizes to importers, so they
// don't know how big these types are. // don't know how big these types are.
switch typ.Etype { switch typ.Etype {
case TINT, TUINT, TUINTPTR: case types.TINT, types.TUINT, types.TUINTPTR:
maxBytes = 8 maxBytes = 8
} }
@ -954,12 +955,12 @@ func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
// Compiler-specific extensions. // Compiler-specific extensions.
func (w *exportWriter) varExt(n *Node) { func (w *exportWriter) varExt(n *ir.Node) {
w.linkname(n.Sym) w.linkname(n.Sym)
w.symIdx(n.Sym) w.symIdx(n.Sym)
} }
func (w *exportWriter) funcExt(n *Node) { func (w *exportWriter) funcExt(n *ir.Node) {
w.linkname(n.Sym) w.linkname(n.Sym)
w.symIdx(n.Sym) w.symIdx(n.Sym)
@ -993,7 +994,7 @@ func (w *exportWriter) funcExt(n *Node) {
func (w *exportWriter) methExt(m *types.Field) { func (w *exportWriter) methExt(m *types.Field) {
w.bool(m.Nointerface()) w.bool(m.Nointerface())
w.funcExt(asNode(m.Nname)) w.funcExt(ir.AsNode(m.Nname))
} }
func (w *exportWriter) linkname(s *types.Sym) { func (w *exportWriter) linkname(s *types.Sym) {
@ -1029,15 +1030,15 @@ func (w *exportWriter) typeExt(t *types.Type) {
// Inline bodies. // Inline bodies.
func (w *exportWriter) stmtList(list Nodes) { func (w *exportWriter) stmtList(list ir.Nodes) {
for _, n := range list.Slice() { for _, n := range list.Slice() {
w.node(n) w.node(n)
} }
w.op(OEND) w.op(ir.OEND)
} }
func (w *exportWriter) node(n *Node) { func (w *exportWriter) node(n *ir.Node) {
if opprec[n.Op] < 0 { if ir.OpPrec[n.Op] < 0 {
w.stmt(n) w.stmt(n)
} else { } else {
w.expr(n) w.expr(n)
@ -1046,8 +1047,8 @@ func (w *exportWriter) node(n *Node) {
// Caution: stmt will emit more than one node for statement nodes n that have a non-empty // 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.). // n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
func (w *exportWriter) stmt(n *Node) { func (w *exportWriter) stmt(n *ir.Node) {
if n.Ninit.Len() > 0 && !stmtwithinit(n.Op) { if n.Ninit.Len() > 0 && !ir.StmtWithInit(n.Op) {
// can't use stmtList here since we don't want the final OEND // can't use stmtList here since we don't want the final OEND
for _, n := range n.Ninit.Slice() { for _, n := range n.Ninit.Slice() {
w.stmt(n) w.stmt(n)
@ -1055,8 +1056,8 @@ func (w *exportWriter) stmt(n *Node) {
} }
switch op := n.Op; op { switch op := n.Op; op {
case ODCL: case ir.ODCL:
w.op(ODCL) w.op(ir.ODCL)
w.pos(n.Left.Pos) w.pos(n.Left.Pos)
w.localName(n.Left) w.localName(n.Left)
w.typ(n.Left.Type) w.typ(n.Left.Type)
@ -1064,19 +1065,19 @@ func (w *exportWriter) stmt(n *Node) {
// case ODCLFIELD: // case ODCLFIELD:
// unimplemented - handled by default case // unimplemented - handled by default case
case OAS: case ir.OAS:
// Don't export "v = <N>" initializing statements, hope they're always // Don't export "v = <N>" initializing statements, hope they're always
// preceded by the DCL which will be re-parsed and typecheck to reproduce // preceded by the DCL which will be re-parsed and typecheck to reproduce
// the "v = <N>" again. // the "v = <N>" again.
if n.Right != nil { if n.Right != nil {
w.op(OAS) w.op(ir.OAS)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
w.expr(n.Right) w.expr(n.Right)
} }
case OASOP: case ir.OASOP:
w.op(OASOP) w.op(ir.OASOP)
w.pos(n.Pos) w.pos(n.Pos)
w.op(n.SubOp()) w.op(n.SubOp())
w.expr(n.Left) w.expr(n.Left)
@ -1084,54 +1085,54 @@ func (w *exportWriter) stmt(n *Node) {
w.expr(n.Right) w.expr(n.Right)
} }
case OAS2: case ir.OAS2:
w.op(OAS2) w.op(ir.OAS2)
w.pos(n.Pos) w.pos(n.Pos)
w.exprList(n.List) w.exprList(n.List)
w.exprList(n.Rlist) w.exprList(n.Rlist)
case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
w.op(OAS2) w.op(ir.OAS2)
w.pos(n.Pos) w.pos(n.Pos)
w.exprList(n.List) w.exprList(n.List)
w.exprList(asNodes([]*Node{n.Right})) w.exprList(ir.AsNodes([]*ir.Node{n.Right}))
case ORETURN: case ir.ORETURN:
w.op(ORETURN) w.op(ir.ORETURN)
w.pos(n.Pos) w.pos(n.Pos)
w.exprList(n.List) w.exprList(n.List)
// case ORETJMP: // case ORETJMP:
// unreachable - generated by compiler for trampolin routines // unreachable - generated by compiler for trampolin routines
case OGO, ODEFER: case ir.OGO, ir.ODEFER:
w.op(op) w.op(op)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
case OIF: case ir.OIF:
w.op(OIF) w.op(ir.OIF)
w.pos(n.Pos) w.pos(n.Pos)
w.stmtList(n.Ninit) w.stmtList(n.Ninit)
w.expr(n.Left) w.expr(n.Left)
w.stmtList(n.Nbody) w.stmtList(n.Nbody)
w.stmtList(n.Rlist) w.stmtList(n.Rlist)
case OFOR: case ir.OFOR:
w.op(OFOR) w.op(ir.OFOR)
w.pos(n.Pos) w.pos(n.Pos)
w.stmtList(n.Ninit) w.stmtList(n.Ninit)
w.exprsOrNil(n.Left, n.Right) w.exprsOrNil(n.Left, n.Right)
w.stmtList(n.Nbody) w.stmtList(n.Nbody)
case ORANGE: case ir.ORANGE:
w.op(ORANGE) w.op(ir.ORANGE)
w.pos(n.Pos) w.pos(n.Pos)
w.stmtList(n.List) w.stmtList(n.List)
w.expr(n.Right) w.expr(n.Right)
w.stmtList(n.Nbody) w.stmtList(n.Nbody)
case OSELECT, OSWITCH: case ir.OSELECT, ir.OSWITCH:
w.op(op) w.op(op)
w.pos(n.Pos) w.pos(n.Pos)
w.stmtList(n.Ninit) w.stmtList(n.Ninit)
@ -1141,19 +1142,19 @@ func (w *exportWriter) stmt(n *Node) {
// case OCASE: // case OCASE:
// handled by caseList // handled by caseList
case OFALL: case ir.OFALL:
w.op(OFALL) w.op(ir.OFALL)
w.pos(n.Pos) w.pos(n.Pos)
case OBREAK, OCONTINUE: case ir.OBREAK, ir.OCONTINUE:
w.op(op) w.op(op)
w.pos(n.Pos) w.pos(n.Pos)
w.exprsOrNil(n.Left, nil) w.exprsOrNil(n.Left, nil)
case OEMPTY: case ir.OEMPTY:
// nothing to emit // nothing to emit
case OGOTO, OLABEL: case ir.OGOTO, ir.OLABEL:
w.op(op) w.op(op)
w.pos(n.Pos) w.pos(n.Pos)
w.string(n.Sym.Name) w.string(n.Sym.Name)
@ -1163,13 +1164,13 @@ func (w *exportWriter) stmt(n *Node) {
} }
} }
func (w *exportWriter) caseList(sw *Node) { func (w *exportWriter) caseList(sw *ir.Node) {
namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil namedTypeSwitch := sw.Op == ir.OSWITCH && sw.Left != nil && sw.Left.Op == ir.OTYPESW && sw.Left.Left != nil
cases := sw.List.Slice() cases := sw.List.Slice()
w.uint64(uint64(len(cases))) w.uint64(uint64(len(cases)))
for _, cas := range cases { for _, cas := range cases {
if cas.Op != OCASE { if cas.Op != ir.OCASE {
base.Fatalf("expected OCASE, got %v", cas) base.Fatalf("expected OCASE, got %v", cas)
} }
w.pos(cas.Pos) w.pos(cas.Pos)
@ -1181,14 +1182,14 @@ func (w *exportWriter) caseList(sw *Node) {
} }
} }
func (w *exportWriter) exprList(list Nodes) { func (w *exportWriter) exprList(list ir.Nodes) {
for _, n := range list.Slice() { for _, n := range list.Slice() {
w.expr(n) 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) // from nodefmt (fmt.go)
// //
// nodefmt reverts nodes back to their original - we don't need to do // nodefmt reverts nodes back to their original - we don't need to do
@ -1199,14 +1200,14 @@ func (w *exportWriter) expr(n *Node) {
// } // }
// from exprfmt (fmt.go) // 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 n = n.Left
} }
switch op := n.Op; op { switch op := n.Op; op {
// expressions // expressions
// (somewhat closely following the structure of exprfmt in fmt.go) // (somewhat closely following the structure of exprfmt in fmt.go)
case ONIL: case ir.ONIL:
if !n.Type.HasNil() { if !n.Type.HasNil() {
base.Fatalf("unexpected type for nil: %v", n.Type) base.Fatalf("unexpected type for nil: %v", n.Type)
} }
@ -1214,49 +1215,49 @@ func (w *exportWriter) expr(n *Node) {
w.expr(n.Orig) w.expr(n.Orig)
break break
} }
w.op(OLITERAL) w.op(ir.OLITERAL)
w.pos(n.Pos) w.pos(n.Pos)
w.typ(n.Type) w.typ(n.Type)
case OLITERAL: case ir.OLITERAL:
w.op(OLITERAL) w.op(ir.OLITERAL)
w.pos(n.Pos) w.pos(n.Pos)
w.value(n.Type, n.Val()) 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, // 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. // 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. // 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.pos(n.Pos)
w.expr(n.Left) // n.Left.Op == OTYPE w.expr(n.Left) // n.Left.Op == OTYPE
w.selector(n.Right.Sym) w.selector(n.Right.Sym)
case ONAME: case ir.ONAME:
// Package scope name. // Package scope name.
if (n.Class() == PEXTERN || n.Class() == PFUNC) && !n.isBlank() { if (n.Class() == ir.PEXTERN || n.Class() == ir.PFUNC) && !ir.IsBlank(n) {
w.op(ONONAME) w.op(ir.ONONAME)
w.qualifiedIdent(n) w.qualifiedIdent(n)
break break
} }
// Function scope name. // Function scope name.
w.op(ONAME) w.op(ir.ONAME)
w.localName(n) w.localName(n)
// case OPACK, ONONAME: // case OPACK, ONONAME:
// should have been resolved by typechecking - handled by default case // should have been resolved by typechecking - handled by default case
case OTYPE: case ir.OTYPE:
w.op(OTYPE) w.op(ir.OTYPE)
w.typ(n.Type) w.typ(n.Type)
case OTYPESW: case ir.OTYPESW:
w.op(OTYPESW) w.op(ir.OTYPESW)
w.pos(n.Pos) w.pos(n.Pos)
var s *types.Sym var s *types.Sym
if n.Left != nil { if n.Left != nil {
if n.Left.Op != ONONAME { if n.Left.Op != ir.ONONAME {
base.Fatalf("expected ONONAME, got %v", n.Left) base.Fatalf("expected ONONAME, got %v", n.Left)
} }
s = n.Left.Sym s = n.Left.Sym
@ -1273,149 +1274,149 @@ func (w *exportWriter) expr(n *Node) {
// case OCOMPLIT: // case OCOMPLIT:
// should have been resolved by typechecking - handled by default case // should have been resolved by typechecking - handled by default case
case OPTRLIT: case ir.OPTRLIT:
w.op(OADDR) w.op(ir.OADDR)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
case OSTRUCTLIT: case ir.OSTRUCTLIT:
w.op(OSTRUCTLIT) w.op(ir.OSTRUCTLIT)
w.pos(n.Pos) w.pos(n.Pos)
w.typ(n.Type) w.typ(n.Type)
w.elemList(n.List) // special handling of field names w.elemList(n.List) // special handling of field names
case OARRAYLIT, OSLICELIT, OMAPLIT: case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
w.op(OCOMPLIT) w.op(ir.OCOMPLIT)
w.pos(n.Pos) w.pos(n.Pos)
w.typ(n.Type) w.typ(n.Type)
w.exprList(n.List) w.exprList(n.List)
case OKEY: case ir.OKEY:
w.op(OKEY) w.op(ir.OKEY)
w.pos(n.Pos) w.pos(n.Pos)
w.exprsOrNil(n.Left, n.Right) w.exprsOrNil(n.Left, n.Right)
// case OSTRUCTKEY: // case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList // unreachable - handled in case OSTRUCTLIT by elemList
case OCALLPART: case ir.OCALLPART:
// An OCALLPART is an OXDOT before type checking. // An OCALLPART is an OXDOT before type checking.
w.op(OXDOT) w.op(ir.OXDOT)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
// Right node should be ONAME // Right node should be ONAME
w.selector(n.Right.Sym) w.selector(n.Right.Sym)
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH:
w.op(OXDOT) w.op(ir.OXDOT)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
w.selector(n.Sym) w.selector(n.Sym)
case ODOTTYPE, ODOTTYPE2: case ir.ODOTTYPE, ir.ODOTTYPE2:
w.op(ODOTTYPE) w.op(ir.ODOTTYPE)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
w.typ(n.Type) w.typ(n.Type)
case OINDEX, OINDEXMAP: case ir.OINDEX, ir.OINDEXMAP:
w.op(OINDEX) w.op(ir.OINDEX)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
w.expr(n.Right) w.expr(n.Right)
case OSLICE, OSLICESTR, OSLICEARR: case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR:
w.op(OSLICE) w.op(ir.OSLICE)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
low, high, _ := n.SliceBounds() low, high, _ := n.SliceBounds()
w.exprsOrNil(low, high) w.exprsOrNil(low, high)
case OSLICE3, OSLICE3ARR: case ir.OSLICE3, ir.OSLICE3ARR:
w.op(OSLICE3) w.op(ir.OSLICE3)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
low, high, max := n.SliceBounds() low, high, max := n.SliceBounds()
w.exprsOrNil(low, high) w.exprsOrNil(low, high)
w.expr(max) w.expr(max)
case OCOPY, OCOMPLEX: case ir.OCOPY, ir.OCOMPLEX:
// treated like other builtin calls (see e.g., OREAL) // treated like other builtin calls (see e.g., OREAL)
w.op(op) w.op(op)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
w.expr(n.Right) w.expr(n.Right)
w.op(OEND) w.op(ir.OEND)
case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR: case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR:
w.op(OCONV) w.op(ir.OCONV)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
w.typ(n.Type) 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.op(op)
w.pos(n.Pos) w.pos(n.Pos)
if n.Left != nil { if n.Left != nil {
w.expr(n.Left) w.expr(n.Left)
w.op(OEND) w.op(ir.OEND)
} else { } else {
w.exprList(n.List) // emits terminating OEND w.exprList(n.List) // emits terminating OEND
} }
// only append() calls may contain '...' arguments // only append() calls may contain '...' arguments
if op == OAPPEND { if op == ir.OAPPEND {
w.bool(n.IsDDD()) w.bool(n.IsDDD())
} else if n.IsDDD() { } else if n.IsDDD() {
base.Fatalf("exporter: unexpected '...' with %v call", op) base.Fatalf("exporter: unexpected '...' with %v call", op)
} }
case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
w.op(OCALL) w.op(ir.OCALL)
w.pos(n.Pos) w.pos(n.Pos)
w.stmtList(n.Ninit) w.stmtList(n.Ninit)
w.expr(n.Left) w.expr(n.Left)
w.exprList(n.List) w.exprList(n.List)
w.bool(n.IsDDD()) 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.op(op) // must keep separate from OMAKE for importer
w.pos(n.Pos) w.pos(n.Pos)
w.typ(n.Type) w.typ(n.Type)
switch { switch {
default: default:
// empty list // empty list
w.op(OEND) w.op(ir.OEND)
case n.List.Len() != 0: // pre-typecheck case n.List.Len() != 0: // pre-typecheck
w.exprList(n.List) // emits terminating OEND w.exprList(n.List) // emits terminating OEND
case n.Right != nil: case n.Right != nil:
w.expr(n.Left) w.expr(n.Left)
w.expr(n.Right) w.expr(n.Right)
w.op(OEND) w.op(ir.OEND)
case n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()): case n.Left != nil && (n.Op == ir.OMAKESLICE || !n.Left.Type.IsUntyped()):
w.expr(n.Left) w.expr(n.Left)
w.op(OEND) w.op(ir.OEND)
} }
// unary expressions // 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.op(op)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
// binary expressions // binary expressions
case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT, case ir.OADD, ir.OAND, ir.OANDAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR: ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR:
w.op(op) w.op(op)
w.pos(n.Pos) w.pos(n.Pos)
w.expr(n.Left) w.expr(n.Left)
w.expr(n.Right) w.expr(n.Right)
case OADDSTR: case ir.OADDSTR:
w.op(OADDSTR) w.op(ir.OADDSTR)
w.pos(n.Pos) w.pos(n.Pos)
w.exprList(n.List) w.exprList(n.List)
case ODCLCONST: case ir.ODCLCONST:
// if exporting, DCLCONST should just be removed as its usage // if exporting, DCLCONST should just be removed as its usage
// has already been replaced with literals // has already been replaced with literals
@ -1425,11 +1426,11 @@ func (w *exportWriter) expr(n *Node) {
} }
} }
func (w *exportWriter) op(op Op) { func (w *exportWriter) op(op ir.Op) {
w.uint64(uint64(op)) w.uint64(uint64(op))
} }
func (w *exportWriter) exprsOrNil(a, b *Node) { func (w *exportWriter) exprsOrNil(a, b *ir.Node) {
ab := 0 ab := 0
if a != nil { if a != nil {
ab |= 1 ab |= 1
@ -1446,7 +1447,7 @@ func (w *exportWriter) exprsOrNil(a, b *Node) {
} }
} }
func (w *exportWriter) elemList(list Nodes) { func (w *exportWriter) elemList(list ir.Nodes) {
w.uint64(uint64(list.Len())) w.uint64(uint64(list.Len()))
for _, n := range list.Slice() { for _, n := range list.Slice() {
w.selector(n.Sym) w.selector(n.Sym)
@ -1454,7 +1455,7 @@ func (w *exportWriter) elemList(list Nodes) {
} }
} }
func (w *exportWriter) localName(n *Node) { func (w *exportWriter) localName(n *ir.Node) {
// Escape analysis happens after inline bodies are saved, but // Escape analysis happens after inline bodies are saved, but
// we're using the same ONAME nodes, so we might still see // we're using the same ONAME nodes, so we might still see
// PAUTOHEAP here. // PAUTOHEAP here.
@ -1463,7 +1464,7 @@ func (w *exportWriter) localName(n *Node) {
// PPARAM/PPARAMOUT, because we only want to include vargen in // PPARAM/PPARAMOUT, because we only want to include vargen in
// non-param names. // non-param names.
var v int32 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 v = n.Name.Vargen
} }

View file

@ -9,6 +9,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/goobj" "cmd/internal/goobj"
@ -40,8 +41,8 @@ var (
inlineImporter = map[*types.Sym]iimporterAndOffset{} inlineImporter = map[*types.Sym]iimporterAndOffset{}
) )
func expandDecl(n *Node) { func expandDecl(n *ir.Node) {
if n.Op != ONONAME { if n.Op != ir.ONONAME {
return return
} }
@ -54,7 +55,7 @@ func expandDecl(n *Node) {
r.doDecl(n) r.doDecl(n)
} }
func expandInline(fn *Node) { func expandInline(fn *ir.Node) {
if fn.Func.Inl.Body != nil { if fn.Func.Inl.Body != nil {
return return
} }
@ -67,7 +68,7 @@ func expandInline(fn *Node) {
r.doInline(fn) 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] x, ok := importers[n.Sym]
if !ok { if !ok {
return nil return nil
@ -147,10 +148,10 @@ func iimport(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType)
if pkg.Name == "" { if pkg.Name == "" {
pkg.Name = pkgName pkg.Name = pkgName
pkg.Height = pkgHeight pkg.Height = pkgHeight
numImport[pkgName]++ ir.NumImport[pkgName]++
// TODO(mdempsky): This belongs somewhere else. // TODO(mdempsky): This belongs somewhere else.
pkg.Lookup("_").Def = asTypesNode(nblank) pkg.Lookup("_").Def = ir.AsTypesNode(ir.BlankNode)
} else { } else {
if pkg.Name != pkgName { if pkg.Name != pkgName {
base.Fatalf("conflicting package names %v and %v for path %q", pkg.Name, pkgName, pkg.Path) base.Fatalf("conflicting package names %v and %v for path %q", pkg.Name, pkgName, pkg.Path)
@ -172,9 +173,9 @@ func iimport(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType)
// Create stub declaration. If used, this will // Create stub declaration. If used, this will
// be overwritten by expandDecl. // be overwritten by expandDecl.
if s.Def != nil { 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)))
} }
} }
@ -280,8 +281,8 @@ func (r *importReader) setPkg() {
r.currPkg = r.pkg() r.currPkg = r.pkg()
} }
func (r *importReader) doDecl(n *Node) { func (r *importReader) doDecl(n *ir.Node) {
if n.Op != ONONAME { if n.Op != ir.ONONAME {
base.Fatalf("doDecl: unexpected Op for %v: %v", n.Sym, n.Op) base.Fatalf("doDecl: unexpected Op for %v: %v", n.Sym, n.Op)
} }
@ -330,13 +331,13 @@ func (r *importReader) doDecl(n *Node) {
recv := r.param() recv := r.param()
mtyp := r.signature(recv) 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.Type = mtyp
m.SetClass(PFUNC) m.SetClass(ir.PFUNC)
// methodSym already marked m.Sym as a function. // methodSym already marked m.Sym as a function.
f := types.NewField(mpos, msym, mtyp) f := types.NewField(mpos, msym, mtyp)
f.Nname = asTypesNode(m) f.Nname = ir.AsTypesNode(m)
ms[i] = f ms[i] = f
} }
t.Methods().Set(ms) t.Methods().Set(ms)
@ -434,7 +435,7 @@ func (r *importReader) ident() *types.Sym {
} }
pkg := r.currPkg pkg := r.currPkg
if types.IsExported(name) { if types.IsExported(name) {
pkg = localpkg pkg = ir.LocalPkg
} }
return pkg.Lookup(name) return pkg.Lookup(name)
} }
@ -498,11 +499,11 @@ func (r *importReader) typ1() *types.Type {
// support inlining functions with local defined // support inlining functions with local defined
// types. Therefore, this must be a package-scope // types. Therefore, this must be a package-scope
// type. // type.
n := asNode(r.qualifiedIdent().PkgDef()) n := ir.AsNode(r.qualifiedIdent().PkgDef())
if n.Op == ONONAME { if n.Op == ir.ONONAME {
expandDecl(n) expandDecl(n)
} }
if n.Op != OTYPE { if n.Op != ir.OTYPE {
base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op, n.Sym, n) base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op, n.Sym, n)
} }
return n.Type return n.Type
@ -542,7 +543,7 @@ func (r *importReader) typ1() *types.Type {
fs[i] = f fs[i] = f
} }
t := types.New(TSTRUCT) t := types.New(types.TSTRUCT)
t.SetPkg(r.currPkg) t.SetPkg(r.currPkg)
t.SetFields(fs) t.SetFields(fs)
return t return t
@ -567,7 +568,7 @@ func (r *importReader) typ1() *types.Type {
methods[i] = types.NewField(pos, sym, typ) methods[i] = types.NewField(pos, sym, typ)
} }
t := types.New(TINTER) t := types.New(types.TINTER)
t.SetPkg(r.currPkg) t.SetPkg(r.currPkg)
t.SetInterface(append(embeddeds, methods...)) t.SetInterface(append(embeddeds, methods...))
@ -634,12 +635,12 @@ func (r *importReader) byte() byte {
// Compiler-specific extensions. // Compiler-specific extensions.
func (r *importReader) varExt(n *Node) { func (r *importReader) varExt(n *ir.Node) {
r.linkname(n.Sym) r.linkname(n.Sym)
r.symIdx(n.Sym) r.symIdx(n.Sym)
} }
func (r *importReader) funcExt(n *Node) { func (r *importReader) funcExt(n *ir.Node) {
r.linkname(n.Sym) r.linkname(n.Sym)
r.symIdx(n.Sym) r.symIdx(n.Sym)
@ -652,7 +653,7 @@ func (r *importReader) funcExt(n *Node) {
// Inline body. // Inline body.
if u := r.uint64(); u > 0 { if u := r.uint64(); u > 0 {
n.Func.Inl = &Inline{ n.Func.Inl = &ir.Inline{
Cost: int32(u - 1), Cost: int32(u - 1),
} }
n.Func.Endlineno = r.pos() n.Func.Endlineno = r.pos()
@ -663,7 +664,7 @@ func (r *importReader) methExt(m *types.Field) {
if r.bool() { if r.bool() {
m.SetNointerface(true) m.SetNointerface(true)
} }
r.funcExt(asNode(m.Nname)) r.funcExt(ir.AsNode(m.Nname))
} }
func (r *importReader) linkname(s *types.Sym) { func (r *importReader) linkname(s *types.Sym) {
@ -694,7 +695,7 @@ func (r *importReader) typeExt(t *types.Type) {
// so we can use index to reference the symbol. // so we can use index to reference the symbol.
var typeSymIdx = make(map[*types.Type][2]int64) 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 { if len(n.Func.Inl.Body) != 0 {
base.Fatalf("%v already has inline body", n) base.Fatalf("%v already has inline body", n)
} }
@ -709,7 +710,7 @@ func (r *importReader) doInline(n *Node) {
// (not doing so can cause significant performance // (not doing so can cause significant performance
// degradation due to unnecessary calls to empty // degradation due to unnecessary calls to empty
// functions). // functions).
body = []*Node{} body = []*ir.Node{}
} }
n.Func.Inl.Body = body n.Func.Inl.Body = body
@ -717,9 +718,9 @@ func (r *importReader) doInline(n *Node) {
if base.Flag.E > 0 && base.Flag.LowerM > 2 { if base.Flag.E > 0 && base.Flag.LowerM > 2 {
if base.Flag.LowerM > 3 { 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 { } 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))
} }
} }
} }
@ -739,15 +740,15 @@ func (r *importReader) doInline(n *Node) {
// unrefined nodes (since this is what the importer uses). The respective case // unrefined nodes (since this is what the importer uses). The respective case
// entries are unreachable in the importer. // entries are unreachable in the importer.
func (r *importReader) stmtList() []*Node { func (r *importReader) stmtList() []*ir.Node {
var list []*Node var list []*ir.Node
for { for {
n := r.node() n := r.node()
if n == nil { if n == nil {
break break
} }
// OBLOCK nodes may be created when importing ODCL nodes - unpack them // 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()...) list = append(list, n.List.Slice()...)
} else { } else {
list = append(list, n) list = append(list, n)
@ -757,18 +758,18 @@ func (r *importReader) stmtList() []*Node {
return list return list
} }
func (r *importReader) caseList(sw *Node) []*Node { func (r *importReader) caseList(sw *ir.Node) []*ir.Node {
namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil 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 { 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()) cas.List.Set(r.stmtList())
if namedTypeSwitch { if namedTypeSwitch {
// Note: per-case variables will have distinct, dotted // Note: per-case variables will have distinct, dotted
// names after import. That's okay: swt.go only needs // names after import. That's okay: swt.go only needs
// Sym for diagnostics anyway. // Sym for diagnostics anyway.
caseVar := newnamel(cas.Pos, r.ident()) caseVar := ir.NewNameAt(cas.Pos, r.ident())
declare(caseVar, dclcontext) declare(caseVar, dclcontext)
cas.Rlist.Set1(caseVar) cas.Rlist.Set1(caseVar)
caseVar.Name.Defn = sw.Left caseVar.Name.Defn = sw.Left
@ -779,8 +780,8 @@ func (r *importReader) caseList(sw *Node) []*Node {
return cases return cases
} }
func (r *importReader) exprList() []*Node { func (r *importReader) exprList() []*ir.Node {
var list []*Node var list []*ir.Node
for { for {
n := r.expr() n := r.expr()
if n == nil { if n == nil {
@ -791,16 +792,16 @@ func (r *importReader) exprList() []*Node {
return list return list
} }
func (r *importReader) expr() *Node { func (r *importReader) expr() *ir.Node {
n := r.node() n := r.node()
if n != nil && n.Op == OBLOCK { if n != nil && n.Op == ir.OBLOCK {
base.Fatalf("unexpected block node: %v", n) base.Fatalf("unexpected block node: %v", n)
} }
return n return n
} }
// TODO(gri) split into expr and stmt // TODO(gri) split into expr and stmt
func (r *importReader) node() *Node { func (r *importReader) node() *ir.Node {
switch op := r.op(); op { switch op := r.op(); op {
// expressions // expressions
// case OPAREN: // case OPAREN:
@ -809,34 +810,34 @@ func (r *importReader) node() *Node {
// case ONIL: // case ONIL:
// unreachable - mapped to OLITERAL // unreachable - mapped to OLITERAL
case OLITERAL: case ir.OLITERAL:
pos := r.pos() pos := r.pos()
typ := r.typ() typ := r.typ()
var n *Node var n *ir.Node
if typ.HasNil() { if typ.HasNil() {
n = nodnil() n = nodnil()
} else { } else {
n = nodlit(r.value(typ)) n = ir.NewLiteral(r.value(typ))
} }
n = npos(pos, n) n = npos(pos, n)
n.Type = typ n.Type = typ
return n return n
case ONONAME: case ir.ONONAME:
return mkname(r.qualifiedIdent()) return mkname(r.qualifiedIdent())
case ONAME: case ir.ONAME:
return mkname(r.ident()) return mkname(r.ident())
// case OPACK, ONONAME: // case OPACK, ONONAME:
// unreachable - should have been resolved by typechecking // unreachable - should have been resolved by typechecking
case OTYPE: case ir.OTYPE:
return typenod(r.typ()) return typenod(r.typ())
case OTYPESW: case ir.OTYPESW:
n := nodl(r.pos(), OTYPESW, nil, nil) n := ir.NodAt(r.pos(), ir.OTYPESW, nil, nil)
if s := r.ident(); s != nil { if s := r.ident(); s != nil {
n.Left = npos(n.Pos, newnoname(s)) n.Left = npos(n.Pos, newnoname(s))
} }
@ -853,11 +854,11 @@ func (r *importReader) node() *Node {
// case OPTRLIT: // case OPTRLIT:
// unreachable - mapped to case OADDR below by exporter // unreachable - mapped to case OADDR below by exporter
case OSTRUCTLIT: case ir.OSTRUCTLIT:
// TODO(mdempsky): Export position information for OSTRUCTKEY nodes. // TODO(mdempsky): Export position information for OSTRUCTKEY nodes.
savedlineno := base.Pos savedlineno := base.Pos
base.Pos = r.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 n.List.Set(r.elemList()) // special handling of field names
base.Pos = savedlineno base.Pos = savedlineno
return n return n
@ -865,15 +866,15 @@ func (r *importReader) node() *Node {
// case OARRAYLIT, OSLICELIT, OMAPLIT: // case OARRAYLIT, OSLICELIT, OMAPLIT:
// unreachable - mapped to case OCOMPLIT below by exporter // unreachable - mapped to case OCOMPLIT below by exporter
case OCOMPLIT: case ir.OCOMPLIT:
n := nodl(r.pos(), OCOMPLIT, nil, typenod(r.typ())) n := ir.NodAt(r.pos(), ir.OCOMPLIT, nil, typenod(r.typ()))
n.List.Set(r.exprList()) n.List.Set(r.exprList())
return n return n
case OKEY: case ir.OKEY:
pos := r.pos() pos := r.pos()
left, right := r.exprsOrNil() left, right := r.exprsOrNil()
return nodl(pos, OKEY, left, right) return ir.NodAt(pos, ir.OKEY, left, right)
// case OSTRUCTKEY: // case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList // unreachable - handled in case OSTRUCTLIT by elemList
@ -884,28 +885,28 @@ func (r *importReader) node() *Node {
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: // case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
// unreachable - mapped to case OXDOT below by exporter // unreachable - mapped to case OXDOT below by exporter
case OXDOT: case ir.OXDOT:
// see parser.new_dotname // 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: // case ODOTTYPE, ODOTTYPE2:
// unreachable - mapped to case ODOTTYPE below by exporter // unreachable - mapped to case ODOTTYPE below by exporter
case ODOTTYPE: case ir.ODOTTYPE:
n := nodl(r.pos(), ODOTTYPE, r.expr(), nil) n := ir.NodAt(r.pos(), ir.ODOTTYPE, r.expr(), nil)
n.Type = r.typ() n.Type = r.typ()
return n return n
// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: // case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
// unreachable - mapped to cases below by exporter // unreachable - mapped to cases below by exporter
case OINDEX: case ir.OINDEX:
return nodl(r.pos(), op, r.expr(), r.expr()) return ir.NodAt(r.pos(), op, r.expr(), r.expr())
case OSLICE, OSLICE3: case ir.OSLICE, ir.OSLICE3:
n := nodl(r.pos(), op, r.expr(), nil) n := ir.NodAt(r.pos(), op, r.expr(), nil)
low, high := r.exprsOrNil() low, high := r.exprsOrNil()
var max *Node var max *ir.Node
if n.Op.IsSlice3() { if n.Op.IsSlice3() {
max = r.expr() max = r.expr()
} }
@ -915,15 +916,15 @@ func (r *importReader) node() *Node {
// case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR: // case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
// unreachable - mapped to OCONV case below by exporter // unreachable - mapped to OCONV case below by exporter
case OCONV: case ir.OCONV:
n := nodl(r.pos(), OCONV, r.expr(), nil) n := ir.NodAt(r.pos(), ir.OCONV, r.expr(), nil)
n.Type = r.typ() n.Type = r.typ()
return n 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 := npos(r.pos(), builtinCall(op))
n.List.Set(r.exprList()) n.List.Set(r.exprList())
if op == OAPPEND { if op == ir.OAPPEND {
n.SetIsDDD(r.bool()) n.SetIsDDD(r.bool())
} }
return n return n
@ -931,45 +932,45 @@ func (r *importReader) node() *Node {
// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: // case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
// unreachable - mapped to OCALL case below by exporter // unreachable - mapped to OCALL case below by exporter
case OCALL: case ir.OCALL:
n := nodl(r.pos(), OCALL, nil, nil) n := ir.NodAt(r.pos(), ir.OCALL, nil, nil)
n.Ninit.Set(r.stmtList()) n.Ninit.Set(r.stmtList())
n.Left = r.expr() n.Left = r.expr()
n.List.Set(r.exprList()) n.List.Set(r.exprList())
n.SetIsDDD(r.bool()) n.SetIsDDD(r.bool())
return n return n
case OMAKEMAP, OMAKECHAN, OMAKESLICE: case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
n := npos(r.pos(), builtinCall(OMAKE)) n := npos(r.pos(), builtinCall(ir.OMAKE))
n.List.Append(typenod(r.typ())) n.List.Append(typenod(r.typ()))
n.List.Append(r.exprList()...) n.List.Append(r.exprList()...)
return n return n
// unary expressions // 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:
return nodl(r.pos(), op, r.expr(), nil) return ir.NodAt(r.pos(), op, r.expr(), nil)
// binary expressions // binary expressions
case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT, case ir.OADD, ir.OAND, ir.OANDAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR: ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR:
return nodl(r.pos(), op, r.expr(), r.expr()) return ir.NodAt(r.pos(), op, r.expr(), r.expr())
case OADDSTR: case ir.OADDSTR:
pos := r.pos() pos := r.pos()
list := r.exprList() list := r.exprList()
x := npos(pos, list[0]) x := npos(pos, list[0])
for _, y := range list[1:] { for _, y := range list[1:] {
x = nodl(pos, OADD, x, y) x = ir.NodAt(pos, ir.OADD, x, y)
} }
return x return x
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// statements // statements
case ODCL: case ir.ODCL:
pos := r.pos() pos := r.pos()
lhs := npos(pos, dclname(r.ident())) lhs := npos(pos, dclname(r.ident()))
typ := typenod(r.typ()) 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: // case ODCLFIELD:
// unimplemented // unimplemented
@ -977,11 +978,11 @@ func (r *importReader) node() *Node {
// case OAS, OASWB: // case OAS, OASWB:
// unreachable - mapped to OAS case below by exporter // unreachable - mapped to OAS case below by exporter
case OAS: case ir.OAS:
return nodl(r.pos(), OAS, r.expr(), r.expr()) return ir.NodAt(r.pos(), ir.OAS, r.expr(), r.expr())
case OASOP: case ir.OASOP:
n := nodl(r.pos(), OASOP, nil, nil) n := ir.NodAt(r.pos(), ir.OASOP, nil, nil)
n.SetSubOp(r.op()) n.SetSubOp(r.op())
n.Left = r.expr() n.Left = r.expr()
if !r.bool() { if !r.bool() {
@ -995,33 +996,33 @@ func (r *importReader) node() *Node {
// case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: // case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
// unreachable - mapped to OAS2 case below by exporter // unreachable - mapped to OAS2 case below by exporter
case OAS2: case ir.OAS2:
n := nodl(r.pos(), OAS2, nil, nil) n := ir.NodAt(r.pos(), ir.OAS2, nil, nil)
n.List.Set(r.exprList()) n.List.Set(r.exprList())
n.Rlist.Set(r.exprList()) n.Rlist.Set(r.exprList())
return n return n
case ORETURN: case ir.ORETURN:
n := nodl(r.pos(), ORETURN, nil, nil) n := ir.NodAt(r.pos(), ir.ORETURN, nil, nil)
n.List.Set(r.exprList()) n.List.Set(r.exprList())
return n return n
// case ORETJMP: // case ORETJMP:
// unreachable - generated by compiler for trampolin routines (not exported) // unreachable - generated by compiler for trampolin routines (not exported)
case OGO, ODEFER: case ir.OGO, ir.ODEFER:
return nodl(r.pos(), op, r.expr(), nil) return ir.NodAt(r.pos(), op, r.expr(), nil)
case OIF: case ir.OIF:
n := nodl(r.pos(), OIF, nil, nil) n := ir.NodAt(r.pos(), ir.OIF, nil, nil)
n.Ninit.Set(r.stmtList()) n.Ninit.Set(r.stmtList())
n.Left = r.expr() n.Left = r.expr()
n.Nbody.Set(r.stmtList()) n.Nbody.Set(r.stmtList())
n.Rlist.Set(r.stmtList()) n.Rlist.Set(r.stmtList())
return n return n
case OFOR: case ir.OFOR:
n := nodl(r.pos(), OFOR, nil, nil) n := ir.NodAt(r.pos(), ir.OFOR, nil, nil)
n.Ninit.Set(r.stmtList()) n.Ninit.Set(r.stmtList())
left, right := r.exprsOrNil() left, right := r.exprsOrNil()
n.Left = left n.Left = left
@ -1029,15 +1030,15 @@ func (r *importReader) node() *Node {
n.Nbody.Set(r.stmtList()) n.Nbody.Set(r.stmtList())
return n return n
case ORANGE: case ir.ORANGE:
n := nodl(r.pos(), ORANGE, nil, nil) n := ir.NodAt(r.pos(), ir.ORANGE, nil, nil)
n.List.Set(r.stmtList()) n.List.Set(r.stmtList())
n.Right = r.expr() n.Right = r.expr()
n.Nbody.Set(r.stmtList()) n.Nbody.Set(r.stmtList())
return n return n
case OSELECT, OSWITCH: case ir.OSELECT, ir.OSWITCH:
n := nodl(r.pos(), op, nil, nil) n := ir.NodAt(r.pos(), op, nil, nil)
n.Ninit.Set(r.stmtList()) n.Ninit.Set(r.stmtList())
left, _ := r.exprsOrNil() left, _ := r.exprsOrNil()
n.Left = left n.Left = left
@ -1047,27 +1048,27 @@ func (r *importReader) node() *Node {
// case OCASE: // case OCASE:
// handled by caseList // handled by caseList
case OFALL: case ir.OFALL:
n := nodl(r.pos(), OFALL, nil, nil) n := ir.NodAt(r.pos(), ir.OFALL, nil, nil)
return n return n
case OBREAK, OCONTINUE: case ir.OBREAK, ir.OCONTINUE:
pos := r.pos() pos := r.pos()
left, _ := r.exprsOrNil() left, _ := r.exprsOrNil()
if left != nil { 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: // case OEMPTY:
// unreachable - not emitted by exporter // unreachable - not emitted by exporter
case OGOTO, OLABEL: case ir.OGOTO, ir.OLABEL:
n := nodl(r.pos(), op, nil, nil) n := ir.NodAt(r.pos(), op, nil, nil)
n.Sym = lookup(r.string()) n.Sym = lookup(r.string())
return n return n
case OEND: case ir.OEND:
return nil return nil
default: default:
@ -1077,21 +1078,21 @@ func (r *importReader) node() *Node {
} }
} }
func (r *importReader) op() Op { func (r *importReader) op() ir.Op {
return Op(r.uint64()) return ir.Op(r.uint64())
} }
func (r *importReader) elemList() []*Node { func (r *importReader) elemList() []*ir.Node {
c := r.uint64() c := r.uint64()
list := make([]*Node, c) list := make([]*ir.Node, c)
for i := range list { for i := range list {
s := r.ident() s := r.ident()
list[i] = nodSym(OSTRUCTKEY, r.expr(), s) list[i] = nodSym(ir.OSTRUCTKEY, r.expr(), s)
} }
return list return list
} }
func (r *importReader) exprsOrNil() (a, b *Node) { func (r *importReader) exprsOrNil() (a, b *ir.Node) {
ab := r.uint64() ab := r.uint64()
if ab&1 != 0 { if ab&1 != 0 {
a = r.expr() a = r.expr()

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
) )
@ -18,7 +19,7 @@ var renameinitgen int
// Function collecting autotmps generated during typechecking, // Function collecting autotmps generated during typechecking,
// to be included in the package-level init function. // 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 { func renameinit() *types.Sym {
s := lookupN("init.", renameinitgen) s := lookupN("init.", renameinitgen)
@ -32,7 +33,7 @@ func renameinit() *types.Sym {
// 1) Initialize all of the packages the current package depends on. // 1) Initialize all of the packages the current package depends on.
// 2) Initialize all the variables that have initializers. // 2) Initialize all the variables that have initializers.
// 3) Run any init functions. // 3) Run any init functions.
func fninit(n []*Node) { func fninit(n []*ir.Node) {
nf := initOrder(n) nf := initOrder(n)
var deps []*obj.LSym // initTask records for packages the current package depends on var deps []*obj.LSym // initTask records for packages the current package depends on
@ -47,7 +48,7 @@ func fninit(n []*Node) {
if len(nf) > 0 { if len(nf) > 0 {
base.Pos = nf[0].Pos // prolog/epilog gets line number of first init stmt base.Pos = nf[0].Pos // prolog/epilog gets line number of first init stmt
initializers := lookup("init") 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 { for _, dcl := range initTodo.Func.Dcl {
dcl.Name.Curfn = fn dcl.Name.Curfn = fn
} }
@ -75,24 +76,24 @@ func fninit(n []*Node) {
// Record user init functions. // Record user init functions.
for i := 0; i < renameinitgen; i++ { for i := 0; i < renameinitgen; i++ {
s := lookupN("init.", i) s := lookupN("init.", i)
fn := asNode(s.Def).Name.Defn fn := ir.AsNode(s.Def).Name.Defn
// Skip init functions with empty bodies. // 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 continue
} }
fns = append(fns, s.Linksym()) 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 return // nothing to initialize
} }
// Make an .inittask structure. // Make an .inittask structure.
sym := lookup(".inittask") sym := lookup(".inittask")
nn := newname(sym) nn := NewName(sym)
nn.Type = types.Types[TUINT8] // fake type nn.Type = types.Types[types.TUINT8] // fake type
nn.SetClass(PEXTERN) nn.SetClass(ir.PEXTERN)
sym.Def = asTypesNode(nn) sym.Def = ir.AsTypesNode(nn)
exportsym(nn) exportsym(nn)
lsym := sym.Linksym() lsym := sym.Linksym()
ot := 0 ot := 0

View file

@ -10,6 +10,8 @@ import (
"fmt" "fmt"
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
) )
// Package initialization // Package initialization
@ -62,7 +64,7 @@ const (
type InitOrder struct { type InitOrder struct {
// blocking maps initialization assignments to the assignments // blocking maps initialization assignments to the assignments
// that depend on it. // that depend on it.
blocking map[*Node][]*Node blocking map[*ir.Node][]*ir.Node
// ready is the queue of Pending initialization assignments // ready is the queue of Pending initialization assignments
// that are ready for initialization. // that are ready for initialization.
@ -73,22 +75,22 @@ type InitOrder struct {
// package-level declarations (in declaration order) and outputs the // package-level declarations (in declaration order) and outputs the
// corresponding list of statements to include in the init() function // corresponding list of statements to include in the init() function
// body. // body.
func initOrder(l []*Node) []*Node { func initOrder(l []*ir.Node) []*ir.Node {
s := InitSchedule{ s := InitSchedule{
initplans: make(map[*Node]*InitPlan), initplans: make(map[*ir.Node]*InitPlan),
inittemps: make(map[*Node]*Node), inittemps: make(map[*ir.Node]*ir.Node),
} }
o := InitOrder{ o := InitOrder{
blocking: make(map[*Node][]*Node), blocking: make(map[*ir.Node][]*ir.Node),
} }
// Process all package-level assignment in declaration order. // Process all package-level assignment in declaration order.
for _, n := range l { for _, n := range l {
switch n.Op { switch n.Op {
case OAS, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: case ir.OAS, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
o.processAssign(n) o.processAssign(n)
o.flushReady(s.staticInit) o.flushReady(s.staticInit)
case ODCLCONST, ODCLFUNC, ODCLTYPE: case ir.ODCLCONST, ir.ODCLFUNC, ir.ODCLTYPE:
// nop // nop
default: default:
base.Fatalf("unexpected package-level statement: %v", n) base.Fatalf("unexpected package-level statement: %v", n)
@ -99,7 +101,7 @@ func initOrder(l []*Node) []*Node {
// have been a dependency cycle. // have been a dependency cycle.
for _, n := range l { for _, n := range l {
switch n.Op { 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 n.Initorder() != InitDone {
// If there have already been errors // If there have already been errors
// printed, those errors may have // printed, those errors may have
@ -108,7 +110,7 @@ func initOrder(l []*Node) []*Node {
// first. // first.
base.ExitIfErrors() base.ExitIfErrors()
findInitLoopAndExit(firstLHS(n), new([]*Node)) findInitLoopAndExit(firstLHS(n), new([]*ir.Node))
base.Fatalf("initialization unfinished, but failed to identify loop") base.Fatalf("initialization unfinished, but failed to identify loop")
} }
} }
@ -123,8 +125,8 @@ func initOrder(l []*Node) []*Node {
return s.out return s.out
} }
func (o *InitOrder) processAssign(n *Node) { func (o *InitOrder) processAssign(n *ir.Node) {
if n.Initorder() != InitNotStarted || n.Xoffset != BADWIDTH { if n.Initorder() != InitNotStarted || n.Xoffset != types.BADWIDTH {
base.Fatalf("unexpected state: %v, %v, %v", n, n.Initorder(), n.Xoffset) base.Fatalf("unexpected state: %v, %v, %v", n, n.Initorder(), n.Xoffset)
} }
@ -137,7 +139,7 @@ func (o *InitOrder) processAssign(n *Node) {
defn := dep.Name.Defn defn := dep.Name.Defn
// Skip dependencies on functions (PFUNC) and // Skip dependencies on functions (PFUNC) and
// variables already initialized (InitDone). // variables already initialized (InitDone).
if dep.Class() != PEXTERN || defn.Initorder() == InitDone { if dep.Class() != ir.PEXTERN || defn.Initorder() == InitDone {
continue continue
} }
n.Xoffset++ n.Xoffset++
@ -152,16 +154,16 @@ func (o *InitOrder) processAssign(n *Node) {
// flushReady repeatedly applies initialize to the earliest (in // flushReady repeatedly applies initialize to the earliest (in
// declaration order) assignment ready for initialization and updates // declaration order) assignment ready for initialization and updates
// the inverse dependency ("blocking") graph. // 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 { 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 { if n.Initorder() != InitPending || n.Xoffset != 0 {
base.Fatalf("unexpected state: %v, %v, %v", n, n.Initorder(), n.Xoffset) base.Fatalf("unexpected state: %v, %v, %v", n, n.Initorder(), n.Xoffset)
} }
initialize(n) initialize(n)
n.SetInitorder(InitDone) n.SetInitorder(InitDone)
n.Xoffset = BADWIDTH n.Xoffset = types.BADWIDTH
blocked := o.blocking[n] blocked := o.blocking[n]
delete(o.blocking, n) delete(o.blocking, n)
@ -181,7 +183,7 @@ func (o *InitOrder) flushReady(initialize func(*Node)) {
// path points to a slice used for tracking the sequence of // path points to a slice used for tracking the sequence of
// variables/functions visited. Using a pointer to a slice allows the // variables/functions visited. Using a pointer to a slice allows the
// slice capacity to grow and limit reallocations. // 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 // We implement a simple DFS loop-finding algorithm. This
// could be faster, but initialization cycles are rare. // could be faster, but initialization cycles are rare.
@ -194,14 +196,14 @@ func findInitLoopAndExit(n *Node, path *[]*Node) {
// There might be multiple loops involving n; by sorting // There might be multiple loops involving n; by sorting
// references, we deterministically pick the one reported. // 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) return ni.Pos.Before(nj.Pos)
}) })
*path = append(*path, n) *path = append(*path, n)
for _, ref := range refers { for _, ref := range refers {
// Short-circuit variables that were initialized. // 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 continue
} }
@ -213,12 +215,12 @@ func findInitLoopAndExit(n *Node, path *[]*Node) {
// reportInitLoopAndExit reports and initialization loop as an error // reportInitLoopAndExit reports and initialization loop as an error
// and exits. However, if l is not actually an initialization loop, it // and exits. However, if l is not actually an initialization loop, it
// simply returns instead. // simply returns instead.
func reportInitLoopAndExit(l []*Node) { func reportInitLoopAndExit(l []*ir.Node) {
// Rotate loop so that the earliest variable declaration is at // Rotate loop so that the earliest variable declaration is at
// the start. // the start.
i := -1 i := -1
for j, n := range l { 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 i = j
} }
} }
@ -236,9 +238,9 @@ func reportInitLoopAndExit(l []*Node) {
var msg bytes.Buffer var msg bytes.Buffer
fmt.Fprintf(&msg, "initialization loop:\n") fmt.Fprintf(&msg, "initialization loop:\n")
for _, n := range l { 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.ErrorfAt(l[0].Pos, msg.String())
base.ErrorExit() base.ErrorExit()
@ -248,14 +250,14 @@ func reportInitLoopAndExit(l []*Node) {
// variables that declaration n depends on. If transitive is true, // variables that declaration n depends on. If transitive is true,
// then it also includes the transitive dependencies of any depended // then it also includes the transitive dependencies of any depended
// upon functions (but not variables). // 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} d := initDeps{transitive: transitive}
switch n.Op { switch n.Op {
case OAS: case ir.OAS:
d.inspect(n.Right) d.inspect(n.Right)
case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
d.inspect(n.Right) d.inspect(n.Right)
case ODCLFUNC: case ir.ODCLFUNC:
d.inspectList(n.Nbody) d.inspectList(n.Nbody)
default: default:
base.Fatalf("unexpected Op: %v", n.Op) base.Fatalf("unexpected Op: %v", n.Op)
@ -265,31 +267,31 @@ func collectDeps(n *Node, transitive bool) NodeSet {
type initDeps struct { type initDeps struct {
transitive bool transitive bool
seen NodeSet seen ir.NodeSet
} }
func (d *initDeps) inspect(n *Node) { inspect(n, d.visit) } func (d *initDeps) inspect(n *ir.Node) { ir.Inspect(n, d.visit) }
func (d *initDeps) inspectList(l Nodes) { inspectList(l, d.visit) } func (d *initDeps) inspectList(l ir.Nodes) { ir.InspectList(l, d.visit) }
// visit calls foundDep on any package-level functions or variables // visit calls foundDep on any package-level functions or variables
// referenced by n, if any. // referenced by n, if any.
func (d *initDeps) visit(n *Node) bool { func (d *initDeps) visit(n *ir.Node) bool {
switch n.Op { switch n.Op {
case OMETHEXPR: case ir.OMETHEXPR:
d.foundDep(n.MethodName()) d.foundDep(methodExprName(n))
return false return false
case ONAME: case ir.ONAME:
switch n.Class() { switch n.Class() {
case PEXTERN, PFUNC: case ir.PEXTERN, ir.PFUNC:
d.foundDep(n) d.foundDep(n)
} }
case OCLOSURE: case ir.OCLOSURE:
d.inspectList(n.Func.Decl.Nbody) d.inspectList(n.Func.Decl.Nbody)
case ODOTMETH, OCALLPART: case ir.ODOTMETH, ir.OCALLPART:
d.foundDep(n.MethodName()) d.foundDep(methodExprName(n))
} }
return true return true
@ -297,7 +299,7 @@ func (d *initDeps) visit(n *Node) bool {
// foundDep records that we've found a dependency on n by adding it to // foundDep records that we've found a dependency on n by adding it to
// seen. // seen.
func (d *initDeps) foundDep(n *Node) { func (d *initDeps) foundDep(n *ir.Node) {
// Can happen with method expressions involving interface // Can happen with method expressions involving interface
// types; e.g., fixedbugs/issue4495.go. // types; e.g., fixedbugs/issue4495.go.
if n == nil { if n == nil {
@ -314,7 +316,7 @@ func (d *initDeps) foundDep(n *Node) {
return return
} }
d.seen.Add(n) d.seen.Add(n)
if d.transitive && n.Class() == PFUNC { if d.transitive && n.Class() == ir.PFUNC {
d.inspectList(n.Name.Defn.Nbody) d.inspectList(n.Name.Defn.Nbody)
} }
} }
@ -326,13 +328,13 @@ func (d *initDeps) foundDep(n *Node) {
// an OAS node's Pos may not be unique. For example, given the // 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", // declaration "var a, b = f(), g()", "a" must be ordered before "b",
// but both OAS nodes use the "=" token's position as their Pos. // 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) 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) 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) 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{} { func (s *declOrder) Pop() interface{} {
n := (*s)[len(*s)-1] n := (*s)[len(*s)-1]
*s = (*s)[:len(*s)-1] *s = (*s)[:len(*s)-1]
@ -341,11 +343,11 @@ func (s *declOrder) Pop() interface{} {
// firstLHS returns the first expression on the left-hand side of // firstLHS returns the first expression on the left-hand side of
// assignment n. // assignment n.
func firstLHS(n *Node) *Node { func firstLHS(n *ir.Node) *ir.Node {
switch n.Op { switch n.Op {
case OAS: case ir.OAS:
return n.Left return n.Left
case OAS2DOTTYPE, OAS2FUNC, OAS2RECV, OAS2MAPR: case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2RECV, ir.OAS2MAPR:
return n.List.First() return n.List.First()
} }

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax" "cmd/compile/internal/syntax"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/src" "cmd/internal/src"
@ -25,78 +26,51 @@ func isQuoted(s string) bool {
return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
} }
type PragmaFlag int16
const ( const (
// Func pragmas. FuncPragmas = ir.Nointerface |
Nointerface PragmaFlag = 1 << iota ir.Noescape |
Noescape // func parameters don't escape ir.Norace |
Norace // func must not have race detector annotations ir.Nosplit |
Nosplit // func should not execute on separate stack ir.Noinline |
Noinline // func should not be inlined ir.NoCheckPtr |
NoCheckPtr // func should not be instrumented by checkptr ir.CgoUnsafeArgs |
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all ir.UintptrEscapes |
UintptrEscapes // pointers converted to uintptr escape ir.Systemstack |
ir.Nowritebarrier |
ir.Nowritebarrierrec |
ir.Yeswritebarrierrec
// Runtime-only func pragmas. TypePragmas = ir.NotInHeap
// 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 ( func pragmaFlag(verb string) ir.PragmaFlag {
FuncPragmas = Nointerface |
Noescape |
Norace |
Nosplit |
Noinline |
NoCheckPtr |
CgoUnsafeArgs |
UintptrEscapes |
Systemstack |
Nowritebarrier |
Nowritebarrierrec |
Yeswritebarrierrec
TypePragmas = NotInHeap
)
func pragmaFlag(verb string) PragmaFlag {
switch verb { switch verb {
case "go:build": case "go:build":
return GoBuildPragma return ir.GoBuildPragma
case "go:nointerface": case "go:nointerface":
if objabi.Fieldtrack_enabled != 0 { if objabi.Fieldtrack_enabled != 0 {
return Nointerface return ir.Nointerface
} }
case "go:noescape": case "go:noescape":
return Noescape return ir.Noescape
case "go:norace": case "go:norace":
return Norace return ir.Norace
case "go:nosplit": case "go:nosplit":
return Nosplit | NoCheckPtr // implies NoCheckPtr (see #34972) return ir.Nosplit | ir.NoCheckPtr // implies NoCheckPtr (see #34972)
case "go:noinline": case "go:noinline":
return Noinline return ir.Noinline
case "go:nocheckptr": case "go:nocheckptr":
return NoCheckPtr return ir.NoCheckPtr
case "go:systemstack": case "go:systemstack":
return Systemstack return ir.Systemstack
case "go:nowritebarrier": case "go:nowritebarrier":
return Nowritebarrier return ir.Nowritebarrier
case "go:nowritebarrierrec": case "go:nowritebarrierrec":
return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier return ir.Nowritebarrierrec | ir.Nowritebarrier // implies Nowritebarrier
case "go:yeswritebarrierrec": case "go:yeswritebarrierrec":
return Yeswritebarrierrec return ir.Yeswritebarrierrec
case "go:cgo_unsafe_args": case "go:cgo_unsafe_args":
return CgoUnsafeArgs | NoCheckPtr // implies NoCheckPtr (see #34968) return ir.CgoUnsafeArgs | ir.NoCheckPtr // implies NoCheckPtr (see #34968)
case "go:uintptrescapes": case "go:uintptrescapes":
// For the next function declared in the file // For the next function declared in the file
// any uintptr arguments may be pointer values // any uintptr arguments may be pointer values
@ -109,9 +83,9 @@ func pragmaFlag(verb string) PragmaFlag {
// call. The conversion to uintptr must appear // call. The conversion to uintptr must appear
// in the argument list. // in the argument list.
// Used in syscall/dll_windows.go. // Used in syscall/dll_windows.go.
return UintptrEscapes return ir.UintptrEscapes
case "go:notinheap": case "go:notinheap":
return NotInHeap return ir.NotInHeap
} }
return 0 return 0
} }

View file

@ -10,6 +10,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
@ -73,17 +74,17 @@ func Main(archInit func(*Arch)) {
// See bugs 31188 and 21945 (CLs 170638, 98075, 72371). // See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin
localpkg = types.NewPkg("", "") ir.LocalPkg = types.NewPkg("", "")
localpkg.Prefix = "\"\"" ir.LocalPkg.Prefix = "\"\""
// We won't know localpkg's height until after import // We won't know localpkg's height until after import
// processing. In the mean time, set to MaxPkgHeight to ensure // processing. In the mean time, set to MaxPkgHeight to ensure
// height comparisons at least work until then. // height comparisons at least work until then.
localpkg.Height = types.MaxPkgHeight ir.LocalPkg.Height = types.MaxPkgHeight
// pseudo-package, for scoping // pseudo-package, for scoping
builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin? ir.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin ir.BuiltinPkg.Prefix = "go.builtin" // not go%2ebuiltin
// pseudo-package, accessed by import "unsafe" // pseudo-package, accessed by import "unsafe"
unsafepkg = types.NewPkg("unsafe", "unsafe") unsafepkg = types.NewPkg("unsafe", "unsafe")
@ -209,29 +210,18 @@ func Main(archInit func(*Arch)) {
types.Widthptr = Widthptr types.Widthptr = Widthptr
types.Dowidth = dowidth types.Dowidth = dowidth
types.Fatalf = base.Fatalf types.Fatalf = base.Fatalf
types.Sconv = func(s *types.Sym, flag, mode int) string { ir.InstallTypeFormats()
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))
}
types.TypeLinkSym = func(t *types.Type) *obj.LSym { types.TypeLinkSym = func(t *types.Type) *obj.LSym {
return typenamesym(t).Linksym() return typenamesym(t).Linksym()
} }
types.FmtLeft = int(FmtLeft) types.FmtLeft = int(ir.FmtLeft)
types.FmtUnsigned = int(FmtUnsigned) types.FmtUnsigned = int(ir.FmtUnsigned)
types.FErr = int(FErr) types.FErr = int(ir.FErr)
types.Ctxt = base.Ctxt types.Ctxt = base.Ctxt
initUniverse() initUniverse()
dclcontext = PEXTERN dclcontext = ir.PEXTERN
autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0) autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
@ -263,7 +253,7 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "typecheck", "top1") timings.Start("fe", "typecheck", "top1")
for i := 0; i < len(xtop); i++ { for i := 0; i < len(xtop); i++ {
n := 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) xtop[i] = typecheck(n, ctxStmt)
} }
} }
@ -275,7 +265,7 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "typecheck", "top2") timings.Start("fe", "typecheck", "top2")
for i := 0; i < len(xtop); i++ { for i := 0; i < len(xtop); i++ {
n := 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) xtop[i] = typecheck(n, ctxStmt)
} }
} }
@ -286,7 +276,7 @@ func Main(archInit func(*Arch)) {
var fcount int64 var fcount int64
for i := 0; i < len(xtop); i++ { for i := 0; i < len(xtop); i++ {
n := xtop[i] n := xtop[i]
if n.Op == ODCLFUNC { if n.Op == ir.ODCLFUNC {
Curfn = n Curfn = n
decldepth = 1 decldepth = 1
errorsBefore := base.Errors() errorsBefore := base.Errors()
@ -316,7 +306,7 @@ func Main(archInit func(*Arch)) {
// because variables captured by value do not escape. // because variables captured by value do not escape.
timings.Start("fe", "capturevars") timings.Start("fe", "capturevars")
for _, n := range xtop { for _, n := range xtop {
if n.Op == ODCLFUNC && n.Func.OClosure != nil { if n.Op == ir.ODCLFUNC && n.Func.OClosure != nil {
Curfn = n Curfn = n
capturevars(n) capturevars(n)
} }
@ -340,7 +330,7 @@ func Main(archInit func(*Arch)) {
if base.Flag.LowerL != 0 { if base.Flag.LowerL != 0 {
// Find functions that can be inlined and clone them before walk expands them. // 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) numfns := numNonClosures(list)
for _, n := range list { for _, n := range list {
if !recursive || numfns > 1 { if !recursive || numfns > 1 {
@ -350,7 +340,7 @@ func Main(archInit func(*Arch)) {
caninl(n) caninl(n)
} else { } else {
if base.Flag.LowerM > 1 { 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) inlcalls(n)
@ -359,7 +349,7 @@ func Main(archInit func(*Arch)) {
} }
for _, n := range xtop { for _, n := range xtop {
if n.Op == ODCLFUNC { if n.Op == ir.ODCLFUNC {
devirtualize(n) devirtualize(n)
} }
} }
@ -389,7 +379,7 @@ func Main(archInit func(*Arch)) {
// before walk reaches a call of a closure. // before walk reaches a call of a closure.
timings.Start("fe", "xclosures") timings.Start("fe", "xclosures")
for _, n := range xtop { for _, n := range xtop {
if n.Op == ODCLFUNC && n.Func.OClosure != nil { if n.Op == ir.ODCLFUNC && n.Func.OClosure != nil {
Curfn = n Curfn = n
transformclosure(n) transformclosure(n)
} }
@ -412,7 +402,7 @@ func Main(archInit func(*Arch)) {
fcount = 0 fcount = 0
for i := 0; i < len(xtop); i++ { for i := 0; i < len(xtop); i++ {
n := xtop[i] n := xtop[i]
if n.Op == ODCLFUNC { if n.Op == ir.ODCLFUNC {
funccompile(n) funccompile(n)
fcount++ fcount++
} }
@ -440,7 +430,7 @@ func Main(archInit func(*Arch)) {
// Phase 9: Check external declarations. // Phase 9: Check external declarations.
timings.Start("be", "externaldcls") timings.Start("be", "externaldcls")
for i, n := range externdcl { for i, n := range externdcl {
if n.Op == ONAME { if n.Op == ir.ONAME {
externdcl[i] = typecheck(externdcl[i], ctxExpr) externdcl[i] = typecheck(externdcl[i], ctxExpr)
} }
} }
@ -491,7 +481,7 @@ func Main(archInit func(*Arch)) {
} }
// numNonClosures returns the number of functions in list which are not closures. // 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 count := 0
for _, n := range list { for _, n := range list {
if n.Func.OClosure == nil { if n.Func.OClosure == nil {
@ -934,14 +924,14 @@ func pkgnotused(lineno src.XPos, path string, name string) {
} }
func mkpackage(pkgname string) { func mkpackage(pkgname string) {
if localpkg.Name == "" { if ir.LocalPkg.Name == "" {
if pkgname == "_" { if pkgname == "_" {
base.Errorf("invalid package name _") base.Errorf("invalid package name _")
} }
localpkg.Name = pkgname ir.LocalPkg.Name = pkgname
} else { } else {
if pkgname != localpkg.Name { if pkgname != ir.LocalPkg.Name {
base.Errorf("package %s; expected %s", pkgname, localpkg.Name) base.Errorf("package %s; expected %s", pkgname, ir.LocalPkg.Name)
} }
} }
} }
@ -954,12 +944,12 @@ func clearImports() {
} }
var unused []importedPkg var unused []importedPkg
for _, s := range localpkg.Syms { for _, s := range ir.LocalPkg.Syms {
n := asNode(s.Def) n := ir.AsNode(s.Def)
if n == nil { if n == nil {
continue continue
} }
if n.Op == OPACK { if n.Op == ir.OPACK {
// throw away top-level package name left over // throw away top-level package name left over
// from previous file. // from previous file.
// leave s->block set to cause redeclaration // leave s->block set to cause redeclaration
@ -990,7 +980,7 @@ func clearImports() {
} }
func IsAlias(sym *types.Sym) bool { 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 // recordFlags records the specified command-line flags to be placed
@ -1057,7 +1047,7 @@ func recordPackageName() {
// together two package main archives. So allow dups. // together two package main archives. So allow dups.
s.Set(obj.AttrDuplicateOK, true) s.Set(obj.AttrDuplicateOK, true)
base.Ctxt.Data = append(base.Ctxt.Data, s) 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. // currentLang returns the current language version.
@ -1084,9 +1074,9 @@ var langWant lang
func langSupported(major, minor int, pkg *types.Pkg) bool { func langSupported(major, minor int, pkg *types.Pkg) bool {
if pkg == nil { if pkg == nil {
// TODO(mdempsky): Set Pkg for local types earlier. // 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. // Assume imported packages passed type-checking.
return true return true
} }

View file

@ -35,7 +35,10 @@ func main() {
fmt.Fprintln(&b) fmt.Fprintln(&b)
fmt.Fprintln(&b, "package gc") fmt.Fprintln(&b, "package gc")
fmt.Fprintln(&b) 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") mkbuiltin(&b, "runtime")
@ -144,12 +147,12 @@ func (i *typeInterner) mktype(t ast.Expr) string {
case "rune": case "rune":
return "types.Runetype" 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: case *ast.SelectorExpr:
if t.X.(*ast.Ident).Name != "unsafe" || t.Sel.Name != "Pointer" { if t.X.(*ast.Ident).Name != "unsafe" || t.Sel.Name != "Pointer" {
log.Fatalf("unhandled type: %#v", t) log.Fatalf("unhandled type: %#v", t)
} }
return "types.Types[TUNSAFEPTR]" return "types.Types[types.TUNSAFEPTR]"
case *ast.ArrayType: case *ast.ArrayType:
if t.Len == nil { if t.Len == nil {
@ -171,7 +174,7 @@ func (i *typeInterner) mktype(t ast.Expr) string {
if len(t.Methods.List) != 0 { if len(t.Methods.List) != 0 {
log.Fatal("non-empty interfaces unsupported") log.Fatal("non-empty interfaces unsupported")
} }
return "types.Types[TINTER]" return "types.Types[types.TINTER]"
case *ast.MapType: case *ast.MapType:
return fmt.Sprintf("types.NewMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value)) return fmt.Sprintf("types.NewMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value))
case *ast.StarExpr: case *ast.StarExpr:
@ -204,7 +207,7 @@ func (i *typeInterner) fields(fl *ast.FieldList, keepNames bool) string {
} }
} }
} }
return fmt.Sprintf("[]*Node{%s}", strings.Join(res, ", ")) return fmt.Sprintf("[]*ir.Node{%s}", strings.Join(res, ", "))
} }
func intconst(e ast.Expr) int64 { func intconst(e ast.Expr) int64 {

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/obj" "cmd/internal/obj"
@ -83,7 +84,7 @@ func printObjHeader(bout *bio.Writer) {
if base.Flag.BuildID != "" { if base.Flag.BuildID != "" {
fmt.Fprintf(bout, "build id %q\n", 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, "main\n")
} }
fmt.Fprintf(bout, "\n") // header ends with blank line fmt.Fprintf(bout, "\n") // header ends with blank line
@ -141,7 +142,7 @@ func dumpdata() {
for { for {
for i := xtops; i < len(xtop); i++ { for i := xtops; i < len(xtop); i++ {
n := xtop[i] n := xtop[i]
if n.Op == ODCLFUNC { if n.Op == ir.ODCLFUNC {
funccompile(n) funccompile(n)
} }
} }
@ -199,16 +200,16 @@ func dumpLinkerObj(bout *bio.Writer) {
} }
func addptabs() { func addptabs() {
if !base.Ctxt.Flag_dynlink || localpkg.Name != "main" { if !base.Ctxt.Flag_dynlink || ir.LocalPkg.Name != "main" {
return return
} }
for _, exportn := range exportlist { for _, exportn := range exportlist {
s := exportn.Sym s := exportn.Sym
n := asNode(s.Def) n := ir.AsNode(s.Def)
if n == nil { if n == nil {
continue continue
} }
if n.Op != ONAME { if n.Op != ir.ONAME {
continue continue
} }
if !types.IsExported(s.Name) { if !types.IsExported(s.Name) {
@ -217,37 +218,37 @@ func addptabs() {
if s.Pkg.Name != "main" { if s.Pkg.Name != "main" {
continue continue
} }
if n.Type.Etype == TFUNC && n.Class() == PFUNC { if n.Type.Etype == types.TFUNC && n.Class() == ir.PFUNC {
// function // 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 { } else {
// variable // 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 { if n.Type == nil {
base.Fatalf("external %v nil type\n", n) base.Fatalf("external %v nil type\n", n)
} }
if n.Class() == PFUNC { if n.Class() == ir.PFUNC {
return return
} }
if n.Sym.Pkg != localpkg { if n.Sym.Pkg != ir.LocalPkg {
return return
} }
dowidth(n.Type) dowidth(n.Type)
ggloblnod(n) ggloblnod(n)
} }
func dumpGlobalConst(n *Node) { func dumpGlobalConst(n *ir.Node) {
// only export typed constants // only export typed constants
t := n.Type t := n.Type
if t == nil { if t == nil {
return return
} }
if n.Sym.Pkg != localpkg { if n.Sym.Pkg != ir.LocalPkg {
return return
} }
// only export integer constants for now // only export integer constants for now
@ -257,21 +258,21 @@ func dumpGlobalConst(n *Node) {
v := n.Val() v := n.Val()
if t.IsUntyped() { if t.IsUntyped() {
// Export untyped integers as int (if they fit). // Export untyped integers as int (if they fit).
t = types.Types[TINT] t = types.Types[types.TINT]
if doesoverflow(v, t) { if doesoverflow(v, t) {
return 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() { func dumpglobls() {
// add globals // add globals
for _, n := range externdcl { for _, n := range externdcl {
switch n.Op { switch n.Op {
case ONAME: case ir.ONAME:
dumpGlobal(n) dumpGlobal(n)
case OLITERAL: case ir.OLITERAL:
dumpGlobalConst(n) dumpGlobalConst(n)
} }
} }
@ -474,12 +475,12 @@ func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.
var slicedataGen int var slicedataGen int
func slicedata(pos src.XPos, s string) *Node { func slicedata(pos src.XPos, s string) *ir.Node {
slicedataGen++ slicedataGen++
symname := fmt.Sprintf(".gobytes.%d", slicedataGen) symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
sym := localpkg.Lookup(symname) sym := ir.LocalPkg.Lookup(symname)
symnode := newname(sym) symnode := NewName(sym)
sym.Def = asTypesNode(symnode) sym.Def = ir.AsTypesNode(symnode)
lsym := sym.Linksym() lsym := sym.Linksym()
off := dstringdata(lsym, 0, s, pos, "slice") off := dstringdata(lsym, 0, s, pos, "slice")
@ -488,8 +489,8 @@ func slicedata(pos src.XPos, s string) *Node {
return symnode return symnode
} }
func slicebytes(nam *Node, s string) { func slicebytes(nam *ir.Node, s string) {
if nam.Op != ONAME { if nam.Op != ir.ONAME {
base.Fatalf("slicebytes %v", nam) base.Fatalf("slicebytes %v", nam)
} }
slicesym(nam, slicedata(nam.Pos, s), int64(len(s))) slicesym(nam, slicedata(nam.Pos, s), int64(len(s)))
@ -529,10 +530,10 @@ func dsymptrWeakOff(s *obj.LSym, off int, x *obj.LSym) int {
// slicesym writes a static slice symbol {&arr, lencap, lencap} to n. // slicesym writes a static slice symbol {&arr, lencap, lencap} to n.
// arr must be an ONAME. slicesym does not modify 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() s := n.Sym.Linksym()
off := n.Xoffset off := n.Xoffset
if arr.Op != ONAME { if arr.Op != ir.ONAME {
base.Fatalf("slicesym non-name arr %v", arr) base.Fatalf("slicesym non-name arr %v", arr)
} }
s.WriteAddr(base.Ctxt, off, Widthptr, arr.Sym.Linksym(), arr.Xoffset) s.WriteAddr(base.Ctxt, off, Widthptr, arr.Sym.Linksym(), arr.Xoffset)
@ -542,14 +543,14 @@ func slicesym(n, arr *Node, lencap int64) {
// addrsym writes the static address of a to n. a must be an ONAME. // addrsym writes the static address of a to n. a must be an ONAME.
// Neither n nor a is modified. // Neither n nor a is modified.
func addrsym(n, a *Node) { func addrsym(n, a *ir.Node) {
if n.Op != ONAME { if n.Op != ir.ONAME {
base.Fatalf("addrsym n op %v", n.Op) base.Fatalf("addrsym n op %v", n.Op)
} }
if n.Sym == nil { if n.Sym == nil {
base.Fatalf("addrsym nil n sym") base.Fatalf("addrsym nil n sym")
} }
if a.Op != ONAME { if a.Op != ir.ONAME {
base.Fatalf("addrsym a op %v", a.Op) base.Fatalf("addrsym a op %v", a.Op)
} }
s := n.Sym.Linksym() s := n.Sym.Linksym()
@ -558,14 +559,14 @@ func addrsym(n, a *Node) {
// pfuncsym writes the static address of f to n. f must be a global function. // pfuncsym writes the static address of f to n. f must be a global function.
// Neither n nor f is modified. // Neither n nor f is modified.
func pfuncsym(n, f *Node) { func pfuncsym(n, f *ir.Node) {
if n.Op != ONAME { if n.Op != ir.ONAME {
base.Fatalf("pfuncsym n op %v", n.Op) base.Fatalf("pfuncsym n op %v", n.Op)
} }
if n.Sym == nil { if n.Sym == nil {
base.Fatalf("pfuncsym nil n sym") base.Fatalf("pfuncsym nil n sym")
} }
if f.Class() != PFUNC { if f.Class() != ir.PFUNC {
base.Fatalf("pfuncsym class not PFUNC %d", f.Class()) base.Fatalf("pfuncsym class not PFUNC %d", f.Class())
} }
s := n.Sym.Linksym() s := n.Sym.Linksym()
@ -574,8 +575,8 @@ func pfuncsym(n, f *Node) {
// litsym writes the static literal c to n. // litsym writes the static literal c to n.
// Neither n nor c is modified. // Neither n nor c is modified.
func litsym(n, c *Node, wid int) { func litsym(n, c *ir.Node, wid int) {
if n.Op != ONAME { if n.Op != ir.ONAME {
base.Fatalf("litsym n op %v", n.Op) base.Fatalf("litsym n op %v", n.Op)
} }
if n.Sym == nil { if n.Sym == nil {
@ -584,10 +585,10 @@ func litsym(n, c *Node, wid int) {
if !types.Identical(n.Type, c.Type) { 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) 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 return
} }
if c.Op != OLITERAL { if c.Op != ir.OLITERAL {
base.Fatalf("litsym c op %v", c.Op) base.Fatalf("litsym c op %v", c.Op)
} }
s := n.Sym.Linksym() s := n.Sym.Linksym()
@ -597,14 +598,14 @@ func litsym(n, c *Node, wid int) {
s.WriteInt(base.Ctxt, n.Xoffset, wid, i) s.WriteInt(base.Ctxt, n.Xoffset, wid, i)
case constant.Int: 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: case constant.Float:
f, _ := constant.Float64Val(u) f, _ := constant.Float64Val(u)
switch n.Type.Etype { switch n.Type.Etype {
case TFLOAT32: case types.TFLOAT32:
s.WriteFloat32(base.Ctxt, n.Xoffset, float32(f)) s.WriteFloat32(base.Ctxt, n.Xoffset, float32(f))
case TFLOAT64: case types.TFLOAT64:
s.WriteFloat64(base.Ctxt, n.Xoffset, f) s.WriteFloat64(base.Ctxt, n.Xoffset, f)
} }
@ -612,10 +613,10 @@ func litsym(n, c *Node, wid int) {
re, _ := constant.Float64Val(constant.Real(u)) re, _ := constant.Float64Val(constant.Real(u))
im, _ := constant.Float64Val(constant.Imag(u)) im, _ := constant.Float64Val(constant.Imag(u))
switch n.Type.Etype { switch n.Type.Etype {
case TCOMPLEX64: case types.TCOMPLEX64:
s.WriteFloat32(base.Ctxt, n.Xoffset, float32(re)) s.WriteFloat32(base.Ctxt, n.Xoffset, float32(re))
s.WriteFloat32(base.Ctxt, n.Xoffset+4, float32(im)) 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, re)
s.WriteFloat64(base.Ctxt, n.Xoffset+8, im) s.WriteFloat64(base.Ctxt, n.Xoffset+8, im)
} }

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/dwarf" "cmd/internal/dwarf"
@ -23,14 +24,14 @@ import (
// "Portable" code generation. // "Portable" code generation.
var ( var (
compilequeue []*Node // functions waiting to be compiled compilequeue []*ir.Node // functions waiting to be compiled
) )
func emitptrargsmap(fn *Node) { func emitptrargsmap(fn *ir.Node) {
if fn.funcname() == "_" || fn.Func.Nname.Sym.Linkname != "" { if ir.FuncName(fn) == "_" || fn.Func.Nname.Sym.Linkname != "" {
return 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)) nptr := int(fn.Type.ArgWidth() / int64(Widthptr))
bv := bvalloc(int32(nptr) * 2) bv := bvalloc(int32(nptr) * 2)
@ -41,7 +42,7 @@ func emitptrargsmap(fn *Node) {
off := duint32(lsym, 0, uint32(nbitmap)) off := duint32(lsym, 0, uint32(nbitmap))
off = duint32(lsym, off, uint32(bv.n)) off = duint32(lsym, off, uint32(bv.n))
if fn.IsMethod() { if ir.IsMethod(fn) {
onebitwalktype1(fn.Type.Recvs(), 0, bv) onebitwalktype1(fn.Type.Recvs(), 0, bv)
} }
if fn.Type.NumParams() > 0 { if fn.Type.NumParams() > 0 {
@ -67,12 +68,12 @@ func emitptrargsmap(fn *Node) {
// really means, in memory, things with pointers needing zeroing at // really means, in memory, things with pointers needing zeroing at
// the top of the stack and increasing in size. // the top of the stack and increasing in size.
// Non-autos sort on offset. // Non-autos sort on offset.
func cmpstackvarlt(a, b *Node) bool { func cmpstackvarlt(a, b *ir.Node) bool {
if (a.Class() == PAUTO) != (b.Class() == PAUTO) { if (a.Class() == ir.PAUTO) != (b.Class() == ir.PAUTO) {
return b.Class() == PAUTO return b.Class() == ir.PAUTO
} }
if a.Class() != PAUTO { if a.Class() != ir.PAUTO {
return a.Xoffset < b.Xoffset return a.Xoffset < b.Xoffset
} }
@ -100,7 +101,7 @@ func cmpstackvarlt(a, b *Node) bool {
} }
// byStackvar implements sort.Interface for []*Node using cmpstackvarlt. // 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) Len() int { return len(s) }
func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) } func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
@ -113,28 +114,28 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
// Mark the PAUTO's unused. // Mark the PAUTO's unused.
for _, ln := range fn.Dcl { for _, ln := range fn.Dcl {
if ln.Class() == PAUTO { if ln.Class() == ir.PAUTO {
ln.Name.SetUsed(false) ln.Name.SetUsed(false)
} }
} }
for _, l := range f.RegAlloc { for _, l := range f.RegAlloc {
if ls, ok := l.(ssa.LocalSlot); ok { if ls, ok := l.(ssa.LocalSlot); ok {
ls.N.(*Node).Name.SetUsed(true) ls.N.(*ir.Node).Name.SetUsed(true)
} }
} }
scratchUsed := false scratchUsed := false
for _, b := range f.Blocks { for _, b := range f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
if n, ok := v.Aux.(*Node); ok { if n, ok := v.Aux.(*ir.Node); ok {
switch n.Class() { switch n.Class() {
case PPARAM, PPARAMOUT: case ir.PPARAM, ir.PPARAMOUT:
// Don't modify nodfp; it is a global. // Don't modify nodfp; it is a global.
if n != nodfp { if n != nodfp {
n.Name.SetUsed(true) n.Name.SetUsed(true)
} }
case PAUTO: case ir.PAUTO:
n.Name.SetUsed(true) n.Name.SetUsed(true)
} }
} }
@ -146,7 +147,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
} }
if f.Config.NeedsFpScratch && scratchUsed { 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)) sort.Sort(byStackVar(fn.Dcl))
@ -154,7 +155,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
// Reassign stack offsets of the locals that are used. // Reassign stack offsets of the locals that are used.
lastHasPtr := false lastHasPtr := false
for i, n := range fn.Dcl { for i, n := range fn.Dcl {
if n.Op != ONAME || n.Class() != PAUTO { if n.Op != ir.ONAME || n.Class() != ir.PAUTO {
continue continue
} }
if !n.Name.Used() { if !n.Name.Used() {
@ -192,7 +193,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg)) s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
} }
func funccompile(fn *Node) { func funccompile(fn *ir.Node) {
if Curfn != nil { if Curfn != nil {
base.Fatalf("funccompile %v inside %v", fn.Func.Nname.Sym, Curfn.Func.Nname.Sym) base.Fatalf("funccompile %v inside %v", fn.Func.Nname.Sym, Curfn.Func.Nname.Sym)
} }
@ -209,21 +210,21 @@ func funccompile(fn *Node) {
if fn.Nbody.Len() == 0 { if fn.Nbody.Len() == 0 {
// Initialize ABI wrappers if necessary. // Initialize ABI wrappers if necessary.
fn.Func.initLSym(false) initLSym(fn.Func, false)
emitptrargsmap(fn) emitptrargsmap(fn)
return return
} }
dclcontext = PAUTO dclcontext = ir.PAUTO
Curfn = fn Curfn = fn
compile(fn) compile(fn)
Curfn = nil Curfn = nil
dclcontext = PEXTERN dclcontext = ir.PEXTERN
} }
func compile(fn *Node) { func compile(fn *ir.Node) {
errorsBefore := base.Errors() errorsBefore := base.Errors()
order(fn) order(fn)
if base.Errors() > errorsBefore { if base.Errors() > errorsBefore {
@ -233,7 +234,7 @@ func compile(fn *Node) {
// Set up the function's LSym early to avoid data races with the assemblers. // 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 // Do this before walk, as walk needs the LSym to set attributes/relocations
// (e.g. in markTypeUsedInInterface). // (e.g. in markTypeUsedInInterface).
fn.Func.initLSym(true) initLSym(fn.Func, true)
walk(fn) walk(fn)
if base.Errors() > errorsBefore { if base.Errors() > errorsBefore {
@ -246,7 +247,7 @@ func compile(fn *Node) {
// From this point, there should be no uses of Curfn. Enforce that. // From this point, there should be no uses of Curfn. Enforce that.
Curfn = nil 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. // 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. // At this point we've generated any errors needed.
// (Beyond here we generate only non-spec errors, like "stack frame too large".) // (Beyond here we generate only non-spec errors, like "stack frame too large".)
@ -260,13 +261,13 @@ func compile(fn *Node) {
// phase of the compiler. // phase of the compiler.
for _, n := range fn.Func.Dcl { for _, n := range fn.Func.Dcl {
switch n.Class() { switch n.Class() {
case PPARAM, PPARAMOUT, PAUTO: case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
if livenessShouldTrack(n) && n.Name.Addrtaken() { if livenessShouldTrack(n) && n.Name.Addrtaken() {
dtypesym(n.Type) dtypesym(n.Type)
// Also make sure we allocate a linker symbol // Also make sure we allocate a linker symbol
// for the stack object data, for the same reason. // for the stack object data, for the same reason.
if fn.Func.lsym.Func().StackObjects == nil { if fn.Func.LSym.Func().StackObjects == nil {
fn.Func.lsym.Func().StackObjects = base.Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj") fn.Func.LSym.Func().StackObjects = base.Ctxt.Lookup(fn.Func.LSym.Name + ".stkobj")
} }
} }
} }
@ -283,13 +284,13 @@ func compile(fn *Node) {
// If functions are not compiled immediately, // If functions are not compiled immediately,
// they are enqueued in compilequeue, // they are enqueued in compilequeue,
// which is drained by compileFunctions. // 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 // Issue 38068: if this function is a method AND an inline
// candidate AND was not inlined (yet), put it onto the compile // candidate AND was not inlined (yet), put it onto the compile
// queue instead of compiling it immediately. This is in case we // queue instead of compiling it immediately. This is in case we
// wind up inlining it into a method wrapper that is generated by // wind up inlining it into a method wrapper that is generated by
// compiling a function later on in the xtop list. // compiling a function later on in the xtop list.
if fn.IsMethod() && isInlinableButNotInlined(fn) { if ir.IsMethod(fn) && isInlinableButNotInlined(fn) {
return false return false
} }
return base.Flag.LowerC == 1 && base.Debug.CompileLater == 0 return base.Flag.LowerC == 1 && base.Debug.CompileLater == 0
@ -298,7 +299,7 @@ func compilenow(fn *Node) bool {
// isInlinableButNotInlined returns true if 'fn' was marked as an // isInlinableButNotInlined returns true if 'fn' was marked as an
// inline candidate but then never inlined (presumably because we // inline candidate but then never inlined (presumably because we
// found no call sites). // found no call sites).
func isInlinableButNotInlined(fn *Node) bool { func isInlinableButNotInlined(fn *ir.Node) bool {
if fn.Func.Nname.Func.Inl == nil { if fn.Func.Nname.Func.Inl == nil {
return false return false
} }
@ -314,7 +315,7 @@ const maxStackSize = 1 << 30
// uses it to generate a plist, // uses it to generate a plist,
// and flushes that plist to machine code. // and flushes that plist to machine code.
// worker indicates which of the backend workers is doing the processing. // 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) f := buildssa(fn, worker)
// Note: check arg size to fix issue 25507. // Note: check arg size to fix issue 25507.
if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize { if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize {
@ -359,7 +360,7 @@ func compileFunctions() {
sizeCalculationDisabled = true // not safe to calculate sizes concurrently sizeCalculationDisabled = true // not safe to calculate sizes concurrently
if race.Enabled { if race.Enabled {
// Randomize compilation order to try to shake out races. // 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)) perm := rand.Perm(len(compilequeue))
for i, v := range perm { for i, v := range perm {
tmp[v] = compilequeue[i] tmp[v] = compilequeue[i]
@ -375,7 +376,7 @@ func compileFunctions() {
} }
var wg sync.WaitGroup var wg sync.WaitGroup
base.Ctxt.InParallel = true 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++ { for i := 0; i < base.Flag.LowerC; i++ {
wg.Add(1) wg.Add(1)
go func(worker int) { go func(worker int) {
@ -397,7 +398,7 @@ func compileFunctions() {
} }
func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) { 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 fn.Func.Nname != nil {
if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect { if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
base.Fatalf("unexpected fnsym: %v != %v", fnsym, expect) base.Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
@ -429,17 +430,17 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
// //
// These two adjustments keep toolstash -cmp working for now. // These two adjustments keep toolstash -cmp working for now.
// Deciding the right answer is, as they say, future work. // 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. // Populate decls for fn.
if isODCLFUNC { if isODCLFUNC {
for _, n := range fn.Func.Dcl { 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 continue
} }
switch n.Class() { switch n.Class() {
case PAUTO: case ir.PAUTO:
if !n.Name.Used() { if !n.Name.Used() {
// Text == nil -> generating abstract function // Text == nil -> generating abstract function
if fnsym.Func().Text != nil { if fnsym.Func().Text != nil {
@ -447,7 +448,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
} }
continue continue
} }
case PPARAM, PPARAMOUT: case ir.PPARAM, ir.PPARAMOUT:
default: default:
continue continue
} }
@ -474,7 +475,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
} }
fnsym.Func().Autot = nil fnsym.Func().Autot = nil
var varScopes []ScopeID var varScopes []ir.ScopeID
for _, decl := range decls { for _, decl := range decls {
pos := declPos(decl) pos := declPos(decl)
varScopes = append(varScopes, findScope(fn.Func.Marks, pos)) varScopes = append(varScopes, findScope(fn.Func.Marks, pos))
@ -488,7 +489,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
return scopes, inlcalls 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()) { if decl.Name.Defn != nil && (decl.Name.Captured() || decl.Name.Byval()) {
// It's not clear which position is correct for captured variables here: // It's not clear which position is correct for captured variables here:
// * decl.Pos is the wrong position for captured variables, in the inner // * decl.Pos is the wrong position for captured variables, in the inner
@ -511,10 +512,10 @@ func declPos(decl *Node) src.XPos {
// createSimpleVars creates a DWARF entry for every variable declared in the // createSimpleVars creates a DWARF entry for every variable declared in the
// function, claiming that they are permanently on the stack. // 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 vars []*dwarf.Var
var decls []*Node var decls []*ir.Node
selected := make(map[*Node]bool) selected := make(map[*ir.Node]bool)
for _, n := range apDecls { for _, n := range apDecls {
if n.IsAutoTmp() { if n.IsAutoTmp() {
continue continue
@ -527,12 +528,12 @@ func createSimpleVars(fnsym *obj.LSym, apDecls []*Node) ([]*Node, []*dwarf.Var,
return decls, vars, selected 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 var abbrev int
offs := n.Xoffset offs := n.Xoffset
switch n.Class() { switch n.Class() {
case PAUTO: case ir.PAUTO:
abbrev = dwarf.DW_ABRV_AUTO abbrev = dwarf.DW_ABRV_AUTO
if base.Ctxt.FixedFrameSize() == 0 { if base.Ctxt.FixedFrameSize() == 0 {
offs -= int64(Widthptr) offs -= int64(Widthptr)
@ -542,7 +543,7 @@ func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
offs -= int64(Widthptr) offs -= int64(Widthptr)
} }
case PPARAM, PPARAMOUT: case ir.PPARAM, ir.PPARAMOUT:
abbrev = dwarf.DW_ABRV_PARAM abbrev = dwarf.DW_ABRV_PARAM
offs += base.Ctxt.FixedFrameSize() offs += base.Ctxt.FixedFrameSize()
default: default:
@ -563,7 +564,7 @@ func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
declpos := base.Ctxt.InnermostPos(declPos(n)) declpos := base.Ctxt.InnermostPos(declPos(n))
return &dwarf.Var{ return &dwarf.Var{
Name: n.Sym.Name, Name: n.Sym.Name,
IsReturnValue: n.Class() == PPARAMOUT, IsReturnValue: n.Class() == ir.PPARAMOUT,
IsInlFormal: n.Name.InlFormal(), IsInlFormal: n.Name.InlFormal(),
Abbrev: abbrev, Abbrev: abbrev,
StackOffset: int32(offs), StackOffset: int32(offs),
@ -578,19 +579,19 @@ func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
// createComplexVars creates recomposed DWARF vars with location lists, // createComplexVars creates recomposed DWARF vars with location lists,
// suitable for describing optimized code. // 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 debugInfo := fn.DebugInfo
// Produce a DWARF variable entry for each user variable. // Produce a DWARF variable entry for each user variable.
var decls []*Node var decls []*ir.Node
var vars []*dwarf.Var var vars []*dwarf.Var
ssaVars := make(map[*Node]bool) ssaVars := make(map[*ir.Node]bool)
for varID, dvar := range debugInfo.Vars { for varID, dvar := range debugInfo.Vars {
n := dvar.(*Node) n := dvar.(*ir.Node)
ssaVars[n] = true ssaVars[n] = true
for _, slot := range debugInfo.VarSlots[varID] { 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 { if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID)); dvar != nil {
@ -604,11 +605,11 @@ func createComplexVars(fnsym *obj.LSym, fn *Func) ([]*Node, []*dwarf.Var, map[*N
// createDwarfVars process fn, returning a list of DWARF variables and the // createDwarfVars process fn, returning a list of DWARF variables and the
// Nodes they represent. // 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. // Collect a raw list of DWARF vars.
var vars []*dwarf.Var var vars []*dwarf.Var
var decls []*Node var decls []*ir.Node
var selected map[*Node]bool var selected map[*ir.Node]bool
if base.Ctxt.Flag_locationlists && base.Ctxt.Flag_optimize && fn.DebugInfo != nil && complexOK { if base.Ctxt.Flag_locationlists && base.Ctxt.Flag_optimize && fn.DebugInfo != nil && complexOK {
decls, vars, selected = createComplexVars(fnsym, fn) decls, vars, selected = createComplexVars(fnsym, fn)
} else { } else {
@ -640,7 +641,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *Func, apDecls []*Node)
if c == '.' || n.Type.IsUntyped() { if c == '.' || n.Type.IsUntyped() {
continue 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 // SSA-able args get location lists, and may move in and
// out of registers, so those are handled elsewhere. // out of registers, so those are handled elsewhere.
// Autos and named output params seem to get handled // Autos and named output params seem to get handled
@ -655,10 +656,10 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *Func, apDecls []*Node)
typename := dwarf.InfoPrefix + typesymname(n.Type) typename := dwarf.InfoPrefix + typesymname(n.Type)
decls = append(decls, n) decls = append(decls, n)
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
isReturnValue := (n.Class() == PPARAMOUT) isReturnValue := (n.Class() == ir.PPARAMOUT)
if n.Class() == PPARAM || n.Class() == PPARAMOUT { if n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST 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 // If dcl in question has been promoted to heap, do a bit
// of extra work to recover original class (auto or param); // of extra work to recover original class (auto or param);
// see issue 30908. This insures that we get the proper // see issue 30908. This insures that we get the proper
@ -667,9 +668,9 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *Func, apDecls []*Node)
// and not stack). // and not stack).
// TODO(thanm): generate a better location expression // TODO(thanm): generate a better location expression
stackcopy := n.Name.Param.Stackcopy 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 abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
isReturnValue = (stackcopy.Class() == PPARAMOUT) isReturnValue = (stackcopy.Class() == ir.PPARAMOUT)
} }
} }
inlIndex := 0 inlIndex := 0
@ -707,9 +708,9 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *Func, apDecls []*Node)
// function that is not local to the package being compiled, then the // function that is not local to the package being compiled, then the
// names of the variables may have been "versioned" to avoid conflicts // names of the variables may have been "versioned" to avoid conflicts
// with local vars; disregard this versioning when sorting. // with local vars; disregard this versioning when sorting.
func preInliningDcls(fnsym *obj.LSym) []*Node { func preInliningDcls(fnsym *obj.LSym) []*ir.Node {
fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node) fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*ir.Node)
var rdcl []*Node var rdcl []*ir.Node
for _, n := range fn.Func.Inl.Dcl { for _, n := range fn.Func.Inl.Dcl {
c := n.Sym.Name[0] c := n.Sym.Name[0]
// Avoid reporting "_" parameters, since if there are more than // Avoid reporting "_" parameters, since if there are more than
@ -726,10 +727,10 @@ func preInliningDcls(fnsym *obj.LSym) []*Node {
// stack pointer, suitable for use in a DWARF location entry. This has nothing // stack pointer, suitable for use in a DWARF location entry. This has nothing
// to do with its offset in the user variable. // to do with its offset in the user variable.
func stackOffset(slot ssa.LocalSlot) int32 { func stackOffset(slot ssa.LocalSlot) int32 {
n := slot.N.(*Node) n := slot.N.(*ir.Node)
var off int64 var off int64
switch n.Class() { switch n.Class() {
case PAUTO: case ir.PAUTO:
if base.Ctxt.FixedFrameSize() == 0 { if base.Ctxt.FixedFrameSize() == 0 {
off -= int64(Widthptr) off -= int64(Widthptr)
} }
@ -737,22 +738,22 @@ func stackOffset(slot ssa.LocalSlot) int32 {
// There is a word space for FP on ARM64 even if the frame pointer is disabled // There is a word space for FP on ARM64 even if the frame pointer is disabled
off -= int64(Widthptr) off -= int64(Widthptr)
} }
case PPARAM, PPARAMOUT: case ir.PPARAM, ir.PPARAMOUT:
off += base.Ctxt.FixedFrameSize() off += base.Ctxt.FixedFrameSize()
} }
return int32(off + n.Xoffset + slot.Off) return int32(off + n.Xoffset + slot.Off)
} }
// createComplexVar builds a single DWARF variable entry and location list. // 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 debug := fn.DebugInfo
n := debug.Vars[varID].(*Node) n := debug.Vars[varID].(*ir.Node)
var abbrev int var abbrev int
switch n.Class() { switch n.Class() {
case PAUTO: case ir.PAUTO:
abbrev = dwarf.DW_ABRV_AUTO_LOCLIST abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
case PPARAM, PPARAMOUT: case ir.PPARAM, ir.PPARAMOUT:
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
default: default:
return nil return nil
@ -773,7 +774,7 @@ func createComplexVar(fnsym *obj.LSym, fn *Func, varID ssa.VarID) *dwarf.Var {
declpos := base.Ctxt.InnermostPos(n.Pos) declpos := base.Ctxt.InnermostPos(n.Pos)
dvar := &dwarf.Var{ dvar := &dwarf.Var{
Name: n.Sym.Name, Name: n.Sym.Name,
IsReturnValue: n.Class() == PPARAMOUT, IsReturnValue: n.Class() == ir.PPARAMOUT,
IsInlFormal: n.Name.InlFormal(), IsInlFormal: n.Name.InlFormal(),
Abbrev: abbrev, Abbrev: abbrev,
Type: base.Ctxt.Lookup(typename), Type: base.Ctxt.Lookup(typename),

View file

@ -5,6 +5,7 @@
package gc package gc
import ( import (
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"reflect" "reflect"
"sort" "sort"
@ -12,133 +13,133 @@ import (
) )
func typeWithoutPointers() *types.Type { func typeWithoutPointers() *types.Type {
t := types.New(TSTRUCT) t := types.New(types.TSTRUCT)
f := &types.Field{Type: types.New(TINT)} f := &types.Field{Type: types.New(types.TINT)}
t.SetFields([]*types.Field{f}) t.SetFields([]*types.Field{f})
return t return t
} }
func typeWithPointers() *types.Type { func typeWithPointers() *types.Type {
t := types.New(TSTRUCT) t := types.New(types.TSTRUCT)
f := &types.Field{Type: types.NewPtr(types.New(TINT))} f := &types.Field{Type: types.NewPtr(types.New(types.TINT))}
t.SetFields([]*types.Field{f}) t.SetFields([]*types.Field{f})
return t return t
} }
func markUsed(n *Node) *Node { func markUsed(n *ir.Node) *ir.Node {
n.Name.SetUsed(true) n.Name.SetUsed(true)
return n return n
} }
func markNeedZero(n *Node) *Node { func markNeedZero(n *ir.Node) *ir.Node {
n.Name.SetNeedzero(true) n.Name.SetNeedzero(true)
return n return n
} }
// Test all code paths for cmpstackvarlt. // Test all code paths for cmpstackvarlt.
func TestCmpstackvar(t *testing.T) { 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 { if s == nil {
s = &types.Sym{Name: "."} s = &types.Sym{Name: "."}
} }
n := newname(s) n := NewName(s)
n.Type = t n.Type = t
n.Xoffset = xoffset n.Xoffset = xoffset
n.SetClass(cl) n.SetClass(cl)
return n return n
} }
testdata := []struct { testdata := []struct {
a, b *Node a, b *ir.Node
lt bool lt bool
}{ }{
{ {
nod(0, nil, nil, PAUTO), nod(0, nil, nil, ir.PAUTO),
nod(0, nil, nil, PFUNC), nod(0, nil, nil, ir.PFUNC),
false, false,
}, },
{ {
nod(0, nil, nil, PFUNC), nod(0, nil, nil, ir.PFUNC),
nod(0, nil, nil, PAUTO), nod(0, nil, nil, ir.PAUTO),
true, true,
}, },
{ {
nod(0, nil, nil, PFUNC), nod(0, nil, nil, ir.PFUNC),
nod(10, nil, nil, PFUNC), nod(10, nil, nil, ir.PFUNC),
true, true,
}, },
{ {
nod(20, nil, nil, PFUNC), nod(20, nil, nil, ir.PFUNC),
nod(10, nil, nil, PFUNC), nod(10, nil, nil, ir.PFUNC),
false, false,
}, },
{ {
nod(10, nil, nil, PFUNC), nod(10, nil, nil, ir.PFUNC),
nod(10, nil, nil, PFUNC), nod(10, nil, nil, ir.PFUNC),
false, false,
}, },
{ {
nod(10, nil, nil, PPARAM), nod(10, nil, nil, ir.PPARAM),
nod(20, nil, nil, PPARAMOUT), nod(20, nil, nil, ir.PPARAMOUT),
true, true,
}, },
{ {
nod(10, nil, nil, PPARAMOUT), nod(10, nil, nil, ir.PPARAMOUT),
nod(20, nil, nil, PPARAM), nod(20, nil, nil, ir.PPARAM),
true, true,
}, },
{ {
markUsed(nod(0, nil, nil, PAUTO)), markUsed(nod(0, nil, nil, ir.PAUTO)),
nod(0, nil, nil, PAUTO), nod(0, nil, nil, ir.PAUTO),
true, true,
}, },
{ {
nod(0, nil, nil, PAUTO), nod(0, nil, nil, ir.PAUTO),
markUsed(nod(0, nil, nil, PAUTO)), markUsed(nod(0, nil, nil, ir.PAUTO)),
false, false,
}, },
{ {
nod(0, typeWithoutPointers(), nil, PAUTO), nod(0, typeWithoutPointers(), nil, ir.PAUTO),
nod(0, typeWithPointers(), nil, PAUTO), nod(0, typeWithPointers(), nil, ir.PAUTO),
false, false,
}, },
{ {
nod(0, typeWithPointers(), nil, PAUTO), nod(0, typeWithPointers(), nil, ir.PAUTO),
nod(0, typeWithoutPointers(), nil, PAUTO), nod(0, typeWithoutPointers(), nil, ir.PAUTO),
true, true,
}, },
{ {
markNeedZero(nod(0, &types.Type{}, nil, PAUTO)), markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
nod(0, &types.Type{}, nil, PAUTO), nod(0, &types.Type{}, nil, ir.PAUTO),
true, true,
}, },
{ {
nod(0, &types.Type{}, nil, PAUTO), nod(0, &types.Type{}, nil, ir.PAUTO),
markNeedZero(nod(0, &types.Type{}, nil, PAUTO)), markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
false, false,
}, },
{ {
nod(0, &types.Type{Width: 1}, nil, PAUTO), nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
nod(0, &types.Type{Width: 2}, nil, PAUTO), nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
false, false,
}, },
{ {
nod(0, &types.Type{Width: 2}, nil, PAUTO), nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
nod(0, &types.Type{Width: 1}, nil, PAUTO), nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
true, true,
}, },
{ {
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: "xyz"}, PAUTO), nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
true, true,
}, },
{ {
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"}, PAUTO), nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
false, false,
}, },
{ {
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, PAUTO), nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, PAUTO), nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
false, false,
}, },
} }
@ -155,42 +156,42 @@ func TestCmpstackvar(t *testing.T) {
} }
func TestStackvarSort(t *testing.T) { func TestStackvarSort(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 {
n := newname(s) n := NewName(s)
n.Type = t n.Type = t
n.Xoffset = xoffset n.Xoffset = xoffset
n.SetClass(cl) n.SetClass(cl)
return n return n
} }
inp := []*Node{ inp := []*ir.Node{
nod(0, &types.Type{}, &types.Sym{}, PFUNC), nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(0, &types.Type{}, &types.Sym{}, PAUTO), nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, PFUNC), nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(10, &types.Type{}, &types.Sym{}, PFUNC), nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(20, &types.Type{}, &types.Sym{}, PFUNC), nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
markUsed(nod(0, &types.Type{}, &types.Sym{}, PAUTO)), markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
nod(0, typeWithoutPointers(), &types.Sym{}, PAUTO), nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, PAUTO), nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
markNeedZero(nod(0, &types.Type{}, &types.Sym{}, PAUTO)), markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
nod(0, &types.Type{Width: 1}, &types.Sym{}, PAUTO), nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{Width: 2}, &types.Sym{}, PAUTO), nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.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: "xyz"}, PAUTO), nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
} }
want := []*Node{ want := []*ir.Node{
nod(0, &types.Type{}, &types.Sym{}, PFUNC), nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(0, &types.Type{}, &types.Sym{}, PFUNC), nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(10, &types.Type{}, &types.Sym{}, PFUNC), nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(20, &types.Type{}, &types.Sym{}, PFUNC), nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
markUsed(nod(0, &types.Type{}, &types.Sym{}, PAUTO)), markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
markNeedZero(nod(0, &types.Type{}, &types.Sym{}, PAUTO)), markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
nod(0, &types.Type{Width: 2}, &types.Sym{}, PAUTO), nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{Width: 1}, &types.Sym{}, PAUTO), nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, PAUTO), nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, PAUTO), nod(0, &types.Type{}, &types.Sym{}, ir.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: "xyz"}, PAUTO), nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
nod(0, typeWithoutPointers(), &types.Sym{}, PAUTO), nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
} }
sort.Sort(byStackVar(inp)) sort.Sort(byStackVar(inp))
if !reflect.DeepEqual(want, inp) { if !reflect.DeepEqual(want, inp) {

View file

@ -5,6 +5,7 @@
package gc package gc
import ( import (
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src" "cmd/internal/src"
@ -40,11 +41,11 @@ func (s *state) insertPhis() {
} }
type phiState struct { type phiState struct {
s *state // SSA state s *state // SSA state
f *ssa.Func // function to work on f *ssa.Func // function to work on
defvars []map[*Node]*ssa.Value // defined variables at end of each block 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 // properties of the dominator tree
idom []*ssa.Block // dominator parents idom []*ssa.Block // dominator parents
@ -70,15 +71,15 @@ func (s *phiState) insertPhis() {
// Find all the variables for which we need to match up reads & writes. // Find all the variables for which we need to match up reads & writes.
// This step prunes any basic-block-only variables from consideration. // This step prunes any basic-block-only variables from consideration.
// Generate a numbering for these variables. // Generate a numbering for these variables.
s.varnum = map[*Node]int32{} s.varnum = map[*ir.Node]int32{}
var vars []*Node var vars []*ir.Node
var vartypes []*types.Type var vartypes []*types.Type
for _, b := range s.f.Blocks { for _, b := range s.f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
if v.Op != ssa.OpFwdRef { if v.Op != ssa.OpFwdRef {
continue continue
} }
var_ := v.Aux.(*Node) var_ := v.Aux.(*ir.Node)
// Optimization: look back 1 block for the definition. // Optimization: look back 1 block for the definition.
if len(b.Preds) == 1 { if len(b.Preds) == 1 {
@ -183,7 +184,7 @@ levels:
} }
} }
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 priq := &s.priq
q := s.q q := s.q
queued := s.queued queued := s.queued
@ -318,7 +319,7 @@ func (s *phiState) resolveFwdRefs() {
if v.Op != ssa.OpFwdRef { if v.Op != ssa.OpFwdRef {
continue continue
} }
n := s.varnum[v.Aux.(*Node)] n := s.varnum[v.Aux.(*ir.Node)]
v.Op = ssa.OpCopy v.Op = ssa.OpCopy
v.Aux = nil v.Aux = nil
v.AddArg(values[n]) v.AddArg(values[n])
@ -432,11 +433,11 @@ func (s *sparseSet) clear() {
// Variant to use for small functions. // Variant to use for small functions.
type simplePhiState struct { type simplePhiState struct {
s *state // SSA state s *state // SSA state
f *ssa.Func // function to work on f *ssa.Func // function to work on
fwdrefs []*ssa.Value // list of FwdRefs to be processed fwdrefs []*ssa.Value // list of FwdRefs to be processed
defvars []map[*Node]*ssa.Value // defined variables at end of each block defvars []map[*ir.Node]*ssa.Value // defined variables at end of each block
reachable []bool // which blocks are reachable reachable []bool // which blocks are reachable
} }
func (s *simplePhiState) insertPhis() { func (s *simplePhiState) insertPhis() {
@ -449,7 +450,7 @@ func (s *simplePhiState) insertPhis() {
continue continue
} }
s.fwdrefs = append(s.fwdrefs, v) s.fwdrefs = append(s.fwdrefs, v)
var_ := v.Aux.(*Node) var_ := v.Aux.(*ir.Node)
if _, ok := s.defvars[b.ID][var_]; !ok { if _, ok := s.defvars[b.ID][var_]; !ok {
s.defvars[b.ID][var_] = v // treat FwdDefs as definitions. s.defvars[b.ID][var_] = v // treat FwdDefs as definitions.
} }
@ -463,7 +464,7 @@ loop:
v := s.fwdrefs[len(s.fwdrefs)-1] v := s.fwdrefs[len(s.fwdrefs)-1]
s.fwdrefs = s.fwdrefs[:len(s.fwdrefs)-1] s.fwdrefs = s.fwdrefs[:len(s.fwdrefs)-1]
b := v.Block b := v.Block
var_ := v.Aux.(*Node) var_ := v.Aux.(*ir.Node)
if b == s.f.Entry { if b == s.f.Entry {
// No variable should be live at 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) s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v)
@ -511,7 +512,7 @@ loop:
} }
// lookupVarOutgoing finds the variable's value at the end of block b. // 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 { for {
if v := s.defvars[b.ID][var_]; v != nil { if v := s.defvars[b.ID][var_]; v != nil {
return v return v

View file

@ -16,6 +16,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
@ -100,10 +101,10 @@ type BlockEffects struct {
// A collection of global state used by liveness analysis. // A collection of global state used by liveness analysis.
type Liveness struct { type Liveness struct {
fn *Node fn *ir.Node
f *ssa.Func f *ssa.Func
vars []*Node vars []*ir.Node
idx map[*Node]int32 idx map[*ir.Node]int32
stkptrsize int64 stkptrsize int64
be []BlockEffects be []BlockEffects
@ -205,20 +206,20 @@ type progeffectscache struct {
// nor do we care about non-local variables, // 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 empty structs (handled by the pointer check),
// nor do we care about the fake PAUTOHEAP variables. // nor do we care about the fake PAUTOHEAP variables.
func livenessShouldTrack(n *Node) bool { func livenessShouldTrack(n *ir.Node) bool {
return n.Op == ONAME && (n.Class() == PAUTO || n.Class() == PPARAM || n.Class() == PPARAMOUT) && n.Type.HasPointers() 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 // getvariables returns the list of on-stack variables that we need to track
// and a map for looking up indices by *Node. // and a map for looking up indices by *Node.
func getvariables(fn *Node) ([]*Node, map[*Node]int32) { func getvariables(fn *ir.Node) ([]*ir.Node, map[*ir.Node]int32) {
var vars []*Node var vars []*ir.Node
for _, n := range fn.Func.Dcl { for _, n := range fn.Func.Dcl {
if livenessShouldTrack(n) { if livenessShouldTrack(n) {
vars = append(vars, 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 { for i, n := range vars {
idx[n] = int32(i) idx[n] = int32(i)
} }
@ -234,7 +235,7 @@ func (lv *Liveness) initcache() {
for i, node := range lv.vars { for i, node := range lv.vars {
switch node.Class() { switch node.Class() {
case PPARAM: case ir.PPARAM:
// A return instruction with a p.to is a tail return, which brings // 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 // the stack pointer back up (if it ever went down) and then jumps
// to a new function entirely. That form of instruction must read // to a new function entirely. That form of instruction must read
@ -243,7 +244,7 @@ func (lv *Liveness) initcache() {
// function runs. // function runs.
lv.cache.tailuevar = append(lv.cache.tailuevar, int32(i)) lv.cache.tailuevar = append(lv.cache.tailuevar, int32(i))
case PPARAMOUT: case ir.PPARAMOUT:
// All results are live at every return point. // All results are live at every return point.
// Note that this point is after escaping return values // Note that this point is after escaping return values
// are copied back to the stack using their PAUTOHEAP references. // are copied back to the stack using their PAUTOHEAP references.
@ -271,7 +272,7 @@ const (
// If v does not affect any tracked variables, it returns -1, 0. // If v does not affect any tracked variables, it returns -1, 0.
func (lv *Liveness) valueEffects(v *ssa.Value) (int32, liveEffect) { func (lv *Liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
n, e := affectedNode(v) 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 return -1, 0
} }
@ -311,7 +312,7 @@ func (lv *Liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
} }
// affectedNode returns the *Node affected by v // 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. // Special cases.
switch v.Op { switch v.Op {
case ssa.OpLoadReg: case ssa.OpLoadReg:
@ -322,9 +323,9 @@ func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
return n, ssa.SymWrite return n, ssa.SymWrite
case ssa.OpVarLive: case ssa.OpVarLive:
return v.Aux.(*Node), ssa.SymRead return v.Aux.(*ir.Node), ssa.SymRead
case ssa.OpVarDef, ssa.OpVarKill: case ssa.OpVarDef, ssa.OpVarKill:
return v.Aux.(*Node), ssa.SymWrite return v.Aux.(*ir.Node), ssa.SymWrite
case ssa.OpKeepAlive: case ssa.OpKeepAlive:
n, _ := AutoVar(v.Args[0]) n, _ := AutoVar(v.Args[0])
return n, ssa.SymRead return n, ssa.SymRead
@ -339,7 +340,7 @@ func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
case nil, *obj.LSym: case nil, *obj.LSym:
// ok, but no node // ok, but no node
return nil, e return nil, e
case *Node: case *ir.Node:
return a, e return a, e
default: default:
base.Fatalf("weird aux: %s", v.LongString()) base.Fatalf("weird aux: %s", v.LongString())
@ -355,7 +356,7 @@ type livenessFuncCache struct {
// Constructs a new liveness structure used to hold the global state of the // 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 // liveness computation. The cfg argument is a slice of *BasicBlocks and the
// vars argument is a slice of *Nodes. // 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{ lv := &Liveness{
fn: fn, fn: fn,
f: f, f: f,
@ -416,20 +417,20 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
} }
switch t.Etype { 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 { if off&int64(Widthptr-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t) base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
} }
bv.Set(int32(off / int64(Widthptr))) // pointer bv.Set(int32(off / int64(Widthptr))) // pointer
case TSTRING: case types.TSTRING:
// struct { byte *str; intgo len; } // struct { byte *str; intgo len; }
if off&int64(Widthptr-1) != 0 { if off&int64(Widthptr-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t) base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
} }
bv.Set(int32(off / int64(Widthptr))) //pointer in first slot bv.Set(int32(off / int64(Widthptr))) //pointer in first slot
case TINTER: case types.TINTER:
// struct { Itab *tab; void *data; } // struct { Itab *tab; void *data; }
// or, when isnilinter(t)==true: // or, when isnilinter(t)==true:
// struct { Type *type; void *data; } // struct { Type *type; void *data; }
@ -450,14 +451,14 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
// well as scan itabs to update their itab._type fields). // well as scan itabs to update their itab._type fields).
bv.Set(int32(off/int64(Widthptr) + 1)) // pointer in second slot bv.Set(int32(off/int64(Widthptr) + 1)) // pointer in second slot
case TSLICE: case types.TSLICE:
// struct { byte *array; uintgo len; uintgo cap; } // struct { byte *array; uintgo len; uintgo cap; }
if off&int64(Widthptr-1) != 0 { if off&int64(Widthptr-1) != 0 {
base.Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t) base.Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
} }
bv.Set(int32(off / int64(Widthptr))) // pointer in first slot (BitsPointer) bv.Set(int32(off / int64(Widthptr))) // pointer in first slot (BitsPointer)
case TARRAY: case types.TARRAY:
elt := t.Elem() elt := t.Elem()
if elt.Width == 0 { if elt.Width == 0 {
// Short-circuit for #20739. // Short-circuit for #20739.
@ -468,7 +469,7 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
off += elt.Width off += elt.Width
} }
case TSTRUCT: case types.TSTRUCT:
for _, f := range t.Fields().Slice() { for _, f := range t.Fields().Slice() {
onebitwalktype1(f.Type, off+f.Offset, bv) onebitwalktype1(f.Type, off+f.Offset, bv)
} }
@ -481,7 +482,7 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
// Generates live pointer value maps for arguments and local variables. The // Generates live pointer value maps for arguments and local variables. The
// this argument and the in arguments are always assumed live. The vars // this argument and the in arguments are always assumed live. The vars
// argument is a slice of *Nodes. // 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++ { for i := int32(0); ; i++ {
i = liveout.Next(i) i = liveout.Next(i)
if i < 0 { if i < 0 {
@ -489,10 +490,10 @@ func (lv *Liveness) pointerMap(liveout bvec, vars []*Node, args, locals bvec) {
} }
node := vars[i] node := vars[i]
switch node.Class() { switch node.Class() {
case PAUTO: case ir.PAUTO:
onebitwalktype1(node.Type, node.Xoffset+lv.stkptrsize, locals) onebitwalktype1(node.Type, node.Xoffset+lv.stkptrsize, locals)
case PPARAM, PPARAMOUT: case ir.PPARAM, ir.PPARAMOUT:
onebitwalktype1(node.Type, node.Xoffset, args) onebitwalktype1(node.Type, node.Xoffset, args)
} }
} }
@ -789,7 +790,7 @@ func (lv *Liveness) epilogue() {
// don't need to keep the stack copy live? // don't need to keep the stack copy live?
if lv.fn.Func.HasDefer() { if lv.fn.Func.HasDefer() {
for i, n := range lv.vars { for i, n := range lv.vars {
if n.Class() == PPARAMOUT { if n.Class() == ir.PPARAMOUT {
if n.Name.IsOutputParamHeapAddr() { if n.Name.IsOutputParamHeapAddr() {
// Just to be paranoid. Heap addresses are PAUTOs. // Just to be paranoid. Heap addresses are PAUTOs.
base.Fatalf("variable %v both output param and heap output param", n) base.Fatalf("variable %v both output param and heap output param", n)
@ -887,7 +888,7 @@ func (lv *Liveness) epilogue() {
if !liveout.Get(int32(i)) { if !liveout.Get(int32(i)) {
continue continue
} }
if n.Class() == PPARAM { if n.Class() == ir.PPARAM {
continue // ok continue // ok
} }
base.Fatalf("bad live variable at entry of %v: %L", lv.fn.Func.Nname, n) base.Fatalf("bad live variable at entry of %v: %L", lv.fn.Func.Nname, n)
@ -920,7 +921,7 @@ func (lv *Liveness) epilogue() {
// the only things that can possibly be live are the // the only things that can possibly be live are the
// input parameters. // input parameters.
for j, n := range lv.vars { 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) lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Func.Nname, n)
} }
} }
@ -967,7 +968,7 @@ func (lv *Liveness) compact(b *ssa.Block) {
} }
func (lv *Liveness) showlive(v *ssa.Value, live bvec) { 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 return
} }
if !(v == nil || v.Op.IsCall()) { if !(v == nil || v.Op.IsCall()) {
@ -986,7 +987,7 @@ func (lv *Liveness) showlive(v *ssa.Value, live bvec) {
s := "live at " s := "live at "
if v == nil { 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 { } else if sym, ok := v.Aux.(*ssa.AuxCall); ok && sym.Fn != nil {
fn := sym.Fn.Name fn := sym.Fn.Name
if pos := strings.Index(fn, "."); pos >= 0 { if pos := strings.Index(fn, "."); pos >= 0 {
@ -1051,7 +1052,7 @@ func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool) bo
// This format synthesizes the information used during the multiple passes // This format synthesizes the information used during the multiple passes
// into a single presentation. // into a single presentation.
func (lv *Liveness) printDebug() { 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 { for i, b := range lv.f.Blocks {
if i > 0 { if i > 0 {
@ -1163,10 +1164,10 @@ func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) {
// Size args bitmaps to be just large enough to hold the largest pointer. // Size args bitmaps to be just large enough to hold the largest pointer.
// First, find the largest Xoffset node we care about. // First, find the largest Xoffset node we care about.
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.) // (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
var maxArgNode *Node var maxArgNode *ir.Node
for _, n := range lv.vars { for _, n := range lv.vars {
switch n.Class() { switch n.Class() {
case PPARAM, PPARAMOUT: case ir.PPARAM, ir.PPARAMOUT:
if maxArgNode == nil || n.Xoffset > maxArgNode.Xoffset { if maxArgNode == nil || n.Xoffset > maxArgNode.Xoffset {
maxArgNode = n maxArgNode = n
} }
@ -1265,7 +1266,7 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
} }
// Emit the live pointer map data structures // Emit the live pointer map data structures
ls := e.curfn.Func.lsym ls := e.curfn.Func.LSym
fninfo := ls.Func() fninfo := ls.Func()
fninfo.GCArgs, fninfo.GCLocals = lv.emit() fninfo.GCArgs, fninfo.GCLocals = lv.emit()
@ -1300,16 +1301,16 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
func isfat(t *types.Type) bool { func isfat(t *types.Type) bool {
if t != nil { if t != nil {
switch t.Etype { switch t.Etype {
case TSLICE, TSTRING, case types.TSLICE, types.TSTRING,
TINTER: // maybe remove later types.TINTER: // maybe remove later
return true return true
case TARRAY: case types.TARRAY:
// Array of 1 element, check if element is fat // Array of 1 element, check if element is fat
if t.NumElem() == 1 { if t.NumElem() == 1 {
return isfat(t.Elem()) return isfat(t.Elem())
} }
return true return true
case TSTRUCT: case types.TSTRUCT:
// Struct with 1 field, check if field is fat // Struct with 1 field, check if field is fat
if t.NumFields() == 1 { if t.NumFields() == 1 {
return isfat(t.Field(0).Type) return isfat(t.Field(0).Type)

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src" "cmd/internal/src"
"cmd/internal/sys" "cmd/internal/sys"
@ -59,8 +60,8 @@ func ispkgin(pkgs []string) bool {
return false return false
} }
func instrument(fn *Node) { func instrument(fn *ir.Node) {
if fn.Func.Pragma&Norace != 0 { if fn.Func.Pragma&ir.Norace != 0 {
return return
} }
@ -82,8 +83,8 @@ func instrument(fn *Node) {
// This only works for amd64. This will not // This only works for amd64. This will not
// work on arm or others that might support // work on arm or others that might support
// race in the future. // race in the future.
nodpc := nodfp.copy() nodpc := ir.Copy(nodfp)
nodpc.Type = types.Types[TUINTPTR] nodpc.Type = types.Types[types.TUINTPTR]
nodpc.Xoffset = int64(-Widthptr) nodpc.Xoffset = int64(-Widthptr)
fn.Func.Dcl = append(fn.Func.Dcl, nodpc) fn.Func.Dcl = append(fn.Func.Dcl, nodpc)
fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc)) fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc))

View file

@ -6,13 +6,14 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/sys" "cmd/internal/sys"
"unicode/utf8" "unicode/utf8"
) )
// range // range
func typecheckrange(n *Node) { func typecheckrange(n *ir.Node) {
// Typechecking order is important here: // Typechecking order is important here:
// 0. first typecheck range expression (slice/map/chan), // 0. first typecheck range expression (slice/map/chan),
// it is evaluated only once and so logically it is not part of the loop. // it is evaluated only once and so logically it is not part of the loop.
@ -38,7 +39,7 @@ func typecheckrange(n *Node) {
decldepth-- decldepth--
} }
func typecheckrangeExpr(n *Node) { func typecheckrangeExpr(n *ir.Node) {
n.Right = typecheck(n.Right, ctxExpr) n.Right = typecheck(n.Right, ctxExpr)
t := n.Right.Type t := n.Right.Type
@ -65,15 +66,15 @@ func typecheckrangeExpr(n *Node) {
base.ErrorfAt(n.Pos, "cannot range over %L", n.Right) base.ErrorfAt(n.Pos, "cannot range over %L", n.Right)
return return
case TARRAY, TSLICE: case types.TARRAY, types.TSLICE:
t1 = types.Types[TINT] t1 = types.Types[types.TINT]
t2 = t.Elem() t2 = t.Elem()
case TMAP: case types.TMAP:
t1 = t.Key() t1 = t.Key()
t2 = t.Elem() t2 = t.Elem()
case TCHAN: case types.TCHAN:
if !t.ChanDir().CanRecv() { if !t.ChanDir().CanRecv() {
base.ErrorfAt(n.Pos, "invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type) base.ErrorfAt(n.Pos, "invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
return return
@ -85,8 +86,8 @@ func typecheckrangeExpr(n *Node) {
toomany = true toomany = true
} }
case TSTRING: case types.TSTRING:
t1 = types.Types[TINT] t1 = types.Types[types.TINT]
t2 = types.Runetype t2 = types.Runetype
} }
@ -94,7 +95,7 @@ func typecheckrangeExpr(n *Node) {
base.ErrorfAt(n.Pos, "too many variables in range") base.ErrorfAt(n.Pos, "too many variables in range")
} }
var v1, v2 *Node var v1, v2 *ir.Node
if n.List.Len() != 0 { if n.List.Len() != 0 {
v1 = n.List.First() v1 = n.List.First()
} }
@ -106,7 +107,7 @@ func typecheckrangeExpr(n *Node) {
// "if the second iteration variable is the blank identifier, the range // "if the second iteration variable is the blank identifier, the range
// clause is equivalent to the same clause with only the first variable // clause is equivalent to the same clause with only the first variable
// present." // present."
if v2.isBlank() { if ir.IsBlank(v2) {
if v1 != nil { if v1 != nil {
n.List.Set1(v1) n.List.Set1(v1)
} }
@ -117,7 +118,7 @@ func typecheckrangeExpr(n *Node) {
if v1.Name != nil && v1.Name.Defn == n { if v1.Name != nil && v1.Name.Defn == n {
v1.Type = t1 v1.Type = t1
} else if v1.Type != nil { } 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) base.ErrorfAt(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
} }
} }
@ -128,7 +129,7 @@ func typecheckrangeExpr(n *Node) {
if v2.Name != nil && v2.Name.Defn == n { if v2.Name != nil && v2.Name.Defn == n {
v2.Type = t2 v2.Type = t2
} else if v2.Type != nil { } 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) base.ErrorfAt(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
} }
} }
@ -156,7 +157,7 @@ func cheapComputableIndex(width int64) bool {
// simpler forms. The result must be assigned back to n. // simpler forms. The result must be assigned back to n.
// Node n may also be modified in place, and may also be // Node n may also be modified in place, and may also be
// the returned node. // the returned node.
func walkrange(n *Node) *Node { func walkrange(n *ir.Node) *ir.Node {
if isMapClear(n) { if isMapClear(n) {
m := n.Right m := n.Right
lno := setlineno(m) lno := setlineno(m)
@ -178,7 +179,7 @@ func walkrange(n *Node) *Node {
lno := setlineno(a) lno := setlineno(a)
n.Right = nil n.Right = nil
var v1, v2 *Node var v1, v2 *ir.Node
l := n.List.Len() l := n.List.Len()
if l > 0 { if l > 0 {
v1 = n.List.First() v1 = n.List.First()
@ -188,11 +189,11 @@ func walkrange(n *Node) *Node {
v2 = n.List.Second() v2 = n.List.Second()
} }
if v2.isBlank() { if ir.IsBlank(v2) {
v2 = nil v2 = nil
} }
if v1.isBlank() && v2 == nil { if ir.IsBlank(v1) && v2 == nil {
v1 = nil v1 = nil
} }
@ -204,17 +205,17 @@ func walkrange(n *Node) *Node {
// to avoid erroneous processing by racewalk. // to avoid erroneous processing by racewalk.
n.List.Set(nil) n.List.Set(nil)
var ifGuard *Node var ifGuard *ir.Node
translatedLoopOp := OFOR translatedLoopOp := ir.OFOR
var body []*Node var body []*ir.Node
var init []*Node var init []*ir.Node
switch t.Etype { switch t.Etype {
default: default:
base.Fatalf("walkrange") base.Fatalf("walkrange")
case TARRAY, TSLICE: case types.TARRAY, types.TSLICE:
if arrayClear(n, v1, v2, a) { if arrayClear(n, v1, v2, a) {
base.Pos = lno base.Pos = lno
return n return n
@ -223,14 +224,14 @@ func walkrange(n *Node) *Node {
// order.stmt arranged for a copy of the array/slice variable if needed. // order.stmt arranged for a copy of the array/slice variable if needed.
ha := a ha := a
hv1 := temp(types.Types[TINT]) hv1 := temp(types.Types[types.TINT])
hn := temp(types.Types[TINT]) hn := temp(types.Types[types.TINT])
init = append(init, nod(OAS, hv1, nil)) init = append(init, ir.Nod(ir.OAS, hv1, nil))
init = append(init, nod(OAS, hn, nod(OLEN, ha, nil))) init = append(init, ir.Nod(ir.OAS, hn, ir.Nod(ir.OLEN, ha, nil)))
n.Left = nod(OLT, hv1, hn) n.Left = ir.Nod(ir.OLT, hv1, hn)
n.Right = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))) n.Right = ir.Nod(ir.OAS, hv1, ir.Nod(ir.OADD, hv1, nodintconst(1)))
// for range ha { body } // for range ha { body }
if v1 == nil { if v1 == nil {
@ -239,21 +240,21 @@ func walkrange(n *Node) *Node {
// for v1 := range ha { body } // for v1 := range ha { body }
if v2 == nil { if v2 == nil {
body = []*Node{nod(OAS, v1, hv1)} body = []*ir.Node{ir.Nod(ir.OAS, v1, hv1)}
break break
} }
// for v1, v2 := range ha { body } // for v1, v2 := range ha { body }
if cheapComputableIndex(n.Type.Elem().Width) { if cheapComputableIndex(n.Type.Elem().Width) {
// v1, v2 = hv1, ha[hv1] // v1, v2 = hv1, ha[hv1]
tmp := nod(OINDEX, ha, hv1) tmp := ir.Nod(ir.OINDEX, ha, hv1)
tmp.SetBounded(true) tmp.SetBounded(true)
// Use OAS2 to correctly handle assignments // Use OAS2 to correctly handle assignments
// of the form "v1, a[v1] := range". // 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.List.Set2(v1, v2)
a.Rlist.Set2(hv1, tmp) a.Rlist.Set2(hv1, tmp)
body = []*Node{a} body = []*ir.Node{a}
break break
} }
@ -269,20 +270,20 @@ func walkrange(n *Node) *Node {
// TODO(austin): OFORUNTIL inhibits bounds-check // TODO(austin): OFORUNTIL inhibits bounds-check
// elimination on the index variable (see #20711). // elimination on the index variable (see #20711).
// Enhance the prove pass to understand this. // Enhance the prove pass to understand this.
ifGuard = nod(OIF, nil, nil) ifGuard = ir.Nod(ir.OIF, nil, nil)
ifGuard.Left = nod(OLT, hv1, hn) ifGuard.Left = ir.Nod(ir.OLT, hv1, hn)
translatedLoopOp = OFORUNTIL translatedLoopOp = ir.OFORUNTIL
hp := temp(types.NewPtr(n.Type.Elem())) hp := temp(types.NewPtr(n.Type.Elem()))
tmp := nod(OINDEX, ha, nodintconst(0)) tmp := ir.Nod(ir.OINDEX, ha, nodintconst(0))
tmp.SetBounded(true) 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 // Use OAS2 to correctly handle assignments
// of the form "v1, a[v1] := range". // 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.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) body = append(body, a)
// Advance pointer as part of the late increment. // Advance pointer as part of the late increment.
@ -290,11 +291,11 @@ func walkrange(n *Node) *Node {
// This runs *after* the condition check, so we know // This runs *after* the condition check, so we know
// advancing the pointer is safe and won't go past the // advancing the pointer is safe and won't go past the
// end of the allocation. // 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) a = typecheck(a, ctxStmt)
n.List.Set1(a) n.List.Set1(a)
case TMAP: case types.TMAP:
// order.stmt allocated the iterator for us. // order.stmt allocated the iterator for us.
// we only use a once, so no copy needed. // we only use a once, so no copy needed.
ha := a ha := a
@ -308,29 +309,29 @@ func walkrange(n *Node) *Node {
fn := syslook("mapiterinit") fn := syslook("mapiterinit")
fn = substArgTypes(fn, t.Key(), t.Elem(), th) fn = substArgTypes(fn, t.Key(), t.Elem(), th)
init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nod(OADDR, hit, nil))) init = append(init, mkcall1(fn, nil, nil, typename(t), ha, ir.Nod(ir.OADDR, hit, nil)))
n.Left = nod(ONE, nodSym(ODOT, hit, keysym), nodnil()) n.Left = ir.Nod(ir.ONE, nodSym(ir.ODOT, hit, keysym), nodnil())
fn = syslook("mapiternext") fn = syslook("mapiternext")
fn = substArgTypes(fn, th) 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 := nodSym(ir.ODOT, hit, keysym)
key = nod(ODEREF, key, nil) key = ir.Nod(ir.ODEREF, key, nil)
if v1 == nil { if v1 == nil {
body = nil body = nil
} else if v2 == nil { } else if v2 == nil {
body = []*Node{nod(OAS, v1, key)} body = []*ir.Node{ir.Nod(ir.OAS, v1, key)}
} else { } else {
elem := nodSym(ODOT, hit, elemsym) elem := nodSym(ir.ODOT, hit, elemsym)
elem = nod(ODEREF, elem, nil) elem = ir.Nod(ir.ODEREF, elem, nil)
a := nod(OAS2, nil, nil) a := ir.Nod(ir.OAS2, nil, nil)
a.List.Set2(v1, v2) a.List.Set2(v1, v2)
a.Rlist.Set2(key, elem) 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. // order.stmt arranged for a copy of the channel variable.
ha := a ha := a
@ -339,27 +340,27 @@ func walkrange(n *Node) *Node {
hv1 := temp(t.Elem()) hv1 := temp(t.Elem())
hv1.SetTypecheck(1) hv1.SetTypecheck(1)
if t.Elem().HasPointers() { 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)) n.Left = ir.Nod(ir.ONE, hb, nodbool(false))
a := nod(OAS2RECV, nil, nil) a := ir.Nod(ir.OAS2RECV, nil, nil)
a.SetTypecheck(1) a.SetTypecheck(1)
a.List.Set2(hv1, hb) a.List.Set2(hv1, hb)
a.Right = nod(ORECV, ha, nil) a.Right = ir.Nod(ir.ORECV, ha, nil)
n.Left.Ninit.Set1(a) n.Left.Ninit.Set1(a)
if v1 == nil { if v1 == nil {
body = nil body = nil
} else { } 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 // Zero hv1. This prevents hv1 from being the sole, inaccessible
// reference to an otherwise GC-able value during the next channel receive. // reference to an otherwise GC-able value during the next channel receive.
// See issue 15281. // 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 // Transform string range statements like "for v1, v2 = range a" into
// //
// ha := a // ha := a
@ -378,35 +379,35 @@ func walkrange(n *Node) *Node {
// order.stmt arranged for a copy of the string variable. // order.stmt arranged for a copy of the string variable.
ha := a ha := a
hv1 := temp(types.Types[TINT]) hv1 := temp(types.Types[types.TINT])
hv1t := temp(types.Types[TINT]) hv1t := temp(types.Types[types.TINT])
hv2 := temp(types.Runetype) hv2 := temp(types.Runetype)
// hv1 := 0 // hv1 := 0
init = append(init, nod(OAS, hv1, nil)) init = append(init, ir.Nod(ir.OAS, hv1, nil))
// hv1 < len(ha) // 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 { if v1 != nil {
// hv1t = hv1 // hv1t = hv1
body = append(body, nod(OAS, hv1t, hv1)) body = append(body, ir.Nod(ir.OAS, hv1t, hv1))
} }
// hv2 := rune(ha[hv1]) // hv2 := rune(ha[hv1])
nind := nod(OINDEX, ha, hv1) nind := ir.Nod(ir.OINDEX, ha, hv1)
nind.SetBounded(true) 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 // if hv2 < utf8.RuneSelf
nif := nod(OIF, nil, nil) nif := ir.Nod(ir.OIF, nil, nil)
nif.Left = nod(OLT, hv2, nodintconst(utf8.RuneSelf)) nif.Left = ir.Nod(ir.OLT, hv2, nodintconst(utf8.RuneSelf))
// hv1++ // 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 { // } else {
eif := nod(OAS2, nil, nil) eif := ir.Nod(ir.OAS2, nil, nil)
nif.Rlist.Set1(eif) nif.Rlist.Set1(eif)
// hv2, hv1 = decoderune(ha, hv1) // hv2, hv1 = decoderune(ha, hv1)
@ -419,13 +420,13 @@ func walkrange(n *Node) *Node {
if v1 != nil { if v1 != nil {
if v2 != nil { if v2 != nil {
// v1, v2 = hv1t, hv2 // v1, v2 = hv1t, hv2
a := nod(OAS2, nil, nil) a := ir.Nod(ir.OAS2, nil, nil)
a.List.Set2(v1, v2) a.List.Set2(v1, v2)
a.Rlist.Set2(hv1t, hv2) a.Rlist.Set2(hv1t, hv2)
body = append(body, a) body = append(body, a)
} else { } else {
// v1 = hv1t // v1 = hv1t
body = append(body, nod(OAS, v1, hv1t)) body = append(body, ir.Nod(ir.OAS, v1, hv1t))
} }
} }
} }
@ -466,17 +467,17 @@ func walkrange(n *Node) *Node {
// } // }
// //
// where == for keys of map m is reflexive. // 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 { if base.Flag.N != 0 || instrumenting {
return false 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 return false
} }
k := n.List.First() k := n.List.First()
if k == nil || k.isBlank() { if k == nil || ir.IsBlank(k) {
return false return false
} }
@ -490,7 +491,7 @@ func isMapClear(n *Node) bool {
} }
stmt := n.Nbody.First() // only stmt in body stmt := n.Nbody.First() // only stmt in body
if stmt == nil || stmt.Op != ODELETE { if stmt == nil || stmt.Op != ir.ODELETE {
return false return false
} }
@ -508,7 +509,7 @@ func isMapClear(n *Node) bool {
} }
// mapClear constructs a call to runtime.mapclear for the map m. // 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 t := m.Type
// instantiate mapclear(typ *type, hmap map[any]any) // instantiate mapclear(typ *type, hmap map[any]any)
@ -533,7 +534,7 @@ func mapClear(m *Node) *Node {
// in which the evaluation of a is side-effect-free. // in which the evaluation of a is side-effect-free.
// //
// Parameters are as in walkrange: "for v1, v2 = range a". // 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 { if base.Flag.N != 0 || instrumenting {
return false return false
} }
@ -547,7 +548,7 @@ func arrayClear(n, v1, v2, a *Node) bool {
} }
stmt := n.Nbody.First() // only stmt in body 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 return false
} }
@ -567,32 +568,32 @@ func arrayClear(n, v1, v2, a *Node) bool {
// memclr{NoHeap,Has}Pointers(hp, hn) // memclr{NoHeap,Has}Pointers(hp, hn)
// i = len(a) - 1 // i = len(a) - 1
// } // }
n.Op = OIF n.Op = ir.OIF
n.Nbody.Set(nil) 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 = &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.SetBounded(true)
tmp = nod(OADDR, tmp, nil) tmp = ir.Nod(ir.OADDR, tmp, nil)
tmp = convnop(tmp, types.Types[TUNSAFEPTR]) tmp = convnop(tmp, types.Types[types.TUNSAFEPTR])
n.Nbody.Append(nod(OAS, hp, tmp)) n.Nbody.Append(ir.Nod(ir.OAS, hp, tmp))
// hn = len(a) * sizeof(elem(a)) // hn = len(a) * sizeof(elem(a))
hn := temp(types.Types[TUINTPTR]) hn := temp(types.Types[types.TUINTPTR])
tmp = nod(OLEN, a, nil) tmp = ir.Nod(ir.OLEN, a, nil)
tmp = nod(OMUL, tmp, nodintconst(elemsize)) tmp = ir.Nod(ir.OMUL, tmp, nodintconst(elemsize))
tmp = conv(tmp, types.Types[TUINTPTR]) tmp = conv(tmp, types.Types[types.TUINTPTR])
n.Nbody.Append(nod(OAS, hn, tmp)) n.Nbody.Append(ir.Nod(ir.OAS, hn, tmp))
var fn *Node var fn *ir.Node
if a.Type.Elem().HasPointers() { if a.Type.Elem().HasPointers() {
// memclrHasPointers(hp, hn) // memclrHasPointers(hp, hn)
Curfn.Func.setWBPos(stmt.Pos) Curfn.Func.SetWBPos(stmt.Pos)
fn = mkcall("memclrHasPointers", nil, nil, hp, hn) fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
} else { } else {
// memclrNoHeapPointers(hp, hn) // memclrNoHeapPointers(hp, hn)
@ -602,7 +603,7 @@ func arrayClear(n, v1, v2, a *Node) bool {
n.Nbody.Append(fn) n.Nbody.Append(fn)
// i = len(a) - 1 // 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) n.Nbody.Append(v1)
@ -614,15 +615,15 @@ func arrayClear(n, v1, v2, a *Node) bool {
} }
// addptr returns (*T)(uintptr(p) + n). // 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 t := p.Type
p = nod(OCONVNOP, p, nil) p = ir.Nod(ir.OCONVNOP, p, nil)
p.Type = types.Types[TUINTPTR] 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 p.Type = t
return p return p

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/gcprog" "cmd/internal/gcprog"
"cmd/internal/obj" "cmd/internal/obj"
@ -84,7 +85,7 @@ func bmap(t *types.Type) *types.Type {
return t.MapType().Bucket return t.MapType().Bucket
} }
bucket := types.New(TSTRUCT) bucket := types.New(types.TSTRUCT)
keytype := t.Key() keytype := t.Key()
elemtype := t.Elem() elemtype := t.Elem()
dowidth(keytype) dowidth(keytype)
@ -99,7 +100,7 @@ func bmap(t *types.Type) *types.Type {
field := make([]*types.Field, 0, 5) field := make([]*types.Field, 0, 5)
// The first field is: uint8 topbits[BUCKETSIZE]. // 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)) field = append(field, makefield("topbits", arr))
arr = types.NewArray(keytype, BUCKETSIZE) arr = types.NewArray(keytype, BUCKETSIZE)
@ -120,7 +121,7 @@ func bmap(t *types.Type) *types.Type {
// See comment on hmap.overflow in runtime/map.go. // See comment on hmap.overflow in runtime/map.go.
otyp := types.NewPtr(bucket) otyp := types.NewPtr(bucket)
if !elemtype.HasPointers() && !keytype.HasPointers() { if !elemtype.HasPointers() && !keytype.HasPointers() {
otyp = types.Types[TUINTPTR] otyp = types.Types[types.TUINTPTR]
} }
overflow := makefield("overflow", otyp) overflow := makefield("overflow", otyp)
field = append(field, overflow) field = append(field, overflow)
@ -209,18 +210,18 @@ func hmap(t *types.Type) *types.Type {
// } // }
// must match runtime/map.go:hmap. // must match runtime/map.go:hmap.
fields := []*types.Field{ fields := []*types.Field{
makefield("count", types.Types[TINT]), makefield("count", types.Types[types.TINT]),
makefield("flags", types.Types[TUINT8]), makefield("flags", types.Types[types.TUINT8]),
makefield("B", types.Types[TUINT8]), makefield("B", types.Types[types.TUINT8]),
makefield("noverflow", types.Types[TUINT16]), makefield("noverflow", types.Types[types.TUINT16]),
makefield("hash0", types.Types[TUINT32]), // Used in walk.go for OMAKEMAP. makefield("hash0", types.Types[types.TUINT32]), // Used in walk.go for OMAKEMAP.
makefield("buckets", types.NewPtr(bmap)), // Used in walk.go for OMAKEMAP. makefield("buckets", types.NewPtr(bmap)), // Used in walk.go for OMAKEMAP.
makefield("oldbuckets", types.NewPtr(bmap)), makefield("oldbuckets", types.NewPtr(bmap)),
makefield("nevacuate", types.Types[TUINTPTR]), makefield("nevacuate", types.Types[types.TUINTPTR]),
makefield("extra", types.Types[TUNSAFEPTR]), makefield("extra", types.Types[types.TUNSAFEPTR]),
} }
hmap := types.New(TSTRUCT) hmap := types.New(types.TSTRUCT)
hmap.SetNoalg(true) hmap.SetNoalg(true)
hmap.SetFields(fields) hmap.SetFields(fields)
dowidth(hmap) dowidth(hmap)
@ -268,23 +269,23 @@ func hiter(t *types.Type) *types.Type {
fields := []*types.Field{ fields := []*types.Field{
makefield("key", types.NewPtr(t.Key())), // Used in range.go for TMAP. 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("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("h", types.NewPtr(hmap)),
makefield("buckets", types.NewPtr(bmap)), makefield("buckets", types.NewPtr(bmap)),
makefield("bptr", types.NewPtr(bmap)), makefield("bptr", types.NewPtr(bmap)),
makefield("overflow", types.Types[TUNSAFEPTR]), makefield("overflow", types.Types[types.TUNSAFEPTR]),
makefield("oldoverflow", types.Types[TUNSAFEPTR]), makefield("oldoverflow", types.Types[types.TUNSAFEPTR]),
makefield("startBucket", types.Types[TUINTPTR]), makefield("startBucket", types.Types[types.TUINTPTR]),
makefield("offset", types.Types[TUINT8]), makefield("offset", types.Types[types.TUINT8]),
makefield("wrapped", types.Types[TBOOL]), makefield("wrapped", types.Types[types.TBOOL]),
makefield("B", types.Types[TUINT8]), makefield("B", types.Types[types.TUINT8]),
makefield("i", types.Types[TUINT8]), makefield("i", types.Types[types.TUINT8]),
makefield("bucket", types.Types[TUINTPTR]), makefield("bucket", types.Types[types.TUINTPTR]),
makefield("checkBucket", types.Types[TUINTPTR]), makefield("checkBucket", types.Types[types.TUINTPTR]),
} }
// build iterator struct holding the above fields // build iterator struct holding the above fields
hiter := types.New(TSTRUCT) hiter := types.New(types.TSTRUCT)
hiter.SetNoalg(true) hiter.SetNoalg(true)
hiter.SetFields(fields) hiter.SetFields(fields)
dowidth(hiter) dowidth(hiter)
@ -303,35 +304,35 @@ func deferstruct(stksize int64) *types.Type {
// Unlike the global makefield function, this one needs to set Pkg // Unlike the global makefield function, this one needs to set Pkg
// because these types might be compared (in SSA CSE sorting). // because these types might be compared (in SSA CSE sorting).
// TODO: unify this makefield and the global one above. // 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) 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.Width = stksize
argtype.Align = 1 argtype.Align = 1
// These fields must match the ones in runtime/runtime2.go:_defer and // These fields must match the ones in runtime/runtime2.go:_defer and
// cmd/compile/internal/gc/ssa.go:(*state).call. // cmd/compile/internal/gc/ssa.go:(*state).call.
fields := []*types.Field{ fields := []*types.Field{
makefield("siz", types.Types[TUINT32]), makefield("siz", types.Types[types.TUINT32]),
makefield("started", types.Types[TBOOL]), makefield("started", types.Types[types.TBOOL]),
makefield("heap", types.Types[TBOOL]), makefield("heap", types.Types[types.TBOOL]),
makefield("openDefer", types.Types[TBOOL]), makefield("openDefer", types.Types[types.TBOOL]),
makefield("sp", types.Types[TUINTPTR]), makefield("sp", types.Types[types.TUINTPTR]),
makefield("pc", types.Types[TUINTPTR]), makefield("pc", types.Types[types.TUINTPTR]),
// Note: the types here don't really matter. Defer structures // Note: the types here don't really matter. Defer structures
// are always scanned explicitly during stack copying and GC, // are always scanned explicitly during stack copying and GC,
// so we make them uintptr type even though they are real pointers. // so we make them uintptr type even though they are real pointers.
makefield("fn", types.Types[TUINTPTR]), makefield("fn", types.Types[types.TUINTPTR]),
makefield("_panic", types.Types[TUINTPTR]), makefield("_panic", types.Types[types.TUINTPTR]),
makefield("link", types.Types[TUINTPTR]), makefield("link", types.Types[types.TUINTPTR]),
makefield("framepc", types.Types[TUINTPTR]), makefield("framepc", types.Types[types.TUINTPTR]),
makefield("varp", types.Types[TUINTPTR]), makefield("varp", types.Types[types.TUINTPTR]),
makefield("fd", types.Types[TUINTPTR]), makefield("fd", types.Types[types.TUINTPTR]),
makefield("args", argtype), makefield("args", argtype),
} }
// build struct holding the above fields // build struct holding the above fields
s := types.New(TSTRUCT) s := types.New(types.TSTRUCT)
s.SetNoalg(true) s.SetNoalg(true)
s.SetFields(fields) s.SetFields(fields)
s.Width = widstruct(s, s, 0, 1) s.Width = widstruct(s, s, 0, 1)
@ -346,7 +347,7 @@ func methodfunc(f *types.Type, receiver *types.Type) *types.Type {
if receiver != nil { if receiver != nil {
inLen++ inLen++
} }
in := make([]*Node, 0, inLen) in := make([]*ir.Node, 0, inLen)
if receiver != nil { if receiver != nil {
d := anonfield(receiver) d := anonfield(receiver)
@ -360,7 +361,7 @@ func methodfunc(f *types.Type, receiver *types.Type) *types.Type {
} }
outLen := f.Results().Fields().Len() outLen := f.Results().Fields().Len()
out := make([]*Node, 0, outLen) out := make([]*ir.Node, 0, outLen)
for _, t := range f.Results().Fields().Slice() { for _, t := range f.Results().Fields().Slice() {
d := anonfield(t.Type) d := anonfield(t.Type)
out = append(out, d) out = append(out, d)
@ -447,7 +448,7 @@ func methods(t *types.Type) []*Sig {
func imethods(t *types.Type) []*Sig { func imethods(t *types.Type) []*Sig {
var methods []*Sig var methods []*Sig
for _, f := range t.Fields().Slice() { for _, f := range t.Fields().Slice() {
if f.Type.Etype != TFUNC || f.Sym == nil { if f.Type.Etype != types.TFUNC || f.Sym == nil {
continue continue
} }
if f.Sym.IsBlank() { if f.Sym.IsBlank() {
@ -494,7 +495,7 @@ func dimportpath(p *types.Pkg) {
} }
str := p.Path str := p.Path
if p == localpkg { if p == ir.LocalPkg {
// Note: myimportpath != "", or else dgopkgpath won't call dimportpath. // Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
str = base.Ctxt.Pkgpath str = base.Ctxt.Pkgpath
} }
@ -511,7 +512,7 @@ func dgopkgpath(s *obj.LSym, ot int, pkg *types.Pkg) int {
return duintptr(s, ot, 0) 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 // 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 // (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. // type..importpath.""., which the linker will rewrite using the correct import path.
@ -530,7 +531,7 @@ func dgopkgpathOff(s *obj.LSym, ot int, pkg *types.Pkg) int {
if pkg == nil { if pkg == nil {
return duint32(s, ot, 0) 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 // 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 // (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. // type..importpath.""., which the linker will rewrite using the correct import path.
@ -674,7 +675,7 @@ func typePkg(t *types.Type) *types.Pkg {
tsym := t.Sym tsym := t.Sym
if tsym == nil { if tsym == nil {
switch t.Etype { switch t.Etype {
case TARRAY, TSLICE, TPTR, TCHAN: case types.TARRAY, types.TSLICE, types.TPTR, types.TCHAN:
if t.Elem() != nil { if t.Elem() != nil {
tsym = t.Elem().Sym tsym = t.Elem().Sym
} }
@ -717,32 +718,32 @@ func dmethodptrOff(s *obj.LSym, ot int, x *obj.LSym) int {
} }
var kinds = []int{ var kinds = []int{
TINT: objabi.KindInt, types.TINT: objabi.KindInt,
TUINT: objabi.KindUint, types.TUINT: objabi.KindUint,
TINT8: objabi.KindInt8, types.TINT8: objabi.KindInt8,
TUINT8: objabi.KindUint8, types.TUINT8: objabi.KindUint8,
TINT16: objabi.KindInt16, types.TINT16: objabi.KindInt16,
TUINT16: objabi.KindUint16, types.TUINT16: objabi.KindUint16,
TINT32: objabi.KindInt32, types.TINT32: objabi.KindInt32,
TUINT32: objabi.KindUint32, types.TUINT32: objabi.KindUint32,
TINT64: objabi.KindInt64, types.TINT64: objabi.KindInt64,
TUINT64: objabi.KindUint64, types.TUINT64: objabi.KindUint64,
TUINTPTR: objabi.KindUintptr, types.TUINTPTR: objabi.KindUintptr,
TFLOAT32: objabi.KindFloat32, types.TFLOAT32: objabi.KindFloat32,
TFLOAT64: objabi.KindFloat64, types.TFLOAT64: objabi.KindFloat64,
TBOOL: objabi.KindBool, types.TBOOL: objabi.KindBool,
TSTRING: objabi.KindString, types.TSTRING: objabi.KindString,
TPTR: objabi.KindPtr, types.TPTR: objabi.KindPtr,
TSTRUCT: objabi.KindStruct, types.TSTRUCT: objabi.KindStruct,
TINTER: objabi.KindInterface, types.TINTER: objabi.KindInterface,
TCHAN: objabi.KindChan, types.TCHAN: objabi.KindChan,
TMAP: objabi.KindMap, types.TMAP: objabi.KindMap,
TARRAY: objabi.KindArray, types.TARRAY: objabi.KindArray,
TSLICE: objabi.KindSlice, types.TSLICE: objabi.KindSlice,
TFUNC: objabi.KindFunc, types.TFUNC: objabi.KindFunc,
TCOMPLEX64: objabi.KindComplex64, types.TCOMPLEX64: objabi.KindComplex64,
TCOMPLEX128: objabi.KindComplex128, types.TCOMPLEX128: objabi.KindComplex128,
TUNSAFEPTR: objabi.KindUnsafePointer, types.TUNSAFEPTR: objabi.KindUnsafePointer,
} }
// typeptrdata returns the length in bytes of the prefix of t // typeptrdata returns the length in bytes of the prefix of t
@ -753,32 +754,32 @@ func typeptrdata(t *types.Type) int64 {
} }
switch t.Etype { switch t.Etype {
case TPTR, case types.TPTR,
TUNSAFEPTR, types.TUNSAFEPTR,
TFUNC, types.TFUNC,
TCHAN, types.TCHAN,
TMAP: types.TMAP:
return int64(Widthptr) return int64(Widthptr)
case TSTRING: case types.TSTRING:
// struct { byte *str; intgo len; } // struct { byte *str; intgo len; }
return int64(Widthptr) return int64(Widthptr)
case TINTER: case types.TINTER:
// struct { Itab *tab; void *data; } or // struct { Itab *tab; void *data; } or
// struct { Type *type; void *data; } // struct { Type *type; void *data; }
// Note: see comment in plive.go:onebitwalktype1. // Note: see comment in plive.go:onebitwalktype1.
return 2 * int64(Widthptr) return 2 * int64(Widthptr)
case TSLICE: case types.TSLICE:
// struct { byte *array; uintgo len; uintgo cap; } // struct { byte *array; uintgo len; uintgo cap; }
return int64(Widthptr) return int64(Widthptr)
case TARRAY: case types.TARRAY:
// haspointers already eliminated t.NumElem() == 0. // haspointers already eliminated t.NumElem() == 0.
return (t.NumElem()-1)*t.Elem().Width + typeptrdata(t.Elem()) return (t.NumElem()-1)*t.Elem().Width + typeptrdata(t.Elem())
case TSTRUCT: case types.TSTRUCT:
// Find the last field that has pointers. // Find the last field that has pointers.
var lastPtrField *types.Field var lastPtrField *types.Field
for _, t1 := range t.Fields().Slice() { for _, t1 := range t.Fields().Slice() {
@ -989,38 +990,38 @@ func typenamesym(t *types.Type) *types.Sym {
return s return s
} }
func typename(t *types.Type) *Node { func typename(t *types.Type) *ir.Node {
s := typenamesym(t) s := typenamesym(t)
if s.Def == nil { if s.Def == nil {
n := newnamel(src.NoXPos, s) n := ir.NewNameAt(src.NoXPos, s)
n.Type = types.Types[TUINT8] n.Type = types.Types[types.TUINT8]
n.SetClass(PEXTERN) n.SetClass(ir.PEXTERN)
n.SetTypecheck(1) n.SetTypecheck(1)
s.Def = asTypesNode(n) s.Def = ir.AsTypesNode(n)
} }
n := nod(OADDR, asNode(s.Def), nil) n := ir.Nod(ir.OADDR, ir.AsNode(s.Def), nil)
n.Type = types.NewPtr(asNode(s.Def).Type) n.Type = types.NewPtr(ir.AsNode(s.Def).Type)
n.SetTypecheck(1) n.SetTypecheck(1)
return n 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() { if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
base.Fatalf("itabname(%v, %v)", t, itype) base.Fatalf("itabname(%v, %v)", t, itype)
} }
s := itabpkg.Lookup(t.ShortString() + "," + itype.ShortString()) s := itabpkg.Lookup(t.ShortString() + "," + itype.ShortString())
if s.Def == nil { if s.Def == nil {
n := newname(s) n := NewName(s)
n.Type = types.Types[TUINT8] n.Type = types.Types[types.TUINT8]
n.SetClass(PEXTERN) n.SetClass(ir.PEXTERN)
n.SetTypecheck(1) n.SetTypecheck(1)
s.Def = asTypesNode(n) s.Def = ir.AsTypesNode(n)
itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()}) itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
} }
n := nod(OADDR, asNode(s.Def), nil) n := ir.Nod(ir.OADDR, ir.AsNode(s.Def), nil)
n.Type = types.NewPtr(asNode(s.Def).Type) n.Type = types.NewPtr(ir.AsNode(s.Def).Type)
n.SetTypecheck(1) n.SetTypecheck(1)
return n return n
} }
@ -1029,35 +1030,35 @@ func itabname(t, itype *types.Type) *Node {
// That is, if x==x for all x of type t. // That is, if x==x for all x of type t.
func isreflexive(t *types.Type) bool { func isreflexive(t *types.Type) bool {
switch t.Etype { switch t.Etype {
case TBOOL, case types.TBOOL,
TINT, types.TINT,
TUINT, types.TUINT,
TINT8, types.TINT8,
TUINT8, types.TUINT8,
TINT16, types.TINT16,
TUINT16, types.TUINT16,
TINT32, types.TINT32,
TUINT32, types.TUINT32,
TINT64, types.TINT64,
TUINT64, types.TUINT64,
TUINTPTR, types.TUINTPTR,
TPTR, types.TPTR,
TUNSAFEPTR, types.TUNSAFEPTR,
TSTRING, types.TSTRING,
TCHAN: types.TCHAN:
return true return true
case TFLOAT32, case types.TFLOAT32,
TFLOAT64, types.TFLOAT64,
TCOMPLEX64, types.TCOMPLEX64,
TCOMPLEX128, types.TCOMPLEX128,
TINTER: types.TINTER:
return false return false
case TARRAY: case types.TARRAY:
return isreflexive(t.Elem()) return isreflexive(t.Elem())
case TSTRUCT: case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() { for _, t1 := range t.Fields().Slice() {
if !isreflexive(t1.Type) { if !isreflexive(t1.Type) {
return false return false
@ -1075,19 +1076,19 @@ func isreflexive(t *types.Type) bool {
// need the key to be updated. // need the key to be updated.
func needkeyupdate(t *types.Type) bool { func needkeyupdate(t *types.Type) bool {
switch t.Etype { switch t.Etype {
case TBOOL, TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, case types.TBOOL, types.TINT, types.TUINT, types.TINT8, types.TUINT8, types.TINT16, types.TUINT16, types.TINT32, types.TUINT32,
TINT64, TUINT64, TUINTPTR, TPTR, TUNSAFEPTR, TCHAN: types.TINT64, types.TUINT64, types.TUINTPTR, types.TPTR, types.TUNSAFEPTR, types.TCHAN:
return false return false
case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, // floats and complex can be +0/-0 case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, // floats and complex can be +0/-0
TINTER, types.TINTER,
TSTRING: // strings might have smaller backing stores types.TSTRING: // strings might have smaller backing stores
return true return true
case TARRAY: case types.TARRAY:
return needkeyupdate(t.Elem()) return needkeyupdate(t.Elem())
case TSTRUCT: case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() { for _, t1 := range t.Fields().Slice() {
if needkeyupdate(t1.Type) { if needkeyupdate(t1.Type) {
return true return true
@ -1104,13 +1105,13 @@ func needkeyupdate(t *types.Type) bool {
// hashMightPanic reports whether the hash of a map key of type t might panic. // hashMightPanic reports whether the hash of a map key of type t might panic.
func hashMightPanic(t *types.Type) bool { func hashMightPanic(t *types.Type) bool {
switch t.Etype { switch t.Etype {
case TINTER: case types.TINTER:
return true return true
case TARRAY: case types.TARRAY:
return hashMightPanic(t.Elem()) return hashMightPanic(t.Elem())
case TSTRUCT: case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() { for _, t1 := range t.Fields().Slice() {
if hashMightPanic(t1.Type) { if hashMightPanic(t1.Type) {
return true return true
@ -1161,7 +1162,7 @@ func dtypesym(t *types.Type) *obj.LSym {
if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Etype] && tbase != types.Bytetype && tbase != types.Runetype && tbase != types.Errortype) { // int, float, etc 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 // 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 { if i, ok := typeSymIdx[tbase]; ok {
lsym.Pkg = tbase.Sym.Pkg.Prefix lsym.Pkg = tbase.Sym.Pkg.Prefix
if t != tbase { if t != tbase {
@ -1174,7 +1175,7 @@ func dtypesym(t *types.Type) *obj.LSym {
return lsym return lsym
} }
// TODO(mdempsky): Investigate whether this can happen. // TODO(mdempsky): Investigate whether this can happen.
if tbase.Etype == TFORW { if tbase.Etype == types.TFORW {
return lsym return lsym
} }
} }
@ -1185,7 +1186,7 @@ func dtypesym(t *types.Type) *obj.LSym {
ot = dcommontype(lsym, t) ot = dcommontype(lsym, t)
ot = dextratype(lsym, ot, t, 0) ot = dextratype(lsym, ot, t, 0)
case TARRAY: case types.TARRAY:
// ../../../../runtime/type.go:/arrayType // ../../../../runtime/type.go:/arrayType
s1 := dtypesym(t.Elem()) s1 := dtypesym(t.Elem())
t2 := types.NewSlice(t.Elem()) t2 := types.NewSlice(t.Elem())
@ -1196,14 +1197,14 @@ func dtypesym(t *types.Type) *obj.LSym {
ot = duintptr(lsym, ot, uint64(t.NumElem())) ot = duintptr(lsym, ot, uint64(t.NumElem()))
ot = dextratype(lsym, ot, t, 0) ot = dextratype(lsym, ot, t, 0)
case TSLICE: case types.TSLICE:
// ../../../../runtime/type.go:/sliceType // ../../../../runtime/type.go:/sliceType
s1 := dtypesym(t.Elem()) s1 := dtypesym(t.Elem())
ot = dcommontype(lsym, t) ot = dcommontype(lsym, t)
ot = dsymptr(lsym, ot, s1, 0) ot = dsymptr(lsym, ot, s1, 0)
ot = dextratype(lsym, ot, t, 0) ot = dextratype(lsym, ot, t, 0)
case TCHAN: case types.TCHAN:
// ../../../../runtime/type.go:/chanType // ../../../../runtime/type.go:/chanType
s1 := dtypesym(t.Elem()) s1 := dtypesym(t.Elem())
ot = dcommontype(lsym, t) ot = dcommontype(lsym, t)
@ -1211,7 +1212,7 @@ func dtypesym(t *types.Type) *obj.LSym {
ot = duintptr(lsym, ot, uint64(t.ChanDir())) ot = duintptr(lsym, ot, uint64(t.ChanDir()))
ot = dextratype(lsym, ot, t, 0) ot = dextratype(lsym, ot, t, 0)
case TFUNC: case types.TFUNC:
for _, t1 := range t.Recvs().Fields().Slice() { for _, t1 := range t.Recvs().Fields().Slice() {
dtypesym(t1.Type) dtypesym(t1.Type)
} }
@ -1250,7 +1251,7 @@ func dtypesym(t *types.Type) *obj.LSym {
ot = dsymptr(lsym, ot, dtypesym(t1.Type), 0) ot = dsymptr(lsym, ot, dtypesym(t1.Type), 0)
} }
case TINTER: case types.TINTER:
m := imethods(t) m := imethods(t)
n := len(m) n := len(m)
for _, a := range m { for _, a := range m {
@ -1286,7 +1287,7 @@ func dtypesym(t *types.Type) *obj.LSym {
} }
// ../../../../runtime/type.go:/mapType // ../../../../runtime/type.go:/mapType
case TMAP: case types.TMAP:
s1 := dtypesym(t.Key()) s1 := dtypesym(t.Key())
s2 := dtypesym(t.Elem()) s2 := dtypesym(t.Elem())
s3 := dtypesym(bmap(t)) s3 := dtypesym(bmap(t))
@ -1326,8 +1327,8 @@ func dtypesym(t *types.Type) *obj.LSym {
ot = duint32(lsym, ot, flags) ot = duint32(lsym, ot, flags)
ot = dextratype(lsym, ot, t, 0) ot = dextratype(lsym, ot, t, 0)
case TPTR: case types.TPTR:
if t.Elem().Etype == TANY { if t.Elem().Etype == types.TANY {
// ../../../../runtime/type.go:/UnsafePointerType // ../../../../runtime/type.go:/UnsafePointerType
ot = dcommontype(lsym, t) ot = dcommontype(lsym, t)
ot = dextratype(lsym, ot, t, 0) ot = dextratype(lsym, ot, t, 0)
@ -1344,7 +1345,7 @@ func dtypesym(t *types.Type) *obj.LSym {
// ../../../../runtime/type.go:/structType // ../../../../runtime/type.go:/structType
// for security, only the exported fields. // for security, only the exported fields.
case TSTRUCT: case types.TSTRUCT:
fields := t.Fields().Slice() fields := t.Fields().Slice()
for _, t1 := range fields { for _, t1 := range fields {
dtypesym(t1.Type) dtypesym(t1.Type)
@ -1403,7 +1404,7 @@ func dtypesym(t *types.Type) *obj.LSym {
// functions must return the existing type structure rather // functions must return the existing type structure rather
// than creating a new one. // than creating a new one.
switch t.Etype { 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 keep = true
} }
} }
@ -1515,10 +1516,10 @@ func addsignat(t *types.Type) {
} }
} }
func addsignats(dcls []*Node) { func addsignats(dcls []*ir.Node) {
// copy types from dcl list to signatset // copy types from dcl list to signatset
for _, n := range dcls { for _, n := range dcls {
if n.Op == OTYPE { if n.Op == ir.OTYPE {
addsignat(n.Type) addsignat(n.Type)
} }
} }
@ -1571,7 +1572,7 @@ func dumptabs() {
} }
// process ptabs // process ptabs
if localpkg.Name == "main" && len(ptabs) > 0 { if ir.LocalPkg.Name == "main" && len(ptabs) > 0 {
ot := 0 ot := 0
s := base.Ctxt.Lookup("go.plugin.tabs") s := base.Ctxt.Lookup("go.plugin.tabs")
for _, p := range ptabs { for _, p := range ptabs {
@ -1615,17 +1616,17 @@ func dumpbasictypes() {
// another possible choice would be package main, // another possible choice would be package main,
// but using runtime means fewer copies in object files. // but using runtime means fewer copies in object files.
if base.Ctxt.Pkgpath == "runtime" { 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[i]))
} }
dtypesym(types.NewPtr(types.Types[TSTRING])) dtypesym(types.NewPtr(types.Types[types.TSTRING]))
dtypesym(types.NewPtr(types.Types[TUNSAFEPTR])) dtypesym(types.NewPtr(types.Types[types.TUNSAFEPTR]))
// emit type structs for error and func(error) string. // emit type structs for error and func(error) string.
// The latter is the type of an auto-generated wrapper. // The latter is the type of an auto-generated wrapper.
dtypesym(types.NewPtr(types.Errortype)) 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. // add paths for runtime and main, which 6l imports implicitly.
dimportpath(Runtimepkg) dimportpath(Runtimepkg)
@ -1767,7 +1768,7 @@ func fillptrmask(t *types.Type, ptrmask []byte) {
// For non-trivial arrays, the program describes the full t.Width size. // For non-trivial arrays, the program describes the full t.Width size.
func dgcprog(t *types.Type) (*obj.LSym, int64) { func dgcprog(t *types.Type) (*obj.LSym, int64) {
dowidth(t) dowidth(t)
if t.Width == BADWIDTH { if t.Width == types.BADWIDTH {
base.Fatalf("dgcprog: %v badwidth", t) base.Fatalf("dgcprog: %v badwidth", t)
} }
lsym := typesymprefix(".gcprog", t).Linksym() lsym := typesymprefix(".gcprog", t).Linksym()
@ -1824,17 +1825,17 @@ func (p *GCProg) emit(t *types.Type, offset int64) {
default: default:
base.Fatalf("GCProg.emit: unexpected type %v", t) base.Fatalf("GCProg.emit: unexpected type %v", t)
case TSTRING: case types.TSTRING:
p.w.Ptr(offset / int64(Widthptr)) 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. // Note: the first word isn't a pointer. See comment in plive.go:onebitwalktype1.
p.w.Ptr(offset/int64(Widthptr) + 1) p.w.Ptr(offset/int64(Widthptr) + 1)
case TSLICE: case types.TSLICE:
p.w.Ptr(offset / int64(Widthptr)) p.w.Ptr(offset / int64(Widthptr))
case TARRAY: case types.TARRAY:
if t.NumElem() == 0 { if t.NumElem() == 0 {
// should have been handled by haspointers check above // should have been handled by haspointers check above
base.Fatalf("GCProg.emit: empty array") base.Fatalf("GCProg.emit: empty array")
@ -1859,7 +1860,7 @@ func (p *GCProg) emit(t *types.Type, offset int64) {
p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr)) p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr))
p.w.Repeat(elem.Width/int64(Widthptr), count-1) p.w.Repeat(elem.Width/int64(Widthptr), count-1)
case TSTRUCT: case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() { for _, t1 := range t.Fields().Slice() {
p.emit(t1.Type, offset+t1.Offset) p.emit(t1.Type, offset+t1.Offset)
} }
@ -1868,7 +1869,7 @@ func (p *GCProg) emit(t *types.Type, offset int64) {
// zeroaddr returns the address of a symbol with at least // zeroaddr returns the address of a symbol with at least
// size bytes of zeros. // size bytes of zeros.
func zeroaddr(size int64) *Node { func zeroaddr(size int64) *ir.Node {
if size >= 1<<31 { if size >= 1<<31 {
base.Fatalf("map elem too big %d", size) base.Fatalf("map elem too big %d", size)
} }
@ -1877,14 +1878,14 @@ func zeroaddr(size int64) *Node {
} }
s := mappkg.Lookup("zero") s := mappkg.Lookup("zero")
if s.Def == nil { if s.Def == nil {
x := newname(s) x := NewName(s)
x.Type = types.Types[TUINT8] x.Type = types.Types[types.TUINT8]
x.SetClass(PEXTERN) x.SetClass(ir.PEXTERN)
x.SetTypecheck(1) x.SetTypecheck(1)
s.Def = asTypesNode(x) s.Def = ir.AsTypesNode(x)
} }
z := nod(OADDR, asNode(s.Def), nil) z := ir.Nod(ir.OADDR, ir.AsNode(s.Def), nil)
z.Type = types.NewPtr(types.Types[TUINT8]) z.Type = types.NewPtr(types.Types[types.TUINT8])
z.SetTypecheck(1) z.SetTypecheck(1)
return z return z
} }

View file

@ -4,6 +4,8 @@
package gc package gc
import "cmd/compile/internal/ir"
// Strongly connected components. // Strongly connected components.
// //
// Run analysis on minimal sets of mutually recursive functions // Run analysis on minimal sets of mutually recursive functions
@ -30,10 +32,10 @@ package gc
// when analyzing a set of mutually recursive functions. // when analyzing a set of mutually recursive functions.
type bottomUpVisitor struct { type bottomUpVisitor struct {
analyze func([]*Node, bool) analyze func([]*ir.Node, bool)
visitgen uint32 visitgen uint32
nodeID map[*Node]uint32 nodeID map[*ir.Node]uint32
stack []*Node stack []*ir.Node
} }
// visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list. // visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list.
@ -49,18 +51,18 @@ type bottomUpVisitor struct {
// If recursive is false, the list consists of only a single function and its closures. // 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 recursive is true, the list may still contain only a single function,
// if that function is itself recursive. // 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 var v bottomUpVisitor
v.analyze = analyze v.analyze = analyze
v.nodeID = make(map[*Node]uint32) v.nodeID = make(map[*ir.Node]uint32)
for _, n := range list { for _, n := range list {
if n.Op == ODCLFUNC && !n.Func.IsHiddenClosure() { if n.Op == ir.ODCLFUNC && !n.Func.IsHiddenClosure() {
v.visit(n) 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 { if id := v.nodeID[n]; id > 0 {
// already visited // already visited
return id return id
@ -73,38 +75,38 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
min := v.visitgen min := v.visitgen
v.stack = append(v.stack, n) 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 { switch n.Op {
case ONAME: case ir.ONAME:
if n.Class() == PFUNC { if n.Class() == ir.PFUNC {
if n != nil && n.Name.Defn != nil { if n != nil && n.Name.Defn != nil {
if m := v.visit(n.Name.Defn); m < min { if m := v.visit(n.Name.Defn); m < min {
min = m min = m
} }
} }
} }
case OMETHEXPR: case ir.OMETHEXPR:
fn := n.MethodName() fn := methodExprName(n)
if fn != nil && fn.Name.Defn != nil { if fn != nil && fn.Name.Defn != nil {
if m := v.visit(fn.Name.Defn); m < min { if m := v.visit(fn.Name.Defn); m < min {
min = m min = m
} }
} }
case ODOTMETH: case ir.ODOTMETH:
fn := n.MethodName() fn := methodExprName(n)
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 {
if m := v.visit(fn.Name.Defn); m < min { if m := v.visit(fn.Name.Defn); m < min {
min = m min = m
} }
} }
case OCALLPART: case ir.OCALLPART:
fn := asNode(callpartMethod(n).Nname) fn := ir.AsNode(callpartMethod(n).Nname)
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 {
if m := v.visit(fn.Name.Defn); m < min { if m := v.visit(fn.Name.Defn); m < min {
min = m min = m
} }
} }
case OCLOSURE: case ir.OCLOSURE:
if m := v.visit(n.Func.Decl); m < min { if m := v.visit(n.Func.Decl); m < min {
min = m min = m
} }

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/internal/dwarf" "cmd/internal/dwarf"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
@ -17,7 +18,7 @@ func xposBefore(p, q src.XPos) bool {
return base.Ctxt.PosTable.Pos(p).Before(base.Ctxt.PosTable.Pos(q)) 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 { i := sort.Search(len(marks), func(i int) bool {
return xposBefore(pos, marks[i].Pos) return xposBefore(pos, marks[i].Pos)
}) })
@ -27,7 +28,7 @@ func findScope(marks []Mark, pos src.XPos) ScopeID {
return marks[i-1].Scope 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. // Initialize the DWARF scope tree based on lexical scopes.
dwarfScopes := make([]dwarf.Scope, 1+len(fn.Func.Parents)) dwarfScopes := make([]dwarf.Scope, 1+len(fn.Func.Parents))
for i, parent := range fn.Func.Parents { for i, parent := range fn.Func.Parents {
@ -40,7 +41,7 @@ func assembleScopes(fnsym *obj.LSym, fn *Node, dwarfVars []*dwarf.Var, varScopes
} }
// scopeVariables assigns DWARF variable records to their scopes. // 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}) sort.Stable(varsByScopeAndOffset{dwarfVars, varScopes})
i0 := 0 i0 := 0
@ -57,7 +58,7 @@ func scopeVariables(dwarfVars []*dwarf.Var, varScopes []ScopeID, dwarfScopes []d
} }
// scopePCs assigns PC ranges to their scopes. // 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 // If there aren't any child scopes (in particular, when scope
// tracking is disabled), we can skip a whole lot of work. // tracking is disabled), we can skip a whole lot of work.
if len(marks) == 0 { if len(marks) == 0 {
@ -90,7 +91,7 @@ func compactScopes(dwarfScopes []dwarf.Scope) []dwarf.Scope {
type varsByScopeAndOffset struct { type varsByScopeAndOffset struct {
vars []*dwarf.Var vars []*dwarf.Var
scopes []ScopeID scopes []ir.ScopeID
} }
func (v varsByScopeAndOffset) Len() int { func (v varsByScopeAndOffset) Len() int {

View file

@ -6,16 +6,17 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
) )
// select // select
func typecheckselect(sel *Node) { func typecheckselect(sel *ir.Node) {
var def *Node var def *ir.Node
lno := setlineno(sel) lno := setlineno(sel)
typecheckslice(sel.Ninit.Slice(), ctxStmt) typecheckslice(sel.Ninit.Slice(), ctxStmt)
for _, ncase := range sel.List.Slice() { for _, ncase := range sel.List.Slice() {
if ncase.Op != OCASE { if ncase.Op != ir.OCASE {
setlineno(ncase) setlineno(ncase)
base.Fatalf("typecheckselect %v", ncase.Op) base.Fatalf("typecheckselect %v", ncase.Op)
} }
@ -23,7 +24,7 @@ func typecheckselect(sel *Node) {
if ncase.List.Len() == 0 { if ncase.List.Len() == 0 {
// default // default
if def != nil { 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 { } else {
def = ncase def = ncase
} }
@ -37,7 +38,7 @@ func typecheckselect(sel *Node) {
switch n.Op { switch n.Op {
default: default:
pos := n.Pos 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 // 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 // others). Using ncase.Pos for now as it will provide the correct
// line number (assuming the expression follows the "case" keyword // line number (assuming the expression follows the "case" keyword
@ -49,37 +50,37 @@ func typecheckselect(sel *Node) {
// convert x = <-c into OSELRECV(x, <-c). // convert x = <-c into OSELRECV(x, <-c).
// remove implicit conversions; the eventual assignment // remove implicit conversions; the eventual assignment
// will reintroduce them. // will reintroduce them.
case OAS: case ir.OAS:
if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit() { if (n.Right.Op == ir.OCONVNOP || n.Right.Op == ir.OCONVIFACE) && n.Right.Implicit() {
n.Right = n.Right.Left 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") base.ErrorfAt(n.Pos, "select assignment must have receive on right hand side")
break break
} }
n.Op = OSELRECV n.Op = ir.OSELRECV
// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok // convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
case OAS2RECV: case ir.OAS2RECV:
if n.Right.Op != ORECV { if n.Right.Op != ir.ORECV {
base.ErrorfAt(n.Pos, "select assignment must have receive on right hand side") base.ErrorfAt(n.Pos, "select assignment must have receive on right hand side")
break break
} }
n.Op = OSELRECV2 n.Op = ir.OSELRECV2
n.Left = n.List.First() n.Left = n.List.First()
n.List.Set1(n.List.Second()) n.List.Set1(n.List.Second())
// convert <-c into OSELRECV(N, <-c) // convert <-c into OSELRECV(N, <-c)
case ORECV: case ir.ORECV:
n = nodl(n.Pos, OSELRECV, nil, n) n = ir.NodAt(n.Pos, ir.OSELRECV, nil, n)
n.SetTypecheck(1) n.SetTypecheck(1)
ncase.Left = n ncase.Left = n
case OSEND: case ir.OSEND:
break break
} }
} }
@ -90,7 +91,7 @@ func typecheckselect(sel *Node) {
base.Pos = lno base.Pos = lno
} }
func walkselect(sel *Node) { func walkselect(sel *ir.Node) {
lno := setlineno(sel) lno := setlineno(sel)
if sel.Nbody.Len() != 0 { if sel.Nbody.Len() != 0 {
base.Fatalf("double walkselect") base.Fatalf("double walkselect")
@ -108,13 +109,13 @@ func walkselect(sel *Node) {
base.Pos = lno base.Pos = lno
} }
func walkselectcases(cases *Nodes) []*Node { func walkselectcases(cases *ir.Nodes) []*ir.Node {
ncas := cases.Len() ncas := cases.Len()
sellineno := base.Pos sellineno := base.Pos
// optimization: zero-case select // optimization: zero-case select
if ncas == 0 { if ncas == 0 {
return []*Node{mkcall("block", nil, nil)} return []*ir.Node{mkcall("block", nil, nil)}
} }
// optimization: one-case select: single op. // optimization: one-case select: single op.
@ -130,25 +131,25 @@ func walkselectcases(cases *Nodes) []*Node {
default: default:
base.Fatalf("select %v", n.Op) base.Fatalf("select %v", n.Op)
case OSEND: case ir.OSEND:
// already ok // already ok
case OSELRECV, OSELRECV2: case ir.OSELRECV, ir.OSELRECV2:
if n.Op == OSELRECV || n.List.Len() == 0 { if n.Op == ir.OSELRECV || n.List.Len() == 0 {
if n.Left == nil { if n.Left == nil {
n = n.Right n = n.Right
} else { } else {
n.Op = OAS n.Op = ir.OAS
} }
break break
} }
if n.Left == nil { if n.Left == nil {
nblank = typecheck(nblank, ctxExpr|ctxAssign) ir.BlankNode = typecheck(ir.BlankNode, ctxExpr|ctxAssign)
n.Left = nblank n.Left = ir.BlankNode
} }
n.Op = OAS2 n.Op = ir.OAS2
n.List.Prepend(n.Left) n.List.Prepend(n.Left)
n.Rlist.Set1(n.Right) n.Rlist.Set1(n.Right)
n.Right = nil n.Right = nil
@ -161,13 +162,13 @@ func walkselectcases(cases *Nodes) []*Node {
} }
l = append(l, cas.Nbody.Slice()...) l = append(l, cas.Nbody.Slice()...)
l = append(l, nod(OBREAK, nil, nil)) l = append(l, ir.Nod(ir.OBREAK, nil, nil))
return l return l
} }
// convert case value arguments to addresses. // convert case value arguments to addresses.
// this rewrite is used by both the general code and the next optimization. // 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() { for _, cas := range cases.Slice() {
setlineno(cas) setlineno(cas)
n := cas.Left n := cas.Left
@ -176,17 +177,17 @@ func walkselectcases(cases *Nodes) []*Node {
continue continue
} }
switch n.Op { switch n.Op {
case OSEND: case ir.OSEND:
n.Right = nod(OADDR, n.Right, nil) n.Right = ir.Nod(ir.OADDR, n.Right, nil)
n.Right = typecheck(n.Right, ctxExpr) n.Right = typecheck(n.Right, ctxExpr)
case OSELRECV, OSELRECV2: case ir.OSELRECV, ir.OSELRECV2:
if n.Op == OSELRECV2 && n.List.Len() == 0 { if n.Op == ir.OSELRECV2 && n.List.Len() == 0 {
n.Op = OSELRECV n.Op = ir.OSELRECV
} }
if n.Left != nil { 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.Left = typecheck(n.Left, ctxExpr)
} }
} }
@ -201,66 +202,66 @@ func walkselectcases(cases *Nodes) []*Node {
n := cas.Left n := cas.Left
setlineno(n) setlineno(n)
r := nod(OIF, nil, nil) r := ir.Nod(ir.OIF, nil, nil)
r.Ninit.Set(cas.Ninit.Slice()) r.Ninit.Set(cas.Ninit.Slice())
switch n.Op { switch n.Op {
default: default:
base.Fatalf("select %v", n.Op) base.Fatalf("select %v", n.Op)
case OSEND: case ir.OSEND:
// if selectnbsend(c, v) { body } else { default body } // if selectnbsend(c, v) { body } else { default body }
ch := n.Left 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 } // if selectnbrecv(&v, c) { body } else { default body }
ch := n.Right.Left ch := n.Right.Left
elem := n.Left elem := n.Left
if elem == nil { if elem == nil {
elem = nodnil() 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 } // if selectnbrecv2(&v, &received, c) { body } else { default body }
ch := n.Right.Left ch := n.Right.Left
elem := n.Left elem := n.Left
if elem == nil { if elem == nil {
elem = nodnil() elem = nodnil()
} }
receivedp := nod(OADDR, n.List.First(), nil) receivedp := ir.Nod(ir.OADDR, n.List.First(), nil)
receivedp = typecheck(receivedp, ctxExpr) 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.Left = typecheck(r.Left, ctxExpr)
r.Nbody.Set(cas.Nbody.Slice()) r.Nbody.Set(cas.Nbody.Slice())
r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.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 { if dflt != nil {
ncas-- ncas--
} }
casorder := make([]*Node, ncas) casorder := make([]*ir.Node, ncas)
nsends, nrecvs := 0, 0 nsends, nrecvs := 0, 0
var init []*Node var init []*ir.Node
// generate sel-struct // generate sel-struct
base.Pos = sellineno base.Pos = sellineno
selv := temp(types.NewArray(scasetype(), int64(ncas))) selv := temp(types.NewArray(scasetype(), int64(ncas)))
r := nod(OAS, selv, nil) r := ir.Nod(ir.OAS, selv, nil)
r = typecheck(r, ctxStmt) r = typecheck(r, ctxStmt)
init = append(init, r) init = append(init, r)
// No initialization for order; runtime.selectgo is responsible for that. // 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 { if base.Flag.Race {
pcs = temp(types.NewArray(types.Types[TUINTPTR], int64(ncas))) pcs = temp(types.NewArray(types.Types[types.TUINTPTR], int64(ncas)))
pc0 = typecheck(nod(OADDR, nod(OINDEX, pcs, nodintconst(0)), nil), ctxExpr) pc0 = typecheck(ir.Nod(ir.OADDR, ir.Nod(ir.OINDEX, pcs, nodintconst(0)), nil), ctxExpr)
} else { } else {
pc0 = nodnil() pc0 = nodnil()
} }
@ -278,16 +279,16 @@ func walkselectcases(cases *Nodes) []*Node {
} }
var i int var i int
var c, elem *Node var c, elem *ir.Node
switch n.Op { switch n.Op {
default: default:
base.Fatalf("select %v", n.Op) base.Fatalf("select %v", n.Op)
case OSEND: case ir.OSEND:
i = nsends i = nsends
nsends++ nsends++
c = n.Left c = n.Left
elem = n.Right elem = n.Right
case OSELRECV, OSELRECV2: case ir.OSELRECV, ir.OSELRECV2:
nrecvs++ nrecvs++
i = ncas - nrecvs i = ncas - nrecvs
c = n.Right.Left c = n.Right.Left
@ -296,23 +297,23 @@ func walkselectcases(cases *Nodes) []*Node {
casorder[i] = cas casorder[i] = cas
setField := func(f string, val *Node) { setField := func(f string, val *ir.Node) {
r := nod(OAS, nodSym(ODOT, nod(OINDEX, selv, nodintconst(int64(i))), lookup(f)), val) r := ir.Nod(ir.OAS, nodSym(ir.ODOT, ir.Nod(ir.OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
r = typecheck(r, ctxStmt) r = typecheck(r, ctxStmt)
init = append(init, r) init = append(init, r)
} }
c = convnop(c, types.Types[TUNSAFEPTR]) c = convnop(c, types.Types[types.TUNSAFEPTR])
setField("c", c) setField("c", c)
if elem != nil { if elem != nil {
elem = convnop(elem, types.Types[TUNSAFEPTR]) elem = convnop(elem, types.Types[types.TUNSAFEPTR])
setField("elem", elem) setField("elem", elem)
} }
// TODO(mdempsky): There should be a cleaner way to // TODO(mdempsky): There should be a cleaner way to
// handle this. // handle this.
if base.Flag.Race { 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) init = append(init, r)
} }
} }
@ -322,9 +323,9 @@ func walkselectcases(cases *Nodes) []*Node {
// run the select // run the select
base.Pos = sellineno base.Pos = sellineno
chosen := temp(types.Types[TINT]) chosen := temp(types.Types[types.TINT])
recvOK := temp(types.Types[TBOOL]) recvOK := temp(types.Types[types.TBOOL])
r = nod(OAS2, nil, nil) r = ir.Nod(ir.OAS2, nil, nil)
r.List.Set2(chosen, recvOK) r.List.Set2(chosen, recvOK)
fn := syslook("selectgo") 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))) 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)))
@ -332,46 +333,46 @@ func walkselectcases(cases *Nodes) []*Node {
init = append(init, r) init = append(init, r)
// selv and order are no longer alive after selectgo. // selv and order are no longer alive after selectgo.
init = append(init, nod(OVARKILL, selv, nil)) init = append(init, ir.Nod(ir.OVARKILL, selv, nil))
init = append(init, nod(OVARKILL, order, nil)) init = append(init, ir.Nod(ir.OVARKILL, order, nil))
if base.Flag.Race { if base.Flag.Race {
init = append(init, nod(OVARKILL, pcs, nil)) init = append(init, ir.Nod(ir.OVARKILL, pcs, nil))
} }
// dispatch cases // dispatch cases
dispatch := func(cond, cas *Node) { dispatch := func(cond, cas *ir.Node) {
cond = typecheck(cond, ctxExpr) cond = typecheck(cond, ctxExpr)
cond = defaultlit(cond, nil) 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 { if n := cas.Left; n != nil && n.Op == ir.OSELRECV2 {
x := nod(OAS, n.List.First(), recvOK) x := ir.Nod(ir.OAS, n.List.First(), recvOK)
x = typecheck(x, ctxStmt) x = typecheck(x, ctxStmt)
r.Nbody.Append(x) r.Nbody.Append(x)
} }
r.Nbody.AppendNodes(&cas.Nbody) 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) init = append(init, r)
} }
if dflt != nil { if dflt != nil {
setlineno(dflt) setlineno(dflt)
dispatch(nod(OLT, chosen, nodintconst(0)), dflt) dispatch(ir.Nod(ir.OLT, chosen, nodintconst(0)), dflt)
} }
for i, cas := range casorder { for i, cas := range casorder {
setlineno(cas) setlineno(cas)
dispatch(nod(OEQ, chosen, nodintconst(int64(i))), cas) dispatch(ir.Nod(ir.OEQ, chosen, nodintconst(int64(i))), cas)
} }
return init return init
} }
// bytePtrToIndex returns a Node representing "(*byte)(&n[i])". // bytePtrToIndex returns a Node representing "(*byte)(&n[i])".
func bytePtrToIndex(n *Node, i int64) *Node { func bytePtrToIndex(n *ir.Node, i int64) *ir.Node {
s := nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil) s := ir.Nod(ir.OADDR, ir.Nod(ir.OINDEX, n, nodintconst(i)), nil)
t := types.NewPtr(types.Types[TUINT8]) t := types.NewPtr(types.Types[types.TUINT8])
return convnop(s, t) return convnop(s, t)
} }
@ -380,9 +381,9 @@ var scase *types.Type
// Keep in sync with src/runtime/select.go. // Keep in sync with src/runtime/select.go.
func scasetype() *types.Type { func scasetype() *types.Type {
if scase == nil { if scase == nil {
scase = tostruct([]*Node{ scase = tostruct([]*ir.Node{
namedfield("c", types.Types[TUNSAFEPTR]), namedfield("c", types.Types[types.TUNSAFEPTR]),
namedfield("elem", types.Types[TUNSAFEPTR]), namedfield("elem", types.Types[types.TUNSAFEPTR]),
}) })
scase.SetNoalg(true) scase.SetNoalg(true)
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src" "cmd/internal/src"
"go/constant" "go/constant"
@ -14,16 +15,16 @@ import (
) )
// typecheckswitch typechecks a switch statement. // typecheckswitch typechecks a switch statement.
func typecheckswitch(n *Node) { func typecheckswitch(n *ir.Node) {
typecheckslice(n.Ninit.Slice(), ctxStmt) typecheckslice(n.Ninit.Slice(), ctxStmt)
if n.Left != nil && n.Left.Op == OTYPESW { if n.Left != nil && n.Left.Op == ir.OTYPESW {
typecheckTypeSwitch(n) typecheckTypeSwitch(n)
} else { } else {
typecheckExprSwitch(n) typecheckExprSwitch(n)
} }
} }
func typecheckTypeSwitch(n *Node) { func typecheckTypeSwitch(n *ir.Node) {
n.Left.Right = typecheck(n.Left.Right, ctxExpr) n.Left.Right = typecheck(n.Left.Right, ctxExpr)
t := n.Left.Right.Type t := n.Left.Right.Type
if t != nil && !t.IsInterface() { if t != nil && !t.IsInterface() {
@ -34,17 +35,17 @@ func typecheckTypeSwitch(n *Node) {
// We don't actually declare the type switch's guarded // We don't actually declare the type switch's guarded
// declaration itself. So if there are no cases, we won't // declaration itself. So if there are no cases, we won't
// notice that it went unused. // 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) base.ErrorfAt(v.Pos, "%v declared but not used", v.Sym)
} }
var defCase, nilCase *Node var defCase, nilCase *ir.Node
var ts typeSet var ts typeSet
for _, ncase := range n.List.Slice() { for _, ncase := range n.List.Slice() {
ls := ncase.List.Slice() ls := ncase.List.Slice()
if len(ls) == 0 { // default: if len(ls) == 0 { // default:
if defCase != nil { 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 { } else {
defCase = ncase defCase = ncase
} }
@ -60,13 +61,13 @@ func typecheckTypeSwitch(n *Node) {
var missing, have *types.Field var missing, have *types.Field
var ptr int var ptr int
switch { switch {
case n1.isNil(): // case nil: case ir.IsNil(n1): // case nil:
if nilCase != 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 { } else {
nilCase = ncase nilCase = ncase
} }
case n1.Op != OTYPE: case n1.Op != ir.OTYPE:
base.ErrorfAt(ncase.Pos, "%L is not a type", n1) base.ErrorfAt(ncase.Pos, "%L is not a type", n1)
case !n1.Type.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr) && !missing.Broke(): case !n1.Type.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr) && !missing.Broke():
if have != nil && !have.Broke() { if have != nil && !have.Broke() {
@ -81,7 +82,7 @@ func typecheckTypeSwitch(n *Node) {
} }
} }
if n1.Op == OTYPE { if n1.Op == ir.OTYPE {
ts.add(ncase.Pos, n1.Type) ts.add(ncase.Pos, n1.Type)
} }
} }
@ -90,9 +91,9 @@ func typecheckTypeSwitch(n *Node) {
// Assign the clause variable's type. // Assign the clause variable's type.
vt := t vt := t
if len(ls) == 1 { if len(ls) == 1 {
if ls[0].Op == OTYPE { if ls[0].Op == ir.OTYPE {
vt = ls[0].Type vt = ls[0].Type
} else if !ls[0].isNil() { } else if !ir.IsNil(ls[0]) {
// Invalid single-type case; // Invalid single-type case;
// mark variable as broken. // mark variable as broken.
vt = nil vt = nil
@ -143,8 +144,8 @@ func (s *typeSet) add(pos src.XPos, typ *types.Type) {
s.m[ls] = append(prevs, typeSetEntry{pos, typ}) s.m[ls] = append(prevs, typeSetEntry{pos, typ})
} }
func typecheckExprSwitch(n *Node) { func typecheckExprSwitch(n *ir.Node) {
t := types.Types[TBOOL] t := types.Types[types.TBOOL]
if n.Left != nil { if n.Left != nil {
n.Left = typecheck(n.Left, ctxExpr) n.Left = typecheck(n.Left, ctxExpr)
n.Left = defaultlit(n.Left, nil) n.Left = defaultlit(n.Left, nil)
@ -156,7 +157,7 @@ func typecheckExprSwitch(n *Node) {
switch { switch {
case t.IsMap(): case t.IsMap():
nilonly = "map" nilonly = "map"
case t.Etype == TFUNC: case t.Etype == types.TFUNC:
nilonly = "func" nilonly = "func"
case t.IsSlice(): case t.IsSlice():
nilonly = "slice" nilonly = "slice"
@ -171,13 +172,13 @@ func typecheckExprSwitch(n *Node) {
} }
} }
var defCase *Node var defCase *ir.Node
var cs constSet var cs constSet
for _, ncase := range n.List.Slice() { for _, ncase := range n.List.Slice() {
ls := ncase.List.Slice() ls := ncase.List.Slice()
if len(ls) == 0 { // default: if len(ls) == 0 { // default:
if defCase != nil { 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 { } else {
defCase = ncase defCase = ncase
} }
@ -192,14 +193,14 @@ func typecheckExprSwitch(n *Node) {
continue 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) 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) { } else if t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type) {
base.ErrorfAt(ncase.Pos, "invalid case %L in switch (incomparable type)", n1) base.ErrorfAt(ncase.Pos, "invalid case %L in switch (incomparable type)", n1)
} else { } else {
op1, _ := assignop(n1.Type, t) op1, _ := assignop(n1.Type, t)
op2, _ := assignop(t, n1.Type) op2, _ := assignop(t, n1.Type)
if op1 == OXXX && op2 == OXXX { if op1 == ir.OXXX && op2 == ir.OXXX {
if n.Left != nil { 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) base.ErrorfAt(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
} else { } else {
@ -224,13 +225,13 @@ func typecheckExprSwitch(n *Node) {
} }
// walkswitch walks a switch statement. // walkswitch walks a switch statement.
func walkswitch(sw *Node) { func walkswitch(sw *ir.Node) {
// Guard against double walk, see #25776. // Guard against double walk, see #25776.
if sw.List.Len() == 0 && sw.Nbody.Len() > 0 { if sw.List.Len() == 0 && sw.Nbody.Len() > 0 {
return // Was fatal, but eliminating every possible source of double-walking is hard 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) walkTypeSwitch(sw)
} else { } else {
walkExprSwitch(sw) walkExprSwitch(sw)
@ -239,7 +240,7 @@ func walkswitch(sw *Node) {
// walkExprSwitch generates an AST implementing sw. sw is an // walkExprSwitch generates an AST implementing sw. sw is an
// expression switch. // expression switch.
func walkExprSwitch(sw *Node) { func walkExprSwitch(sw *ir.Node) {
lno := setlineno(sw) lno := setlineno(sw)
cond := sw.Left cond := sw.Left
@ -259,12 +260,12 @@ func walkExprSwitch(sw *Node) {
// because walkexpr will lower the string // because walkexpr will lower the string
// conversion into a runtime call. // conversion into a runtime call.
// See issue 24937 for more discussion. // See issue 24937 for more discussion.
if cond.Op == OBYTES2STR && allCaseExprsAreSideEffectFree(sw) { if cond.Op == ir.OBYTES2STR && allCaseExprsAreSideEffectFree(sw) {
cond.Op = OBYTES2STRTMP cond.Op = ir.OBYTES2STRTMP
} }
cond = walkexpr(cond, &sw.Ninit) 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) cond = copyexpr(cond, cond.Type, &sw.Nbody)
} }
@ -274,11 +275,11 @@ func walkExprSwitch(sw *Node) {
exprname: cond, exprname: cond,
} }
var defaultGoto *Node var defaultGoto *ir.Node
var body Nodes var body ir.Nodes
for _, ncase := range sw.List.Slice() { for _, ncase := range sw.List.Slice() {
label := autolabel(".s") label := autolabel(".s")
jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label)) jmp := npos(ncase.Pos, nodSym(ir.OGOTO, nil, label))
// Process case dispatch. // Process case dispatch.
if ncase.List.Len() == 0 { if ncase.List.Len() == 0 {
@ -293,10 +294,10 @@ func walkExprSwitch(sw *Node) {
} }
// Process body. // 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()...) body.Append(ncase.Nbody.Slice()...)
if fall, pos := hasFall(ncase.Nbody.Slice()); !fall { if fall, pos := hasFall(ncase.Nbody.Slice()); !fall {
br := nod(OBREAK, nil, nil) br := ir.Nod(ir.OBREAK, nil, nil)
br.Pos = pos br.Pos = pos
body.Append(br) body.Append(br)
} }
@ -304,7 +305,7 @@ func walkExprSwitch(sw *Node) {
sw.List.Set(nil) sw.List.Set(nil)
if defaultGoto == nil { if defaultGoto == nil {
br := nod(OBREAK, nil, nil) br := ir.Nod(ir.OBREAK, nil, nil)
br.Pos = br.Pos.WithNotStmt() br.Pos = br.Pos.WithNotStmt()
defaultGoto = br defaultGoto = br
} }
@ -317,21 +318,21 @@ func walkExprSwitch(sw *Node) {
// An exprSwitch walks an expression switch. // An exprSwitch walks an expression switch.
type exprSwitch struct { type exprSwitch struct {
exprname *Node // value being switched on exprname *ir.Node // value being switched on
done Nodes done ir.Nodes
clauses []exprClause clauses []exprClause
} }
type exprClause struct { type exprClause struct {
pos src.XPos pos src.XPos
lo, hi *Node lo, hi *ir.Node
jmp *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} 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) s.clauses = append(s.clauses, c)
return return
} }
@ -341,7 +342,7 @@ func (s *exprSwitch) Add(pos src.XPos, expr, jmp *Node) {
s.flush() s.flush()
} }
func (s *exprSwitch) Emit(out *Nodes) { func (s *exprSwitch) Emit(out *ir.Nodes) {
s.flush() s.flush()
out.AppendNodes(&s.done) out.AppendNodes(&s.done)
} }
@ -389,12 +390,12 @@ func (s *exprSwitch) flush() {
// Perform two-level binary search. // Perform two-level binary search.
binarySearch(len(runs), &s.done, binarySearch(len(runs), &s.done,
func(i int) *Node { func(i int) *ir.Node {
return nod(OLE, nod(OLEN, s.exprname, nil), nodintconst(runLen(runs[i-1]))) 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] 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(run, &nif.Nbody)
}, },
) )
@ -422,12 +423,12 @@ func (s *exprSwitch) flush() {
s.search(cc, &s.done) 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, binarySearch(len(cc), out,
func(i int) *Node { func(i int) *ir.Node {
return nod(OLE, s.exprname, cc[i-1].hi) 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] c := &cc[i]
nif.Left = c.test(s.exprname) nif.Left = c.test(s.exprname)
nif.Nbody.Set1(c.jmp) nif.Nbody.Set1(c.jmp)
@ -435,27 +436,27 @@ func (s *exprSwitch) search(cc []exprClause, out *Nodes) {
) )
} }
func (c *exprClause) test(exprname *Node) *Node { func (c *exprClause) test(exprname *ir.Node) *ir.Node {
// Integer range. // Integer range.
if c.hi != c.lo { if c.hi != c.lo {
low := nodl(c.pos, OGE, exprname, c.lo) low := ir.NodAt(c.pos, ir.OGE, exprname, c.lo)
high := nodl(c.pos, OLE, exprname, c.hi) high := ir.NodAt(c.pos, ir.OLE, exprname, c.hi)
return nodl(c.pos, OANDAND, low, high) return ir.NodAt(c.pos, ir.OANDAND, low, high)
} }
// Optimize "switch true { ...}" and "switch false { ... }". // 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() { if exprname.BoolVal() {
return c.lo return c.lo
} else { } 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 // In theory, we could be more aggressive, allowing any
// side-effect-free expressions in cases, but it's a bit // side-effect-free expressions in cases, but it's a bit
// tricky because some of that information is unavailable due // tricky because some of that information is unavailable due
@ -464,11 +465,11 @@ func allCaseExprsAreSideEffectFree(sw *Node) bool {
// enough. // enough.
for _, ncase := range sw.List.Slice() { 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) base.Fatalf("switch string(byteslice) bad op: %v", ncase.Op)
} }
for _, v := range ncase.List.Slice() { for _, v := range ncase.List.Slice() {
if v.Op != OLITERAL { if v.Op != ir.OLITERAL {
return false return false
} }
} }
@ -477,7 +478,7 @@ func allCaseExprsAreSideEffectFree(sw *Node) bool {
} }
// hasFall reports whether stmts ends with a "fallthrough" statement. // 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 // Search backwards for the index of the fallthrough
// statement. Do not assume it'll be in the last // statement. Do not assume it'll be in the last
// position, since in some cases (e.g. when the statement // position, since in some cases (e.g. when the statement
@ -485,30 +486,30 @@ func hasFall(stmts []*Node) (bool, src.XPos) {
// nodes will be at the end of the list. // nodes will be at the end of the list.
i := len(stmts) - 1 i := len(stmts) - 1
for i >= 0 && stmts[i].Op == OVARKILL { for i >= 0 && stmts[i].Op == ir.OVARKILL {
i-- i--
} }
if i < 0 { if i < 0 {
return false, src.NoXPos 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 // walkTypeSwitch generates an AST that implements sw, where sw is a
// type switch. // type switch.
func walkTypeSwitch(sw *Node) { func walkTypeSwitch(sw *ir.Node) {
var s typeSwitch var s typeSwitch
s.facename = sw.Left.Right s.facename = sw.Left.Right
sw.Left = nil sw.Left = nil
s.facename = walkexpr(s.facename, &sw.Ninit) s.facename = walkexpr(s.facename, &sw.Ninit)
s.facename = copyexpr(s.facename, s.facename.Type, &sw.Nbody) 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. // Get interface descriptor word.
// For empty interfaces this will be the type. // For empty interfaces this will be the type.
// For non-empty interfaces this will be the itab. // 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: // For empty interfaces, do:
// if e._type == nil { // if e._type == nil {
@ -516,8 +517,8 @@ func walkTypeSwitch(sw *Node) {
// } // }
// h := e._type.hash // h := e._type.hash
// Use a similar strategy for non-empty interfaces. // Use a similar strategy for non-empty interfaces.
ifNil := nod(OIF, nil, nil) ifNil := ir.Nod(ir.OIF, nil, nil)
ifNil.Left = nod(OEQ, itab, nodnil()) ifNil.Left = ir.Nod(ir.OEQ, itab, nodnil())
base.Pos = base.Pos.WithNotStmt() // disable statement marks after the first check. base.Pos = base.Pos.WithNotStmt() // disable statement marks after the first check.
ifNil.Left = typecheck(ifNil.Left, ctxExpr) ifNil.Left = typecheck(ifNil.Left, ctxExpr)
ifNil.Left = defaultlit(ifNil.Left, nil) ifNil.Left = defaultlit(ifNil.Left, nil)
@ -525,8 +526,8 @@ func walkTypeSwitch(sw *Node) {
sw.Nbody.Append(ifNil) sw.Nbody.Append(ifNil)
// Load hash from type or itab. // Load hash from type or itab.
dotHash := nodSym(ODOTPTR, itab, nil) dotHash := nodSym(ir.ODOTPTR, itab, nil)
dotHash.Type = types.Types[TUINT32] dotHash.Type = types.Types[types.TUINT32]
dotHash.SetTypecheck(1) dotHash.SetTypecheck(1)
if s.facename.Type.IsEmptyInterface() { if s.facename.Type.IsEmptyInterface() {
dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
@ -536,11 +537,11 @@ func walkTypeSwitch(sw *Node) {
dotHash.SetBounded(true) // guaranteed not to fault dotHash.SetBounded(true) // guaranteed not to fault
s.hashname = copyexpr(dotHash, dotHash.Type, &sw.Nbody) s.hashname = copyexpr(dotHash, dotHash.Type, &sw.Nbody)
br := nod(OBREAK, nil, nil) br := ir.Nod(ir.OBREAK, nil, nil)
var defaultGoto, nilGoto *Node var defaultGoto, nilGoto *ir.Node
var body Nodes var body ir.Nodes
for _, ncase := range sw.List.Slice() { for _, ncase := range sw.List.Slice() {
var caseVar *Node var caseVar *ir.Node
if ncase.Rlist.Len() != 0 { if ncase.Rlist.Len() != 0 {
caseVar = ncase.Rlist.First() caseVar = ncase.Rlist.First()
} }
@ -549,13 +550,13 @@ func walkTypeSwitch(sw *Node) {
// we initialize the case variable as part of the type assertion. // we initialize the case variable as part of the type assertion.
// In other cases, we initialize it in the body. // In other cases, we initialize it in the body.
var singleType *types.Type 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 singleType = ncase.List.First().Type
} }
caseVarInitialized := false caseVarInitialized := false
label := autolabel(".s") 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 ncase.List.Len() == 0 { // default:
if defaultGoto != nil { if defaultGoto != nil {
@ -565,7 +566,7 @@ func walkTypeSwitch(sw *Node) {
} }
for _, n1 := range ncase.List.Slice() { for _, n1 := range ncase.List.Slice() {
if n1.isNil() { // case nil: if ir.IsNil(n1) { // case nil:
if nilGoto != nil { if nilGoto != nil {
base.Fatalf("duplicate nil case not detected during typechecking") base.Fatalf("duplicate nil case not detected during typechecking")
} }
@ -581,7 +582,7 @@ func walkTypeSwitch(sw *Node) {
} }
} }
body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label))) body.Append(npos(ncase.Pos, nodSym(ir.OLABEL, nil, label)))
if caseVar != nil && !caseVarInitialized { if caseVar != nil && !caseVarInitialized {
val := s.facename val := s.facename
if singleType != nil { if singleType != nil {
@ -591,9 +592,9 @@ func walkTypeSwitch(sw *Node) {
} }
val = ifaceData(ncase.Pos, s.facename, singleType) val = ifaceData(ncase.Pos, s.facename, singleType)
} }
l := []*Node{ l := []*ir.Node{
nodl(ncase.Pos, ODCL, caseVar, nil), ir.NodAt(ncase.Pos, ir.ODCL, caseVar, nil),
nodl(ncase.Pos, OAS, caseVar, val), ir.NodAt(ncase.Pos, ir.OAS, caseVar, val),
} }
typecheckslice(l, ctxStmt) typecheckslice(l, ctxStmt)
body.Append(l...) body.Append(l...)
@ -621,36 +622,36 @@ func walkTypeSwitch(sw *Node) {
// A typeSwitch walks a type switch. // A typeSwitch walks a type switch.
type typeSwitch struct { type typeSwitch struct {
// Temporary variables (i.e., ONAMEs) used by type switch dispatch logic: // Temporary variables (i.e., ONAMEs) used by type switch dispatch logic:
facename *Node // value being type-switched on facename *ir.Node // value being type-switched on
hashname *Node // type hash of the value being type-switched on hashname *ir.Node // type hash of the value being type-switched on
okname *Node // boolean used for comma-ok type assertions okname *ir.Node // boolean used for comma-ok type assertions
done Nodes done ir.Nodes
clauses []typeClause clauses []typeClause
} }
type typeClause struct { type typeClause struct {
hash uint32 hash uint32
body Nodes body ir.Nodes
} }
func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *Node) { func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *ir.Node) {
var body Nodes var body ir.Nodes
if caseVar != nil { if caseVar != nil {
l := []*Node{ l := []*ir.Node{
nodl(pos, ODCL, caseVar, nil), ir.NodAt(pos, ir.ODCL, caseVar, nil),
nodl(pos, OAS, caseVar, nil), ir.NodAt(pos, ir.OAS, caseVar, nil),
} }
typecheckslice(l, ctxStmt) typecheckslice(l, ctxStmt)
body.Append(l...) body.Append(l...)
} else { } else {
caseVar = nblank caseVar = ir.BlankNode
} }
// cv, ok = iface.(type) // 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 = 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) dot.Type = typ // iface.(type)
as.Rlist.Set1(dot) as.Rlist.Set1(dot)
as = typecheck(as, ctxStmt) as = typecheck(as, ctxStmt)
@ -658,7 +659,7 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *Node) {
body.Append(as) body.Append(as)
// if ok { goto label } // if ok { goto label }
nif := nodl(pos, OIF, nil, nil) nif := ir.NodAt(pos, ir.OIF, nil, nil)
nif.Left = s.okname nif.Left = s.okname
nif.Nbody.Set1(jmp) nif.Nbody.Set1(jmp)
body.Append(nif) body.Append(nif)
@ -675,7 +676,7 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *Node) {
s.done.AppendNodes(&body) s.done.AppendNodes(&body)
} }
func (s *typeSwitch) Emit(out *Nodes) { func (s *typeSwitch) Emit(out *ir.Nodes) {
s.flush() s.flush()
out.AppendNodes(&s.done) out.AppendNodes(&s.done)
} }
@ -702,14 +703,14 @@ func (s *typeSwitch) flush() {
cc = merged cc = merged
binarySearch(len(cc), &s.done, binarySearch(len(cc), &s.done,
func(i int) *Node { func(i int) *ir.Node {
return nod(OLE, s.hashname, nodintconst(int64(cc[i-1].hash))) 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 // TODO(mdempsky): Omit hash equality check if
// there's only one type. // there's only one type.
c := cc[i] 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) nif.Nbody.AppendNodes(&c.body)
}, },
) )
@ -724,15 +725,15 @@ func (s *typeSwitch) flush() {
// //
// leaf(i, nif) should setup nif (an OIF node) to test case i. In // leaf(i, nif) should setup nif (an OIF node) to test case i. In
// particular, it should set nif.Left and nif.Nbody. // 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 const binarySearchMin = 4 // minimum number of cases for binary search
var do func(lo, hi int, out *Nodes) var do func(lo, hi int, out *ir.Nodes)
do = func(lo, hi int, out *Nodes) { do = func(lo, hi int, out *ir.Nodes) {
n := hi - lo n := hi - lo
if n < binarySearchMin { if n < binarySearchMin {
for i := lo; i < hi; i++ { for i := lo; i < hi; i++ {
nif := nod(OIF, nil, nil) nif := ir.Nod(ir.OIF, nil, nil)
leaf(i, nif) leaf(i, nif)
base.Pos = base.Pos.WithNotStmt() base.Pos = base.Pos.WithNotStmt()
nif.Left = typecheck(nif.Left, ctxExpr) nif.Left = typecheck(nif.Left, ctxExpr)
@ -744,7 +745,7 @@ func binarySearch(n int, out *Nodes, less func(i int) *Node, leaf func(i int, ni
} }
half := lo + n/2 half := lo + n/2
nif := nod(OIF, nil, nil) nif := ir.Nod(ir.OIF, nil, nil)
nif.Left = less(half) nif.Left = less(half)
base.Pos = base.Pos.WithNotStmt() base.Pos = base.Pos.WithNotStmt()
nif.Left = typecheck(nif.Left, ctxExpr) nif.Left = typecheck(nif.Left, ctxExpr)

File diff suppressed because it is too large Load diff

View file

@ -3,56 +3,3 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package gc 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
)

View file

@ -6,11 +6,3 @@
// TODO(gri) try to eliminate these soon // TODO(gri) try to eliminate these soon
package gc 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)) }

View file

@ -8,31 +8,29 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src" "cmd/internal/src"
) )
// builtinpkg is a fake package that declares the universe block.
var builtinpkg *types.Pkg
var basicTypes = [...]struct { var basicTypes = [...]struct {
name string name string
etype types.EType etype types.EType
}{ }{
{"int8", TINT8}, {"int8", types.TINT8},
{"int16", TINT16}, {"int16", types.TINT16},
{"int32", TINT32}, {"int32", types.TINT32},
{"int64", TINT64}, {"int64", types.TINT64},
{"uint8", TUINT8}, {"uint8", types.TUINT8},
{"uint16", TUINT16}, {"uint16", types.TUINT16},
{"uint32", TUINT32}, {"uint32", types.TUINT32},
{"uint64", TUINT64}, {"uint64", types.TUINT64},
{"float32", TFLOAT32}, {"float32", types.TFLOAT32},
{"float64", TFLOAT64}, {"float64", types.TFLOAT64},
{"complex64", TCOMPLEX64}, {"complex64", types.TCOMPLEX64},
{"complex128", TCOMPLEX128}, {"complex128", types.TCOMPLEX128},
{"bool", TBOOL}, {"bool", types.TBOOL},
{"string", TSTRING}, {"string", types.TSTRING},
} }
var typedefs = [...]struct { var typedefs = [...]struct {
@ -41,30 +39,30 @@ var typedefs = [...]struct {
sameas32 types.EType sameas32 types.EType
sameas64 types.EType sameas64 types.EType
}{ }{
{"int", TINT, TINT32, TINT64}, {"int", types.TINT, types.TINT32, types.TINT64},
{"uint", TUINT, TUINT32, TUINT64}, {"uint", types.TUINT, types.TUINT32, types.TUINT64},
{"uintptr", TUINTPTR, TUINT32, TUINT64}, {"uintptr", types.TUINTPTR, types.TUINT32, types.TUINT64},
} }
var builtinFuncs = [...]struct { var builtinFuncs = [...]struct {
name string name string
op Op op ir.Op
}{ }{
{"append", OAPPEND}, {"append", ir.OAPPEND},
{"cap", OCAP}, {"cap", ir.OCAP},
{"close", OCLOSE}, {"close", ir.OCLOSE},
{"complex", OCOMPLEX}, {"complex", ir.OCOMPLEX},
{"copy", OCOPY}, {"copy", ir.OCOPY},
{"delete", ODELETE}, {"delete", ir.ODELETE},
{"imag", OIMAG}, {"imag", ir.OIMAG},
{"len", OLEN}, {"len", ir.OLEN},
{"make", OMAKE}, {"make", ir.OMAKE},
{"new", ONEW}, {"new", ir.ONEW},
{"panic", OPANIC}, {"panic", ir.OPANIC},
{"print", OPRINT}, {"print", ir.OPRINT},
{"println", OPRINTN}, {"println", ir.OPRINTN},
{"real", OREAL}, {"real", ir.OREAL},
{"recover", ORECOVER}, {"recover", ir.ORECOVER},
} }
// isBuiltinFuncName reports whether name matches a builtin function // isBuiltinFuncName reports whether name matches a builtin function
@ -80,11 +78,11 @@ func isBuiltinFuncName(name string) bool {
var unsafeFuncs = [...]struct { var unsafeFuncs = [...]struct {
name string name string
op Op op ir.Op
}{ }{
{"Alignof", OALIGNOF}, {"Alignof", ir.OALIGNOF},
{"Offsetof", OOFFSETOF}, {"Offsetof", ir.OOFFSETOF},
{"Sizeof", OSIZEOF}, {"Sizeof", ir.OSIZEOF},
} }
// initUniverse initializes the universe block. // initUniverse initializes the universe block.
@ -101,71 +99,71 @@ func lexinit() {
if int(etype) >= len(types.Types) { if int(etype) >= len(types.Types) {
base.Fatalf("lexinit: %s bad etype", s.name) base.Fatalf("lexinit: %s bad etype", s.name)
} }
s2 := builtinpkg.Lookup(s.name) s2 := ir.BuiltinPkg.Lookup(s.name)
t := types.Types[etype] t := types.Types[etype]
if t == nil { if t == nil {
t = types.New(etype) t = types.New(etype)
t.Sym = s2 t.Sym = s2
if etype != TANY && etype != TSTRING { if etype != types.TANY && etype != types.TSTRING {
dowidth(t) dowidth(t)
} }
types.Types[etype] = t types.Types[etype] = t
} }
s2.Def = asTypesNode(typenod(t)) s2.Def = ir.AsTypesNode(typenod(t))
asNode(s2.Def).Name = new(Name) ir.AsNode(s2.Def).Name = new(ir.Name)
} }
for _, s := range &builtinFuncs { for _, s := range &builtinFuncs {
s2 := builtinpkg.Lookup(s.name) s2 := ir.BuiltinPkg.Lookup(s.name)
s2.Def = asTypesNode(newname(s2)) s2.Def = ir.AsTypesNode(NewName(s2))
asNode(s2.Def).SetSubOp(s.op) ir.AsNode(s2.Def).SetSubOp(s.op)
} }
for _, s := range &unsafeFuncs { for _, s := range &unsafeFuncs {
s2 := unsafepkg.Lookup(s.name) s2 := unsafepkg.Lookup(s.name)
s2.Def = asTypesNode(newname(s2)) s2.Def = ir.AsTypesNode(NewName(s2))
asNode(s2.Def).SetSubOp(s.op) ir.AsNode(s2.Def).SetSubOp(s.op)
} }
types.UntypedString = types.New(TSTRING) types.UntypedString = types.New(types.TSTRING)
types.UntypedBool = types.New(TBOOL) types.UntypedBool = types.New(types.TBOOL)
types.Types[TANY] = types.New(TANY) types.Types[types.TANY] = types.New(types.TANY)
s := builtinpkg.Lookup("true") s := ir.BuiltinPkg.Lookup("true")
s.Def = asTypesNode(nodbool(true)) s.Def = ir.AsTypesNode(nodbool(true))
asNode(s.Def).Sym = lookup("true") ir.AsNode(s.Def).Sym = lookup("true")
asNode(s.Def).Name = new(Name) ir.AsNode(s.Def).Name = new(ir.Name)
asNode(s.Def).Type = types.UntypedBool ir.AsNode(s.Def).Type = types.UntypedBool
s = builtinpkg.Lookup("false") s = ir.BuiltinPkg.Lookup("false")
s.Def = asTypesNode(nodbool(false)) s.Def = ir.AsTypesNode(nodbool(false))
asNode(s.Def).Sym = lookup("false") ir.AsNode(s.Def).Sym = lookup("false")
asNode(s.Def).Name = new(Name) ir.AsNode(s.Def).Name = new(ir.Name)
asNode(s.Def).Type = types.UntypedBool ir.AsNode(s.Def).Type = types.UntypedBool
s = lookup("_") s = lookup("_")
s.Block = -100 s.Block = -100
s.Def = asTypesNode(newname(s)) s.Def = ir.AsTypesNode(NewName(s))
types.Types[TBLANK] = types.New(TBLANK) types.Types[types.TBLANK] = types.New(types.TBLANK)
asNode(s.Def).Type = types.Types[TBLANK] ir.AsNode(s.Def).Type = types.Types[types.TBLANK]
nblank = asNode(s.Def) ir.BlankNode = ir.AsNode(s.Def)
s = builtinpkg.Lookup("_") s = ir.BuiltinPkg.Lookup("_")
s.Block = -100 s.Block = -100
s.Def = asTypesNode(newname(s)) s.Def = ir.AsTypesNode(NewName(s))
types.Types[TBLANK] = types.New(TBLANK) types.Types[types.TBLANK] = types.New(types.TBLANK)
asNode(s.Def).Type = types.Types[TBLANK] ir.AsNode(s.Def).Type = types.Types[types.TBLANK]
types.Types[TNIL] = types.New(TNIL) types.Types[types.TNIL] = types.New(types.TNIL)
s = builtinpkg.Lookup("nil") s = ir.BuiltinPkg.Lookup("nil")
s.Def = asTypesNode(nodnil()) s.Def = ir.AsTypesNode(nodnil())
asNode(s.Def).Sym = s ir.AsNode(s.Def).Sym = s
asNode(s.Def).Name = new(Name) ir.AsNode(s.Def).Name = new(ir.Name)
s = builtinpkg.Lookup("iota") s = ir.BuiltinPkg.Lookup("iota")
s.Def = asTypesNode(nod(OIOTA, nil, nil)) s.Def = ir.AsTypesNode(ir.Nod(ir.OIOTA, nil, nil))
asNode(s.Def).Sym = s ir.AsNode(s.Def).Sym = s
asNode(s.Def).Name = new(Name) ir.AsNode(s.Def).Name = new(ir.Name)
} }
func typeinit() { func typeinit() {
@ -173,42 +171,42 @@ func typeinit() {
base.Fatalf("typeinit before betypeinit") 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 simtype[et] = et
} }
types.Types[TPTR] = types.New(TPTR) types.Types[types.TPTR] = types.New(types.TPTR)
dowidth(types.Types[TPTR]) dowidth(types.Types[types.TPTR])
t := types.New(TUNSAFEPTR) t := types.New(types.TUNSAFEPTR)
types.Types[TUNSAFEPTR] = t types.Types[types.TUNSAFEPTR] = t
t.Sym = unsafepkg.Lookup("Pointer") t.Sym = unsafepkg.Lookup("Pointer")
t.Sym.Def = asTypesNode(typenod(t)) t.Sym.Def = ir.AsTypesNode(typenod(t))
asNode(t.Sym.Def).Name = new(Name) ir.AsNode(t.Sym.Def).Name = new(ir.Name)
dowidth(types.Types[TUNSAFEPTR]) dowidth(types.Types[types.TUNSAFEPTR])
for et := TINT8; et <= TUINT64; et++ { for et := types.TINT8; et <= types.TUINT64; et++ {
isInt[et] = true isInt[et] = true
} }
isInt[TINT] = true isInt[types.TINT] = true
isInt[TUINT] = true isInt[types.TUINT] = true
isInt[TUINTPTR] = true isInt[types.TUINTPTR] = true
isFloat[TFLOAT32] = true isFloat[types.TFLOAT32] = true
isFloat[TFLOAT64] = true isFloat[types.TFLOAT64] = true
isComplex[TCOMPLEX64] = true isComplex[types.TCOMPLEX64] = true
isComplex[TCOMPLEX128] = true isComplex[types.TCOMPLEX128] = true
// initialize okfor // initialize okfor
for et := types.EType(0); et < NTYPE; et++ { for et := types.EType(0); et < types.NTYPE; et++ {
if isInt[et] || et == TIDEAL { if isInt[et] || et == types.TIDEAL {
okforeq[et] = true okforeq[et] = true
okforcmp[et] = true okforcmp[et] = true
okforarith[et] = true okforarith[et] = true
okforadd[et] = true okforadd[et] = true
okforand[et] = true okforand[et] = true
okforconst[et] = true ir.OKForConst[et] = true
issimple[et] = true issimple[et] = true
} }
@ -217,7 +215,7 @@ func typeinit() {
okforcmp[et] = true okforcmp[et] = true
okforadd[et] = true okforadd[et] = true
okforarith[et] = true okforarith[et] = true
okforconst[et] = true ir.OKForConst[et] = true
issimple[et] = true issimple[et] = true
} }
@ -225,43 +223,43 @@ func typeinit() {
okforeq[et] = true okforeq[et] = true
okforadd[et] = true okforadd[et] = true
okforarith[et] = true okforarith[et] = true
okforconst[et] = true ir.OKForConst[et] = true
issimple[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[types.TARRAY] = true
okforcap[TCHAN] = true okforcap[types.TCHAN] = true
okforcap[TSLICE] = true okforcap[types.TSLICE] = true
okforconst[TBOOL] = true ir.OKForConst[types.TBOOL] = true
okforconst[TSTRING] = true ir.OKForConst[types.TSTRING] = true
okforlen[TARRAY] = true okforlen[types.TARRAY] = true
okforlen[TCHAN] = true okforlen[types.TCHAN] = true
okforlen[TMAP] = true okforlen[types.TMAP] = true
okforlen[TSLICE] = true okforlen[types.TSLICE] = true
okforlen[TSTRING] = true okforlen[types.TSTRING] = true
okforeq[TPTR] = true okforeq[types.TPTR] = true
okforeq[TUNSAFEPTR] = true okforeq[types.TUNSAFEPTR] = true
okforeq[TINTER] = true okforeq[types.TINTER] = true
okforeq[TCHAN] = true okforeq[types.TCHAN] = true
okforeq[TSTRING] = true okforeq[types.TSTRING] = true
okforeq[TBOOL] = true okforeq[types.TBOOL] = true
okforeq[TMAP] = true // nil only; refined in typecheck okforeq[types.TMAP] = true // nil only; refined in typecheck
okforeq[TFUNC] = true // nil only; refined in typecheck okforeq[types.TFUNC] = true // nil only; refined in typecheck
okforeq[TSLICE] = true // nil only; refined in typecheck okforeq[types.TSLICE] = true // nil only; refined in typecheck
okforeq[TARRAY] = true // only if element type is comparable; refined in typecheck okforeq[types.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.TSTRUCT] = true // only if all struct fields are comparable; refined in typecheck
okforcmp[TSTRING] = true okforcmp[types.TSTRING] = true
var i int var i int
for i = 0; i < len(okfor); i++ { for i = 0; i < len(okfor); i++ {
@ -269,51 +267,51 @@ func typeinit() {
} }
// binary // binary
okfor[OADD] = okforadd[:] okfor[ir.OADD] = okforadd[:]
okfor[OAND] = okforand[:] okfor[ir.OAND] = okforand[:]
okfor[OANDAND] = okforbool[:] okfor[ir.OANDAND] = okforbool[:]
okfor[OANDNOT] = okforand[:] okfor[ir.OANDNOT] = okforand[:]
okfor[ODIV] = okforarith[:] okfor[ir.ODIV] = okforarith[:]
okfor[OEQ] = okforeq[:] okfor[ir.OEQ] = okforeq[:]
okfor[OGE] = okforcmp[:] okfor[ir.OGE] = okforcmp[:]
okfor[OGT] = okforcmp[:] okfor[ir.OGT] = okforcmp[:]
okfor[OLE] = okforcmp[:] okfor[ir.OLE] = okforcmp[:]
okfor[OLT] = okforcmp[:] okfor[ir.OLT] = okforcmp[:]
okfor[OMOD] = okforand[:] okfor[ir.OMOD] = okforand[:]
okfor[OMUL] = okforarith[:] okfor[ir.OMUL] = okforarith[:]
okfor[ONE] = okforeq[:] okfor[ir.ONE] = okforeq[:]
okfor[OOR] = okforand[:] okfor[ir.OOR] = okforand[:]
okfor[OOROR] = okforbool[:] okfor[ir.OOROR] = okforbool[:]
okfor[OSUB] = okforarith[:] okfor[ir.OSUB] = okforarith[:]
okfor[OXOR] = okforand[:] okfor[ir.OXOR] = okforand[:]
okfor[OLSH] = okforand[:] okfor[ir.OLSH] = okforand[:]
okfor[ORSH] = okforand[:] okfor[ir.ORSH] = okforand[:]
// unary // unary
okfor[OBITNOT] = okforand[:] okfor[ir.OBITNOT] = okforand[:]
okfor[ONEG] = okforarith[:] okfor[ir.ONEG] = okforarith[:]
okfor[ONOT] = okforbool[:] okfor[ir.ONOT] = okforbool[:]
okfor[OPLUS] = okforarith[:] okfor[ir.OPLUS] = okforarith[:]
// special // special
okfor[OCAP] = okforcap[:] okfor[ir.OCAP] = okforcap[:]
okfor[OLEN] = okforlen[:] okfor[ir.OLEN] = okforlen[:]
// comparison // comparison
iscmp[OLT] = true iscmp[ir.OLT] = true
iscmp[OGT] = true iscmp[ir.OGT] = true
iscmp[OGE] = true iscmp[ir.OGE] = true
iscmp[OLE] = true iscmp[ir.OLE] = true
iscmp[OEQ] = true iscmp[ir.OEQ] = true
iscmp[ONE] = 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 // simple aliases
simtype[TMAP] = TPTR simtype[types.TMAP] = types.TPTR
simtype[TCHAN] = TPTR simtype[types.TCHAN] = types.TPTR
simtype[TFUNC] = TPTR simtype[types.TFUNC] = types.TPTR
simtype[TUNSAFEPTR] = TPTR simtype[types.TUNSAFEPTR] = types.TPTR
slicePtrOffset = 0 slicePtrOffset = 0
sliceLenOffset = Rnd(slicePtrOffset+int64(Widthptr), int64(Widthptr)) sliceLenOffset = Rnd(slicePtrOffset+int64(Widthptr), int64(Widthptr))
@ -323,29 +321,29 @@ func typeinit() {
// string is same as slice wo the cap // string is same as slice wo the cap
sizeofString = Rnd(sliceLenOffset+int64(Widthptr), int64(Widthptr)) sizeofString = Rnd(sliceLenOffset+int64(Widthptr), int64(Widthptr))
dowidth(types.Types[TSTRING]) dowidth(types.Types[types.TSTRING])
dowidth(types.UntypedString) dowidth(types.UntypedString)
} }
func makeErrorInterface() *types.Type { func makeErrorInterface() *types.Type {
sig := functypefield(fakeRecvField(), nil, []*types.Field{ 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) method := types.NewField(src.NoXPos, lookup("Error"), sig)
t := types.New(TINTER) t := types.New(types.TINTER)
t.SetInterface([]*types.Field{method}) t.SetInterface([]*types.Field{method})
return t return t
} }
func lexinit1() { func lexinit1() {
// error type // error type
s := builtinpkg.Lookup("error") s := ir.BuiltinPkg.Lookup("error")
types.Errortype = makeErrorInterface() types.Errortype = makeErrorInterface()
types.Errortype.Sym = s types.Errortype.Sym = s
types.Errortype.Orig = makeErrorInterface() types.Errortype.Orig = makeErrorInterface()
s.Def = asTypesNode(typenod(types.Errortype)) s.Def = ir.AsTypesNode(typenod(types.Errortype))
dowidth(types.Errortype) dowidth(types.Errortype)
// We create separate byte and rune types for better error messages // We create separate byte and rune types for better error messages
@ -357,24 +355,24 @@ func lexinit1() {
// type aliases, albeit at the cost of having to deal with it everywhere). // type aliases, albeit at the cost of having to deal with it everywhere).
// byte alias // byte alias
s = builtinpkg.Lookup("byte") s = ir.BuiltinPkg.Lookup("byte")
types.Bytetype = types.New(TUINT8) types.Bytetype = types.New(types.TUINT8)
types.Bytetype.Sym = s types.Bytetype.Sym = s
s.Def = asTypesNode(typenod(types.Bytetype)) s.Def = ir.AsTypesNode(typenod(types.Bytetype))
asNode(s.Def).Name = new(Name) ir.AsNode(s.Def).Name = new(ir.Name)
dowidth(types.Bytetype) dowidth(types.Bytetype)
// rune alias // rune alias
s = builtinpkg.Lookup("rune") s = ir.BuiltinPkg.Lookup("rune")
types.Runetype = types.New(TINT32) types.Runetype = types.New(types.TINT32)
types.Runetype.Sym = s types.Runetype.Sym = s
s.Def = asTypesNode(typenod(types.Runetype)) s.Def = ir.AsTypesNode(typenod(types.Runetype))
asNode(s.Def).Name = new(Name) ir.AsNode(s.Def).Name = new(ir.Name)
dowidth(types.Runetype) dowidth(types.Runetype)
// backend-dependent builtin types (e.g. int). // backend-dependent builtin types (e.g. int).
for _, s := range &typedefs { for _, s := range &typedefs {
s1 := builtinpkg.Lookup(s.name) s1 := ir.BuiltinPkg.Lookup(s.name)
sameas := s.sameas32 sameas := s.sameas32
if Widthptr == 8 { if Widthptr == 8 {
@ -386,9 +384,9 @@ func lexinit1() {
t := types.New(s.etype) t := types.New(s.etype)
t.Sym = s1 t.Sym = s1
types.Types[s.etype] = t types.Types[s.etype] = t
s1.Def = asTypesNode(typenod(t)) s1.Def = ir.AsTypesNode(typenod(t))
asNode(s1.Def).Name = new(Name) ir.AsNode(s1.Def).Name = new(ir.Name)
s1.Origpkg = builtinpkg s1.Origpkg = ir.BuiltinPkg
dowidth(t) dowidth(t)
} }
@ -400,7 +398,7 @@ func finishUniverse() {
// that we silently skip symbols that are already declared in the // that we silently skip symbols that are already declared in the
// package block rather than emitting a redeclared symbol error. // package block rather than emitting a redeclared symbol error.
for _, s := range builtinpkg.Syms { for _, s := range ir.BuiltinPkg.Syms {
if s.Def == nil { if s.Def == nil {
continue continue
} }
@ -413,8 +411,8 @@ func finishUniverse() {
s1.Block = s.Block s1.Block = s.Block
} }
nodfp = newname(lookup(".fp")) nodfp = NewName(lookup(".fp"))
nodfp.Type = types.Types[TINT32] nodfp.Type = types.Types[types.TINT32]
nodfp.SetClass(PPARAM) nodfp.SetClass(ir.PPARAM)
nodfp.Name.SetUsed(true) nodfp.Name.SetUsed(true)
} }

View file

@ -4,12 +4,15 @@
package gc 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. // evalunsafe evaluates a package unsafe operation and returns the result.
func evalunsafe(n *Node) int64 { func evalunsafe(n *ir.Node) int64 {
switch n.Op { switch n.Op {
case OALIGNOF, OSIZEOF: case ir.OALIGNOF, ir.OSIZEOF:
n.Left = typecheck(n.Left, ctxExpr) n.Left = typecheck(n.Left, ctxExpr)
n.Left = defaultlit(n.Left, nil) n.Left = defaultlit(n.Left, nil)
tr := n.Left.Type tr := n.Left.Type
@ -17,14 +20,14 @@ func evalunsafe(n *Node) int64 {
return 0 return 0
} }
dowidth(tr) dowidth(tr)
if n.Op == OALIGNOF { if n.Op == ir.OALIGNOF {
return int64(tr.Align) return int64(tr.Align)
} }
return tr.Width return tr.Width
case OOFFSETOF: case ir.OOFFSETOF:
// must be a selector. // must be a selector.
if n.Left.Op != OXDOT { if n.Left.Op != ir.OXDOT {
base.Errorf("invalid expression %v", n) base.Errorf("invalid expression %v", n)
return 0 return 0
} }
@ -40,9 +43,9 @@ func evalunsafe(n *Node) int64 {
return 0 return 0
} }
switch n.Left.Op { switch n.Left.Op {
case ODOT, ODOTPTR: case ir.ODOT, ir.ODOTPTR:
break break
case OCALLPART: case ir.OCALLPART:
base.Errorf("invalid expression %v: argument is a method value", n) base.Errorf("invalid expression %v: argument is a method value", n)
return 0 return 0
default: default:
@ -54,7 +57,7 @@ func evalunsafe(n *Node) int64 {
var v int64 var v int64
for r := n.Left; r != sbase; r = r.Left { for r := n.Left; r != sbase; r = r.Left {
switch r.Op { switch r.Op {
case ODOTPTR: case ir.ODOTPTR:
// For Offsetof(s.f), s may itself be a pointer, // For Offsetof(s.f), s may itself be a pointer,
// but accessing f must not otherwise involve // but accessing f must not otherwise involve
// indirection via embedded pointer types. // indirection via embedded pointer types.
@ -63,10 +66,10 @@ func evalunsafe(n *Node) int64 {
return 0 return 0
} }
fallthrough fallthrough
case ODOT: case ir.ODOT:
v += r.Xoffset v += r.Xoffset
default: default:
Dump("unsafenmagic", n.Left) ir.Dump("unsafenmagic", n.Left)
base.Fatalf("impossible %#v node after dot insertion", r.Op) base.Fatalf("impossible %#v node after dot insertion", r.Op)
} }
} }

View file

@ -12,12 +12,6 @@ import (
"cmd/compile/internal/base" "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 ( var (
memprofilerate int64 memprofilerate int64
traceHandler func(string) traceHandler func(string)

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package gc package ir
type bitset8 uint8 type bitset8 uint8

View file

@ -1,6 +1,6 @@
// Code generated by "stringer -type=Class"; DO NOT EDIT. // Code generated by "stringer -type=Class"; DO NOT EDIT.
package gc package ir
import "strconv" import "strconv"

View file

@ -6,22 +6,23 @@
// for debugging purposes. The code is customized for Node graphs // for debugging purposes. The code is customized for Node graphs
// and may be used for an alternative view of the node structure. // and may be used for an alternative view of the node structure.
package gc package ir
import ( import (
"cmd/compile/internal/base"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt" "fmt"
"io" "io"
"os" "os"
"reflect" "reflect"
"regexp" "regexp"
"cmd/compile/internal/base"
"cmd/compile/internal/types"
"cmd/internal/src"
) )
// dump is like fdump but prints to stderr. // dump is like fdump but prints to stderr.
func dump(root interface{}, filter string, depth int) { func DumpAny(root interface{}, filter string, depth int) {
fdump(os.Stderr, root, filter, depth) FDumpAny(os.Stderr, root, filter, depth)
} }
// fdump prints the structure of a rooted data structure // fdump prints the structure of a rooted data structure
@ -41,7 +42,7 @@ func dump(root interface{}, filter string, depth int) {
// rather than their type; struct fields with zero values or // rather than their type; struct fields with zero values or
// non-matching field names are omitted, and "…" means recursion // non-matching field names are omitted, and "…" means recursion
// depth has been reached or struct fields have been omitted. // 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 { if root == nil {
fmt.Fprintln(w, "nil") fmt.Fprintln(w, "nil")
return return
@ -151,7 +152,7 @@ func (p *dumper) dump(x reflect.Value, depth int) {
return return
case *types.Node: case *types.Node:
x = reflect.ValueOf(asNode(v)) x = reflect.ValueOf(AsNode(v))
} }
switch x.Kind() { switch x.Kind() {

View file

@ -2,13 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package gc package ir
import ( import (
"bytes" "bytes"
"cmd/compile/internal/base"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt" "fmt"
"go/constant" "go/constant"
"io" "io"
@ -16,6 +13,10 @@ import (
"strings" "strings"
"sync" "sync"
"unicode/utf8" "unicode/utf8"
"cmd/compile/internal/base"
"cmd/compile/internal/types"
"cmd/internal/src"
) )
// A FmtFlag value is a set of flags (or 0). // A FmtFlag value is a set of flags (or 0).
@ -98,7 +99,7 @@ func fmtFlag(s fmt.State, verb rune) FmtFlag {
// *types.Sym, *types.Type, and *Node types use the flags below to set the format mode // *types.Sym, *types.Type, and *Node types use the flags below to set the format mode
const ( const (
FErr fmtMode = iota FErr FmtMode = iota
FDbg FDbg
FTypeId FTypeId
FTypeIdName // same as FTypeId, but use package name instead of prefix FTypeIdName // same as FTypeId, but use package name instead of prefix
@ -131,7 +132,7 @@ const (
// %- v type identifiers with package name instead of prefix (typesym, dcommontype, typehash) // %- v type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
// update returns the results of applying f to mode. // 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 { switch {
case f&FmtSign != 0: case f&FmtSign != 0:
mode = FDbg mode = FDbg
@ -147,7 +148,7 @@ func (f FmtFlag) update(mode fmtMode) (FmtFlag, fmtMode) {
return f, mode return f, mode
} }
var goopnames = []string{ var OpNames = []string{
OADDR: "&", OADDR: "&",
OADD: "+", OADD: "+",
OADDSTR: "+", OADDSTR: "+",
@ -217,7 +218,7 @@ func (o Op) GoString() string {
return fmt.Sprintf("%#v", o) 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 { switch verb {
case 'v': case 'v':
o.oconv(s, fmtFlag(s, verb), mode) o.oconv(s, fmtFlag(s, verb), mode)
@ -227,10 +228,10 @@ func (o Op) format(s fmt.State, verb rune, mode fmtMode) {
} }
} }
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 flag&FmtSharp != 0 || mode != FDbg {
if int(o) < len(goopnames) && goopnames[o] != "" { if int(o) < len(OpNames) && OpNames[o] != "" {
fmt.Fprint(s, goopnames[o]) fmt.Fprint(s, OpNames[o])
return return
} }
} }
@ -239,66 +240,73 @@ func (o Op) oconv(s fmt.State, flag FmtFlag, mode fmtMode) {
fmt.Fprint(s, o.String()) fmt.Fprint(s, o.String())
} }
type fmtMode int type FmtMode int
type fmtNode struct { type fmtNode struct {
x *Node x *Node
m fmtMode m FmtMode
} }
func (f *fmtNode) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) } func (f *fmtNode) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) }
type fmtOp struct { type fmtOp struct {
x Op x Op
m fmtMode m FmtMode
} }
func (f *fmtOp) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) } func (f *fmtOp) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) }
type fmtType struct { type fmtType struct {
x *types.Type x *types.Type
m fmtMode m FmtMode
} }
func (f *fmtType) Format(s fmt.State, verb rune) { typeFormat(f.x, s, verb, f.m) } func (f *fmtType) Format(s fmt.State, verb rune) { typeFormat(f.x, s, verb, f.m) }
type fmtSym struct { type fmtSym struct {
x *types.Sym x *types.Sym
m fmtMode m FmtMode
} }
func (f *fmtSym) Format(s fmt.State, verb rune) { symFormat(f.x, s, verb, f.m) } func (f *fmtSym) Format(s fmt.State, verb rune) { symFormat(f.x, s, verb, f.m) }
type fmtNodes struct { type fmtNodes struct {
x Nodes x Nodes
m fmtMode m FmtMode
} }
func (f *fmtNodes) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) } 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 (n *Node) Format(s fmt.State, verb rune) {
func (o Op) Format(s fmt.State, verb rune) { o.format(s, verb, FErr) } 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 (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 (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 (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) m.prepareArgs(args)
fmt.Fprintf(s, format, 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) m.prepareArgs(args)
return fmt.Sprintf(format, args...) return fmt.Sprintf(format, args...)
} }
func (m fmtMode) Sprint(args ...interface{}) string { func (m FmtMode) Sprint(args ...interface{}) string {
m.prepareArgs(args) m.prepareArgs(args)
return fmt.Sprint(args...) return fmt.Sprint(args...)
} }
func (m fmtMode) prepareArgs(args []interface{}) { func (m FmtMode) prepareArgs(args []interface{}) {
for i, arg := range args { for i, arg := range args {
switch arg := arg.(type) { switch arg := arg.(type) {
case Op: case Op:
@ -319,13 +327,13 @@ func (m fmtMode) prepareArgs(args []interface{}) {
} }
} }
func (n *Node) format(s fmt.State, verb rune, mode fmtMode) { func (n *Node) format(s fmt.State, verb rune, mode FmtMode) {
switch verb { switch verb {
case 'v', 'S', 'L': case 'v', 'S', 'L':
n.nconv(s, fmtFlag(s, verb), mode) nconvFmt(n, s, fmtFlag(s, verb), mode)
case 'j': case 'j':
n.jconv(s, fmtFlag(s, verb)) jconvFmt(n, s, fmtFlag(s, verb))
default: default:
fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n) fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)
@ -336,7 +344,7 @@ func (n *Node) format(s fmt.State, verb rune, mode fmtMode) {
var EscFmt func(n *Node, short bool) string var EscFmt func(n *Node, short bool) string
// *Node details // *Node details
func (n *Node) jconv(s fmt.State, flag FmtFlag) { func jconvFmt(n *Node, s fmt.State, flag FmtFlag) {
short := flag&FmtShort != 0 short := flag&FmtShort != 0
// Useful to see which nodes in an AST printout are actually identical // Useful to see which nodes in an AST printout are actually identical
@ -363,7 +371,7 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) {
fmt.Fprintf(s, " l(%s%d)", pfx, n.Pos.Line()) 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) fmt.Fprintf(s, " x(%d)", n.Xoffset)
} }
@ -430,7 +438,7 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) {
} }
} }
func vconv(v constant.Value, flag FmtFlag) string { func FmtConst(v constant.Value, flag FmtFlag) string {
if flag&FmtSharp == 0 && v.Kind() == constant.Complex { if flag&FmtSharp == 0 && v.Kind() == constant.Complex {
real, imag := constant.Real(v), constant.Imag(v) real, imag := constant.Real(v), constant.Imag(v)
@ -473,17 +481,17 @@ s%^ ........*\]%&~%g
s%~ %%g 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 { if flag&FmtShort == 0 {
switch mode { switch mode {
case FErr: // This is for the user 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) b.WriteString(s.Name)
return return
} }
// If the name was used by multiple packages, display the full path, // 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) fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name)
return return
} }
@ -534,28 +542,28 @@ func symfmt(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode fmtMode) {
b.WriteString(s.Name) b.WriteString(s.Name)
} }
var basicnames = []string{ var BasicTypeNames = []string{
TINT: "int", types.TINT: "int",
TUINT: "uint", types.TUINT: "uint",
TINT8: "int8", types.TINT8: "int8",
TUINT8: "uint8", types.TUINT8: "uint8",
TINT16: "int16", types.TINT16: "int16",
TUINT16: "uint16", types.TUINT16: "uint16",
TINT32: "int32", types.TINT32: "int32",
TUINT32: "uint32", types.TUINT32: "uint32",
TINT64: "int64", types.TINT64: "int64",
TUINT64: "uint64", types.TUINT64: "uint64",
TUINTPTR: "uintptr", types.TUINTPTR: "uintptr",
TFLOAT32: "float32", types.TFLOAT32: "float32",
TFLOAT64: "float64", types.TFLOAT64: "float64",
TCOMPLEX64: "complex64", types.TCOMPLEX64: "complex64",
TCOMPLEX128: "complex128", types.TCOMPLEX128: "complex128",
TBOOL: "bool", types.TBOOL: "bool",
TANY: "any", types.TANY: "any",
TSTRING: "string", types.TSTRING: "string",
TNIL: "nil", types.TNIL: "nil",
TIDEAL: "untyped number", types.TIDEAL: "untyped number",
TBLANK: "blank", types.TBLANK: "blank",
} }
var fmtBufferPool = sync.Pool{ var fmtBufferPool = sync.Pool{
@ -564,7 +572,7 @@ 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 := fmtBufferPool.Get().(*bytes.Buffer)
buf.Reset() buf.Reset()
defer fmtBufferPool.Put(buf) defer fmtBufferPool.Put(buf)
@ -577,7 +585,7 @@ func tconv(t *types.Type, flag FmtFlag, mode fmtMode) string {
// flag and mode control exactly what is printed. // 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]. // 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. // 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 { if off, ok := visited[t]; ok {
// We've seen this type before, so we're trying to print it recursively. // We've seen this type before, so we're trying to print it recursively.
// Print a reference to it instead. // Print a reference to it instead.
@ -648,7 +656,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
return 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)) b.WriteString(mode.Sprintf("%v·%d", t.Sym, t.Vargen))
return return
} }
@ -658,7 +666,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
return return
} }
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" { if int(t.Etype) < len(BasicTypeNames) && BasicTypeNames[t.Etype] != "" {
var name string var name string
switch t { switch t {
case types.UntypedBool: case types.UntypedBool:
@ -674,7 +682,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
case types.UntypedComplex: case types.UntypedComplex:
name = "untyped complex" name = "untyped complex"
default: default:
name = basicnames[t.Etype] name = BasicTypeNames[t.Etype]
} }
b.WriteString(name) b.WriteString(name)
return return
@ -701,7 +709,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
defer delete(visited, t) defer delete(visited, t)
switch t.Etype { switch t.Etype {
case TPTR: case types.TPTR:
b.WriteByte('*') b.WriteByte('*')
switch mode { switch mode {
case FTypeId, FTypeIdName: case FTypeId, FTypeIdName:
@ -712,17 +720,17 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
} }
tconv2(b, t.Elem(), 0, mode, visited) tconv2(b, t.Elem(), 0, mode, visited)
case TARRAY: case types.TARRAY:
b.WriteByte('[') b.WriteByte('[')
b.WriteString(strconv.FormatInt(t.NumElem(), 10)) b.WriteString(strconv.FormatInt(t.NumElem(), 10))
b.WriteByte(']') b.WriteByte(']')
tconv2(b, t.Elem(), 0, mode, visited) tconv2(b, t.Elem(), 0, mode, visited)
case TSLICE: case types.TSLICE:
b.WriteString("[]") b.WriteString("[]")
tconv2(b, t.Elem(), 0, mode, visited) tconv2(b, t.Elem(), 0, mode, visited)
case TCHAN: case types.TCHAN:
switch t.ChanDir() { switch t.ChanDir() {
case types.Crecv: case types.Crecv:
b.WriteString("<-chan ") b.WriteString("<-chan ")
@ -741,13 +749,13 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
} }
} }
case TMAP: case types.TMAP:
b.WriteString("map[") b.WriteString("map[")
tconv2(b, t.Key(), 0, mode, visited) tconv2(b, t.Key(), 0, mode, visited)
b.WriteByte(']') b.WriteByte(']')
tconv2(b, t.Elem(), 0, mode, visited) tconv2(b, t.Elem(), 0, mode, visited)
case TINTER: case types.TINTER:
if t.IsEmptyInterface() { if t.IsEmptyInterface() {
b.WriteString("interface {}") b.WriteString("interface {}")
break break
@ -779,7 +787,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
} }
b.WriteByte('}') b.WriteByte('}')
case TFUNC: case types.TFUNC:
if flag&FmtShort != 0 { if flag&FmtShort != 0 {
// no leading func // no leading func
} else { } else {
@ -805,7 +813,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
tconv2(b, t.Results(), 0, mode, visited) tconv2(b, t.Results(), 0, mode, visited)
} }
case TSTRUCT: case types.TSTRUCT:
if m := t.StructType().Map; m != nil { if m := t.StructType().Map; m != nil {
mt := m.MapType() mt := m.MapType()
// Format the bucket struct for map[x]y as map.bucket[x]y. // Format the bucket struct for map[x]y as map.bucket[x]y.
@ -856,17 +864,17 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
b.WriteByte('}') b.WriteByte('}')
} }
case TFORW: case types.TFORW:
b.WriteString("undefined") b.WriteString("undefined")
if t.Sym != nil { if t.Sym != nil {
b.WriteByte(' ') b.WriteByte(' ')
sconv2(b, t.Sym, 0, mode) sconv2(b, t.Sym, 0, mode)
} }
case TUNSAFEPTR: case types.TUNSAFEPTR:
b.WriteString("unsafe.Pointer") b.WriteString("unsafe.Pointer")
case Txxx: case types.Txxx:
b.WriteString("Txxx") b.WriteString("Txxx")
default: default:
// Don't know how to handle - fall back to detailed prints. // Don't know how to handle - fall back to detailed prints.
@ -875,7 +883,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
} }
// Statements which may be rendered with a simplestmt as init. // Statements which may be rendered with a simplestmt as init.
func stmtwithinit(op Op) bool { func StmtWithInit(op Op) bool {
switch op { switch op {
case OIF, OFOR, OFORUNTIL, OSWITCH: case OIF, OFOR, OFORUNTIL, OSWITCH:
return true return true
@ -884,20 +892,20 @@ func stmtwithinit(op Op) bool {
return false 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, // some statements allow for an init, but at most one,
// but we may have an arbitrary number added, eg by typecheck // but we may have an arbitrary number added, eg by typecheck
// and inlining. If it doesn't fit the syntax, emit an enclosing // and inlining. If it doesn't fit the syntax, emit an enclosing
// block starting with the init statements. // block starting with the init statements.
// if we can just say "for" n->ninit; ... then do so // 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 // otherwise, print the inits as separate statements
complexinit := n.Ninit.Len() != 0 && !simpleinit && (mode != FErr) 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 // 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 { if extrablock {
fmt.Fprint(s, "{") fmt.Fprint(s, "{")
@ -1064,7 +1072,7 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
} }
} }
var opprec = []int{ var OpPrec = []int{
OALIGNOF: 8, OALIGNOF: 8,
OAPPEND: 8, OAPPEND: 8,
OBYTES2STR: 8, OBYTES2STR: 8,
@ -1184,7 +1192,7 @@ var opprec = []int{
OEND: 0, 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) { for n != nil && n.Implicit() && (n.Op == ODEREF || n.Op == OADDR) {
n = n.Left n = n.Left
} }
@ -1194,7 +1202,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
return return
} }
nprec := opprec[n.Op] nprec := OpPrec[n.Op]
if n.Op == OTYPE && n.Sym != nil { if n.Op == OTYPE && n.Sym != nil {
nprec = 8 nprec = 8
} }
@ -1214,7 +1222,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
case OLITERAL: // this is a bit of a mess case OLITERAL: // this is a bit of a mess
if mode == FErr { if mode == FErr {
if n.Orig != nil && n.Orig != n { if n.Orig != nil && n.Orig != n {
n.Orig.exprfmt(s, prec, mode) exprFmt(n.Orig, s, prec, mode)
return return
} }
if n.Sym != nil { if n.Sym != nil {
@ -1252,7 +1260,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
fmt.Fprintf(s, "'\\U%08x'", uint64(x)) fmt.Fprintf(s, "'\\U%08x'", uint64(x))
} }
} else { } else {
fmt.Fprint(s, vconv(n.Val(), fmtFlag(s, 'v'))) fmt.Fprint(s, FmtConst(n.Val(), fmtFlag(s, 'v')))
} }
if needUnparen { if needUnparen {
@ -1369,7 +1377,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
mode.Fprintf(s, "%v:%v", n.Sym, n.Left) mode.Fprintf(s, "%v:%v", n.Sym, n.Left)
case OCALLPART: case OCALLPART:
n.Left.exprfmt(s, nprec, mode) exprFmt(n.Left, s, nprec, mode)
if n.Right == nil || n.Right.Sym == nil { if n.Right == nil || n.Right.Sym == nil {
fmt.Fprint(s, ".<nil>") fmt.Fprint(s, ".<nil>")
return return
@ -1377,7 +1385,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
mode.Fprintf(s, ".%0S", n.Right.Sym) mode.Fprintf(s, ".%0S", n.Right.Sym)
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
n.Left.exprfmt(s, nprec, mode) exprFmt(n.Left, s, nprec, mode)
if n.Sym == nil { if n.Sym == nil {
fmt.Fprint(s, ".<nil>") fmt.Fprint(s, ".<nil>")
return return
@ -1385,7 +1393,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
mode.Fprintf(s, ".%0S", n.Sym) mode.Fprintf(s, ".%0S", n.Sym)
case ODOTTYPE, ODOTTYPE2: case ODOTTYPE, ODOTTYPE2:
n.Left.exprfmt(s, nprec, mode) exprFmt(n.Left, s, nprec, mode)
if n.Right != nil { if n.Right != nil {
mode.Fprintf(s, ".(%v)", n.Right) mode.Fprintf(s, ".(%v)", n.Right)
return return
@ -1393,24 +1401,24 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
mode.Fprintf(s, ".(%v)", n.Type) mode.Fprintf(s, ".(%v)", n.Type)
case OINDEX, OINDEXMAP: case OINDEX, OINDEXMAP:
n.Left.exprfmt(s, nprec, mode) exprFmt(n.Left, s, nprec, mode)
mode.Fprintf(s, "[%v]", n.Right) mode.Fprintf(s, "[%v]", n.Right)
case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
n.Left.exprfmt(s, nprec, mode) exprFmt(n.Left, s, nprec, mode)
fmt.Fprint(s, "[") fmt.Fprint(s, "[")
low, high, max := n.SliceBounds() low, high, max := n.SliceBounds()
if low != nil { if low != nil {
fmt.Fprint(s, low.modeString(mode)) fmt.Fprint(s, modeString(low, mode))
} }
fmt.Fprint(s, ":") fmt.Fprint(s, ":")
if high != nil { if high != nil {
fmt.Fprint(s, high.modeString(mode)) fmt.Fprint(s, modeString(high, mode))
} }
if n.Op.IsSlice3() { if n.Op.IsSlice3() {
fmt.Fprint(s, ":") fmt.Fprint(s, ":")
if max != nil { if max != nil {
fmt.Fprint(s, max.modeString(mode)) fmt.Fprint(s, modeString(max, mode))
} }
} }
fmt.Fprint(s, "]") fmt.Fprint(s, "]")
@ -1474,7 +1482,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
mode.Fprintf(s, "%#v(%.v)", n.Op, n.List) mode.Fprintf(s, "%#v(%.v)", n.Op, n.List)
case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG: case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
n.Left.exprfmt(s, nprec, mode) exprFmt(n.Left, s, nprec, mode)
if n.IsDDD() { if n.IsDDD() {
mode.Fprintf(s, "(%.v...)", n.List) mode.Fprintf(s, "(%.v...)", n.List)
return return
@ -1505,7 +1513,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
if n.Left != nil && n.Left.Op == n.Op { if n.Left != nil && n.Left.Op == n.Op {
fmt.Fprint(s, " ") fmt.Fprint(s, " ")
} }
n.Left.exprfmt(s, nprec+1, mode) exprFmt(n.Left, s, nprec+1, mode)
// Binary // Binary
case OADD, case OADD,
@ -1528,16 +1536,16 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
OSEND, OSEND,
OSUB, OSUB,
OXOR: OXOR:
n.Left.exprfmt(s, nprec, mode) exprFmt(n.Left, s, nprec, mode)
mode.Fprintf(s, " %#v ", n.Op) mode.Fprintf(s, " %#v ", n.Op)
n.Right.exprfmt(s, nprec+1, mode) exprFmt(n.Right, s, nprec+1, mode)
case OADDSTR: case OADDSTR:
for i, n1 := range n.List.Slice() { for i, n1 := range n.List.Slice() {
if i != 0 { if i != 0 {
fmt.Fprint(s, " + ") fmt.Fprint(s, " + ")
} }
n1.exprfmt(s, nprec, mode) exprFmt(n1, s, nprec, mode)
} }
case ODDD: case ODDD:
mode.Fprintf(s, "...") mode.Fprintf(s, "...")
@ -1546,7 +1554,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
} }
} }
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 t := n.Type
// We almost always want the original. // We almost always want the original.
@ -1556,7 +1564,7 @@ func (n *Node) nodefmt(s fmt.State, flag FmtFlag, mode fmtMode) {
} }
if flag&FmtLong != 0 && t != nil { if flag&FmtLong != 0 && t != nil {
if t.Etype == TNIL { if t.Etype == types.TNIL {
fmt.Fprint(s, "nil") fmt.Fprint(s, "nil")
} else if n.Op == ONAME && n.Name.AutoTemp() { } else if n.Op == ONAME && n.Name.AutoTemp() {
mode.Fprintf(s, "%v value", t) mode.Fprintf(s, "%v value", t)
@ -1568,15 +1576,15 @@ func (n *Node) nodefmt(s fmt.State, flag FmtFlag, mode fmtMode) {
// TODO inlining produces expressions with ninits. we can't print these yet. // TODO inlining produces expressions with ninits. we can't print these yet.
if opprec[n.Op] < 0 { if OpPrec[n.Op] < 0 {
n.stmtfmt(s, mode) stmtFmt(n, s, mode)
return 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 recur := flag&FmtShort == 0
if recur { if recur {
@ -1647,7 +1655,7 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
if n.Op == ODCLFUNC && n.Func != nil && n.Func.Dcl != nil && len(n.Func.Dcl) != 0 { if n.Op == ODCLFUNC && n.Func != nil && n.Func.Dcl != nil && len(n.Func.Dcl) != 0 {
indent(s) indent(s)
// The dcls for a func or closure // 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 { if n.List.Len() != 0 {
indent(s) indent(s)
@ -1667,7 +1675,7 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
} }
// "%S" suppresses qualifying with package // "%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 { switch verb {
case 'v', 'S': case 'v', 'S':
fmt.Fprint(f, sconv(s, fmtFlag(f, verb), mode)) fmt.Fprint(f, sconv(s, fmtFlag(f, verb), mode))
@ -1677,10 +1685,10 @@ func symFormat(s *types.Sym, f fmt.State, verb rune, mode fmtMode) {
} }
} }
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. // 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 { if flag&FmtLong != 0 {
panic("linksymfmt") panic("linksymfmt")
} }
@ -1701,7 +1709,7 @@ func sconv(s *types.Sym, flag FmtFlag, mode fmtMode) string {
return types.InternString(buf.Bytes()) 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 { if flag&FmtLong != 0 {
panic("linksymfmt") panic("linksymfmt")
} }
@ -1718,7 +1726,7 @@ func sconv2(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode fmtMode) {
symfmt(b, s, flag, mode) 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 { if f == nil {
b.WriteString("<T>") b.WriteString("<T>")
return return
@ -1734,12 +1742,12 @@ func fldconv(b *bytes.Buffer, f *types.Field, flag FmtFlag, mode fmtMode, visite
// Take the name from the original. // Take the name from the original.
if mode == FErr { if mode == FErr {
s = origSym(s) s = OrigSym(s)
} }
if s != nil && f.Embedded == 0 { if s != nil && f.Embedded == 0 {
if funarg != types.FunargNone { if funarg != types.FunargNone {
name = asNode(f.Nname).modeString(mode) name = modeString(AsNode(f.Nname), mode)
} else if flag&FmtLong != 0 { } else if flag&FmtLong != 0 {
name = mode.Sprintf("%0S", s) name = mode.Sprintf("%0S", s)
if !types.IsExported(name) && flag&FmtUnsigned == 0 { if !types.IsExported(name) && flag&FmtUnsigned == 0 {
@ -1775,7 +1783,7 @@ func fldconv(b *bytes.Buffer, f *types.Field, flag FmtFlag, mode fmtMode, visite
// "%L" print definition, not name // "%L" print definition, not name
// "%S" omit 'func' and receiver from function types, short type names // "%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 { switch verb {
case 'v', 'S', 'L': case 'v', 'S', 'L':
fmt.Fprint(s, tconv(t, fmtFlag(s, verb), mode)) fmt.Fprint(s, tconv(t, fmtFlag(s, verb), mode))
@ -1784,12 +1792,12 @@ func typeFormat(t *types.Type, s fmt.State, verb rune, mode fmtMode) {
} }
} }
func (n *Node) String() string { return fmt.Sprint(n) } func (n *Node) String() string { return fmt.Sprint(n) }
func (n *Node) modeString(mode fmtMode) string { return mode.Sprint(n) } func modeString(n *Node, mode FmtMode) string { return mode.Sprint(n) }
// "%L" suffix with "(type %T)" where possible // "%L" suffix with "(type %T)" where possible
// "%+S" in debug mode, don't recurse, no multiline output // "%+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 { if n == nil {
fmt.Fprint(s, "<N>") fmt.Fprint(s, "<N>")
return return
@ -1799,11 +1807,11 @@ func (n *Node) nconv(s fmt.State, flag FmtFlag, mode fmtMode) {
switch mode { switch mode {
case FErr: case FErr:
n.nodefmt(s, flag, mode) nodeFmt(n, s, flag, mode)
case FDbg: case FDbg:
dumpdepth++ dumpdepth++
n.nodedump(s, flag, mode) nodeDumpFmt(n, s, flag, mode)
dumpdepth-- dumpdepth--
default: default:
@ -1811,7 +1819,7 @@ func (n *Node) nconv(s fmt.State, flag FmtFlag, mode fmtMode) {
} }
} }
func (l Nodes) format(s fmt.State, verb rune, mode fmtMode) { func (l Nodes) format(s fmt.State, verb rune, mode FmtMode) {
switch verb { switch verb {
case 'v': case 'v':
l.hconv(s, fmtFlag(s, verb), mode) l.hconv(s, fmtFlag(s, verb), mode)
@ -1826,7 +1834,7 @@ func (n Nodes) String() string {
} }
// Flags: all those of %N plus '.': separate with comma's instead of semicolons. // 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 { if l.Len() == 0 && mode == FDbg {
fmt.Fprint(s, "<nil>") fmt.Fprint(s, "<nil>")
return return
@ -1841,18 +1849,18 @@ func (l Nodes) hconv(s fmt.State, flag FmtFlag, mode fmtMode) {
} }
for i, n := range l.Slice() { for i, n := range l.Slice() {
fmt.Fprint(s, n.modeString(mode)) fmt.Fprint(s, modeString(n, mode))
if i+1 < l.Len() { if i+1 < l.Len() {
fmt.Fprint(s, sep) fmt.Fprint(s, sep)
} }
} }
} }
func dumplist(s string, l Nodes) { func DumpList(s string, l Nodes) {
fmt.Printf("%s%+v\n", s, l) 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) fmt.Fprintf(w, "%s%+v\n", s, l)
} }
@ -1877,3 +1885,30 @@ func ellipsisIf(b bool) string {
} }
return "" 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)
}

View file

@ -0,0 +1,12 @@
// 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

View file

@ -4,17 +4,20 @@
// “Abstract” syntax representation. // “Abstract” syntax representation.
package gc package ir
import ( import (
"go/constant"
"sort"
"strings"
"unsafe"
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/src" "cmd/internal/src"
"go/constant"
"sort"
) )
// A Node is a single node in the syntax tree. // A Node is a single node in the syntax tree.
@ -290,7 +293,7 @@ func (n *Node) SetVal(v constant.Value) {
base.Fatalf("have Opt") base.Fatalf("have Opt")
} }
if n.Op == OLITERAL { if n.Op == OLITERAL {
assertRepresents(n.Type, v) AssertValidTypeForConst(n.Type, v)
} }
n.SetHasVal(true) n.SetHasVal(true)
n.E = &v n.E = &v
@ -333,7 +336,7 @@ func (n *Node) SetIota(x int64) {
// mayBeShared reports whether n may occur in multiple places in the AST. // mayBeShared reports whether n may occur in multiple places in the AST.
// Extra care must be taken when mutating such a node. // Extra care must be taken when mutating such a node.
func (n *Node) mayBeShared() bool { func MayBeShared(n *Node) bool {
switch n.Op { switch n.Op {
case ONAME, OLITERAL, ONIL, OTYPE: case ONAME, OLITERAL, ONIL, OTYPE:
return true return true
@ -342,7 +345,7 @@ func (n *Node) mayBeShared() bool {
} }
// funcname returns the name (without the package) of the function n. // 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 { if n == nil || n.Func == nil || n.Func.Nname == nil {
return "<nil>" return "<nil>"
} }
@ -353,7 +356,7 @@ func (n *Node) funcname() string {
// This differs from the compiler's internal convention where local functions lack a package // 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 // 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. // if the compilation package is actually the empty string.
func (n *Node) pkgFuncName() string { func PkgFuncName(n *Node) string {
var s *types.Sym var s *types.Sym
if n == nil { if n == nil {
return "<nil>" return "<nil>"
@ -681,7 +684,7 @@ type Func struct {
FieldTrack map[*types.Sym]struct{} FieldTrack map[*types.Sym]struct{}
DebugInfo *ssa.FuncDebug DebugInfo *ssa.FuncDebug
lsym *obj.LSym LSym *obj.LSym
Inl *Inline Inl *Inline
@ -693,13 +696,13 @@ type Func struct {
Pragma PragmaFlag // go:xxx function annotations Pragma PragmaFlag // go:xxx function annotations
flags bitset16 flags bitset16
numDefers int // number of defer calls in the function NumDefers int // number of defer calls in the function
numReturns int // number of explicit returns in the function NumReturns int // number of explicit returns in the function
// nwbrCalls records the LSyms of functions called by this // nwbrCalls records the LSyms of functions called by this
// function for go:nowritebarrierrec analysis. Only filled in // function for go:nowritebarrierrec analysis. Only filled in
// if nowritebarrierrecCheck != nil. // if nowritebarrierrecCheck != nil.
nwbrCalls *[]nowritebarrierrecCallSym NWBRCalls *[]SymAndPos
} }
// An Inline holds fields used for function bodies that can be inlined. // An Inline holds fields used for function bodies that can be inlined.
@ -764,7 +767,7 @@ func (f *Func) SetExportInline(b bool) { f.flags.set(funcExportInlin
func (f *Func) SetInstrumentBody(b bool) { f.flags.set(funcInstrumentBody, b) } 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) 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 { if base.Debug.WB != 0 {
base.WarnfAt(pos, "write barrier") base.WarnfAt(pos, "write barrier")
} }
@ -996,7 +999,7 @@ const (
type Nodes struct{ slice *[]*Node } type Nodes struct{ slice *[]*Node }
// asNodes returns a slice of *Node as a Nodes value. // asNodes returns a slice of *Node as a Nodes value.
func asNodes(s []*Node) Nodes { func AsNodes(s []*Node) Nodes {
return Nodes{&s} return Nodes{&s}
} }
@ -1136,38 +1139,38 @@ func (n *Nodes) AppendNodes(n2 *Nodes) {
// inspect invokes f on each node in an AST in depth-first order. // inspect invokes f on each node in an AST in depth-first order.
// If f(n) returns false, inspect skips visiting n's children. // 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) { if n == nil || !f(n) {
return return
} }
inspectList(n.Ninit, f) InspectList(n.Ninit, f)
inspect(n.Left, f) Inspect(n.Left, f)
inspect(n.Right, f) Inspect(n.Right, f)
inspectList(n.List, f) InspectList(n.List, f)
inspectList(n.Nbody, f) InspectList(n.Nbody, f)
inspectList(n.Rlist, 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() { for _, n := range l.Slice() {
inspect(n, f) Inspect(n, f)
} }
} }
// nodeQueue is a FIFO queue of *Node. The zero value of nodeQueue is // nodeQueue is a FIFO queue of *Node. The zero value of nodeQueue is
// a ready-to-use empty queue. // a ready-to-use empty queue.
type nodeQueue struct { type NodeQueue struct {
ring []*Node ring []*Node
head, tail int head, tail int
} }
// empty reports whether q contains no Nodes. // empty reports whether q contains no Nodes.
func (q *nodeQueue) empty() bool { func (q *NodeQueue) Empty() bool {
return q.head == q.tail return q.head == q.tail
} }
// pushRight appends n to the right of the queue. // 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 { if len(q.ring) == 0 {
q.ring = make([]*Node, 16) q.ring = make([]*Node, 16)
} else if q.head+len(q.ring) == q.tail { } else if q.head+len(q.ring) == q.tail {
@ -1191,8 +1194,8 @@ func (q *nodeQueue) pushRight(n *Node) {
// popLeft pops a node from the left of the queue. It panics if q is // popLeft pops a node from the left of the queue. It panics if q is
// empty. // empty.
func (q *nodeQueue) popLeft() *Node { func (q *NodeQueue) PopLeft() *Node {
if q.empty() { if q.Empty() {
panic("dequeue empty") panic("dequeue empty")
} }
n := q.ring[q.head%len(q.ring)] n := q.ring[q.head%len(q.ring)]
@ -1226,3 +1229,342 @@ func (s NodeSet) Sorted(less func(*Node, *Node) bool) []*Node {
sort.Slice(res, func(i, j int) bool { return less(res[i], res[j]) }) sort.Slice(res, func(i, j int) bool { return less(res[i], res[j]) })
return res 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 &copy
}
// 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 = &copy
return &copy
}
// 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 = &copy
}
return &copy
}
// 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
}
}

View file

@ -1,6 +1,6 @@
// Code generated by "stringer -type=Op -trimprefix=O"; DO NOT EDIT. // Code generated by "stringer -type=Op -trimprefix=O"; DO NOT EDIT.
package gc package ir
import "strconv" import "strconv"

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package gc package ir
import ( import (
"reflect" "reflect"

View file

@ -0,0 +1,120 @@
// 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

View file

@ -9,6 +9,7 @@ import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/gc" "cmd/compile/internal/gc"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
@ -288,7 +289,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case *obj.LSym: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *gc.Node: case *ir.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:

View file

@ -9,6 +9,7 @@ import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/gc" "cmd/compile/internal/gc"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
@ -262,7 +263,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case *obj.LSym: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *gc.Node: case *ir.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:

View file

@ -7,6 +7,7 @@ package ppc64
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/gc" "cmd/compile/internal/gc"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
@ -751,7 +752,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
} }
case *obj.LSym, *gc.Node: case *obj.LSym, *ir.Node:
p := s.Prog(ppc64.AMOVD) p := s.Prog(ppc64.AMOVD)
p.From.Type = obj.TYPE_ADDR p.From.Type = obj.TYPE_ADDR
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()

View file

@ -7,6 +7,7 @@ package riscv64
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/gc" "cmd/compile/internal/gc"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
@ -323,7 +324,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case *obj.LSym: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *gc.Node: case *ir.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:

View file

@ -7,6 +7,7 @@ package wasm
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/gc" "cmd/compile/internal/gc"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/types" "cmd/compile/internal/types"
@ -236,7 +237,7 @@ func ssaGenValueOnStack(s *gc.SSAGenState, v *ssa.Value, extend bool) {
switch v.Aux.(type) { switch v.Aux.(type) {
case *obj.LSym: case *obj.LSym:
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *gc.Node: case *ir.Node:
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
default: default:

View file

@ -42,6 +42,7 @@ var bootstrapDirs = []string{
"cmd/compile/internal/arm", "cmd/compile/internal/arm",
"cmd/compile/internal/arm64", "cmd/compile/internal/arm64",
"cmd/compile/internal/gc", "cmd/compile/internal/gc",
"cmd/compile/internal/ir",
"cmd/compile/internal/logopt", "cmd/compile/internal/logopt",
"cmd/compile/internal/mips", "cmd/compile/internal/mips",
"cmd/compile/internal/mips64", "cmd/compile/internal/mips64",