[dev.cc] cmd/internal/gc, cmd/new6g etc: convert from cmd/gc, cmd/6g etc
First draft of converted Go compiler, using rsc.io/c2go rev 83d795a.
Change-Id: I29f4c7010de07d2ff1947bbca9865879d83c32c3
Reviewed-on: https://go-review.googlesource.com/4851
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/internal/gc/gsubr.go
new file mode 100644
index 0000000..6762171
--- /dev/null
+++ b/src/cmd/internal/gc/gsubr.go
@@ -0,0 +1,617 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package gc
+
+import "cmd/internal/obj"
+
+var ddumped int
+
+var dfirst *obj.Prog
+
+var dpc *obj.Prog
+
+/*
+ * Is this node a memory operand?
+ */
+func Ismem(n *Node) int {
+ switch n.Op {
+ case OITAB,
+ OSPTR,
+ OLEN,
+ OCAP,
+ OINDREG,
+ ONAME,
+ OPARAM,
+ OCLOSUREVAR:
+ return 1
+
+ case OADDR:
+ return bool2int(Thearch.Thechar == '6' || Thearch.Thechar == '9') // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
+ }
+
+ return 0
+}
+
+func Samereg(a *Node, b *Node) int {
+ if a == nil || b == nil {
+ return 0
+ }
+ if a.Op != OREGISTER {
+ return 0
+ }
+ if b.Op != OREGISTER {
+ return 0
+ }
+ if a.Val.U.Reg != b.Val.U.Reg {
+ return 0
+ }
+ return 1
+}
+
+/*
+ * gsubr.c
+ */
+func Gbranch(as int, t *Type, likely int) *obj.Prog {
+ var p *obj.Prog
+
+ p = Prog(as)
+ p.To.Type = obj.TYPE_BRANCH
+ p.To.U.Branch = nil
+ if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' {
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = int64(bool2int(likely > 0))
+ }
+
+ return p
+}
+
+func Prog(as int) *obj.Prog {
+ var p *obj.Prog
+
+ if as == obj.ADATA || as == obj.AGLOBL {
+ if ddumped != 0 {
+ Fatal("already dumped data")
+ }
+ if dpc == nil {
+ dpc = Ctxt.NewProg()
+ dfirst = dpc
+ }
+
+ p = dpc
+ dpc = Ctxt.NewProg()
+ p.Link = dpc
+ } else {
+ p = Pc
+ Pc = Ctxt.NewProg()
+ Clearp(Pc)
+ p.Link = Pc
+ }
+
+ if lineno == 0 {
+ if Debug['K'] != 0 {
+ Warn("prog: line 0")
+ }
+ }
+
+ p.As = int16(as)
+ p.Lineno = lineno
+ return p
+}
+
+func Nodreg(n *Node, t *Type, r int) {
+ if t == nil {
+ Fatal("nodreg: t nil")
+ }
+
+ *n = Node{}
+ n.Op = OREGISTER
+ n.Addable = 1
+ ullmancalc(n)
+ n.Val.U.Reg = int16(r)
+ n.Type = t
+}
+
+func Nodindreg(n *Node, t *Type, r int) {
+ Nodreg(n, t, r)
+ n.Op = OINDREG
+}
+
+func Afunclit(a *obj.Addr, n *Node) {
+ if a.Type == obj.TYPE_ADDR && a.Name == obj.NAME_EXTERN {
+ a.Type = obj.TYPE_MEM
+ a.Sym = Linksym(n.Sym)
+ }
+}
+
+func Clearp(p *obj.Prog) {
+ obj.Nopout(p)
+ p.As = obj.AEND
+ p.Pc = int64(pcloc)
+ pcloc++
+}
+
+func dumpdata() {
+ ddumped = 1
+ if dfirst == nil {
+ return
+ }
+ newplist()
+ *Pc = *dfirst
+ Pc = dpc
+ Clearp(Pc)
+}
+
+func fixautoused(p *obj.Prog) {
+ var lp **obj.Prog
+
+ for lp = &p; ; {
+ p = *lp
+ if !(p != nil) {
+ break
+ }
+ if p.As == obj.ATYPE && p.From.Node != nil && p.From.Name == obj.NAME_AUTO && !(((p.From.Node).(*Node)).Used != 0) {
+ *lp = p.Link
+ continue
+ }
+
+ if (p.As == obj.AVARDEF || p.As == obj.AVARKILL) && p.To.Node != nil && !(((p.To.Node).(*Node)).Used != 0) {
+ // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
+ // VARDEFs are interspersed with other code, and a jump might be using the
+ // VARDEF as a target. Replace with a no-op instead. A later pass will remove
+ // the no-ops.
+ obj.Nopout(p)
+
+ continue
+ }
+
+ if p.From.Name == obj.NAME_AUTO && p.From.Node != nil {
+ p.From.Offset += ((p.From.Node).(*Node)).Stkdelta
+ }
+
+ if p.To.Name == obj.NAME_AUTO && p.To.Node != nil {
+ p.To.Offset += ((p.To.Node).(*Node)).Stkdelta
+ }
+
+ lp = &p.Link
+ }
+}
+
+func ggloblnod(nam *Node) {
+ var p *obj.Prog
+
+ p = Thearch.Gins(obj.AGLOBL, nam, nil)
+ p.Lineno = nam.Lineno
+ p.From.Sym.Gotype = Linksym(ngotype(nam))
+ p.To.Sym = nil
+ p.To.Type = obj.TYPE_CONST
+ p.To.Offset = nam.Type.Width
+ if nam.Readonly != 0 {
+ p.From3.Offset = obj.RODATA
+ }
+ if nam.Type != nil && !haspointers(nam.Type) {
+ p.From3.Offset |= obj.NOPTR
+ }
+}
+
+func ggloblsym(s *Sym, width int32, flags int8) {
+ var p *obj.Prog
+
+ p = Thearch.Gins(obj.AGLOBL, nil, nil)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Name = obj.NAME_EXTERN
+ p.From.Sym = Linksym(s)
+ p.To.Type = obj.TYPE_CONST
+ p.To.Offset = int64(width)
+ p.From3.Offset = int64(flags)
+}
+
+func gjmp(to *obj.Prog) *obj.Prog {
+ var p *obj.Prog
+
+ p = Gbranch(obj.AJMP, nil, 0)
+ if to != nil {
+ Patch(p, to)
+ }
+ return p
+}
+
+func gtrack(s *Sym) {
+ var p *obj.Prog
+
+ p = Thearch.Gins(obj.AUSEFIELD, nil, nil)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Name = obj.NAME_EXTERN
+ p.From.Sym = Linksym(s)
+}
+
+func gused(n *Node) {
+ Thearch.Gins(obj.ANOP, n, nil) // used
+}
+
+func Isfat(t *Type) int {
+ if t != nil {
+ switch t.Etype {
+ case TSTRUCT,
+ TARRAY,
+ TSTRING,
+ TINTER: // maybe remove later
+ return 1
+ }
+ }
+
+ return 0
+}
+
+func markautoused(p *obj.Prog) {
+ for ; p != nil; p = p.Link {
+ if p.As == obj.ATYPE || p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+ continue
+ }
+
+ if p.From.Node != nil {
+ ((p.From.Node).(*Node)).Used = 1
+ }
+
+ if p.To.Node != nil {
+ ((p.To.Node).(*Node)).Used = 1
+ }
+ }
+}
+
+func Naddr(n *Node, a *obj.Addr, canemitcode int) {
+ var s *Sym
+
+ *a = obj.Zprog.From
+ if n == nil {
+ return
+ }
+
+ if n.Type != nil && n.Type.Etype != TIDEAL {
+ // TODO(rsc): This is undone by the selective clearing of width below,
+ // to match architectures that were not as aggressive in setting width
+ // during naddr. Those widths must be cleared to avoid triggering
+ // failures in gins when it detects real but heretofore latent (and one
+ // hopes innocuous) type mismatches.
+ // The type mismatches should be fixed and the clearing below removed.
+ dowidth(n.Type)
+
+ a.Width = n.Type.Width
+ }
+
+ switch n.Op {
+ default:
+ Fatal("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a))
+
+ case OREGISTER:
+ a.Type = obj.TYPE_REG
+ a.Reg = n.Val.U.Reg
+ a.Sym = nil
+ if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+ a.Width = 0
+ }
+
+ case OINDREG:
+ a.Type = obj.TYPE_MEM
+ a.Reg = n.Val.U.Reg
+ a.Sym = Linksym(n.Sym)
+ a.Offset = n.Xoffset
+ if a.Offset != int64(int32(a.Offset)) {
+ Yyerror("offset %d too large for OINDREG", a.Offset)
+ }
+ if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+ a.Width = 0
+ }
+
+ // n->left is PHEAP ONAME for stack parameter.
+ // compute address of actual parameter on stack.
+ case OPARAM:
+ a.Etype = Simtype[n.Left.Type.Etype]
+
+ a.Width = n.Left.Type.Width
+ a.Offset = n.Xoffset
+ a.Sym = Linksym(n.Left.Sym)
+ a.Type = obj.TYPE_MEM
+ a.Name = obj.NAME_PARAM
+ a.Node = n.Left.Orig
+
+ case OCLOSUREVAR:
+ if !(Curfn.Needctxt != 0) {
+ Fatal("closurevar without needctxt")
+ }
+ a.Type = obj.TYPE_MEM
+ a.Reg = int16(Thearch.REGCTXT)
+ a.Sym = nil
+ a.Offset = n.Xoffset
+
+ case OCFUNC:
+ Naddr(n.Left, a, canemitcode)
+ a.Sym = Linksym(n.Left.Sym)
+
+ case ONAME:
+ a.Etype = 0
+ if n.Type != nil {
+ a.Etype = Simtype[n.Type.Etype]
+ }
+ a.Offset = n.Xoffset
+ s = n.Sym
+ a.Node = n.Orig
+
+ //if(a->node >= (Node*)&n)
+ // fatal("stack node");
+ if s == nil {
+ s = Lookup(".noname")
+ }
+ if n.Method != 0 {
+ if n.Type != nil {
+ if n.Type.Sym != nil {
+ if n.Type.Sym.Pkg != nil {
+ s = Pkglookup(s.Name, n.Type.Sym.Pkg)
+ }
+ }
+ }
+ }
+
+ a.Type = obj.TYPE_MEM
+ switch n.Class {
+ default:
+ Fatal("naddr: ONAME class %v %d\n", Sconv(n.Sym, 0), n.Class)
+ fallthrough
+
+ case PEXTERN:
+ a.Name = obj.NAME_EXTERN
+
+ case PAUTO:
+ a.Name = obj.NAME_AUTO
+
+ case PPARAM,
+ PPARAMOUT:
+ a.Name = obj.NAME_PARAM
+
+ case PFUNC:
+ a.Name = obj.NAME_EXTERN
+ a.Type = obj.TYPE_ADDR
+ a.Width = int64(Widthptr)
+ s = funcsym(s)
+ }
+
+ a.Sym = Linksym(s)
+
+ case OLITERAL:
+ if Thearch.Thechar == '8' {
+ a.Width = 0
+ }
+ switch n.Val.Ctype {
+ default:
+ Fatal("naddr: const %v", Tconv(n.Type, obj.FmtLong))
+
+ case CTFLT:
+ a.Type = obj.TYPE_FCONST
+ a.U.Dval = mpgetflt(n.Val.U.Fval)
+
+ case CTINT,
+ CTRUNE:
+ a.Sym = nil
+ a.Type = obj.TYPE_CONST
+ a.Offset = Mpgetfix(n.Val.U.Xval)
+
+ case CTSTR:
+ datagostring(n.Val.U.Sval, a)
+
+ case CTBOOL:
+ a.Sym = nil
+ a.Type = obj.TYPE_CONST
+ a.Offset = int64(n.Val.U.Bval)
+
+ case CTNIL:
+ a.Sym = nil
+ a.Type = obj.TYPE_CONST
+ a.Offset = 0
+ }
+
+ case OADDR:
+ Naddr(n.Left, a, canemitcode)
+ a.Etype = uint8(Tptr)
+ if Thearch.Thechar != '5' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
+ a.Width = int64(Widthptr)
+ }
+ if a.Type != obj.TYPE_MEM {
+ Fatal("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(int(n.Left.Op), 0))
+ }
+ a.Type = obj.TYPE_ADDR
+
+ // itable of interface value
+ case OITAB:
+ Naddr(n.Left, a, canemitcode)
+
+ if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+ break // itab(nil)
+ }
+ a.Etype = uint8(Tptr)
+ a.Width = int64(Widthptr)
+
+ // pointer in a string or slice
+ case OSPTR:
+ Naddr(n.Left, a, canemitcode)
+
+ if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+ break // ptr(nil)
+ }
+ a.Etype = Simtype[Tptr]
+ a.Offset += int64(Array_array)
+ a.Width = int64(Widthptr)
+
+ // len of string or slice
+ case OLEN:
+ Naddr(n.Left, a, canemitcode)
+
+ if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+ break // len(nil)
+ }
+ a.Etype = Simtype[TUINT]
+ if Thearch.Thechar == '9' {
+ a.Etype = Simtype[TINT]
+ }
+ a.Offset += int64(Array_nel)
+ if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+ a.Width = int64(Widthint)
+ }
+
+ // cap of string or slice
+ case OCAP:
+ Naddr(n.Left, a, canemitcode)
+
+ if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+ break // cap(nil)
+ }
+ a.Etype = Simtype[TUINT]
+ if Thearch.Thechar == '9' {
+ a.Etype = Simtype[TINT]
+ }
+ a.Offset += int64(Array_cap)
+ if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+ a.Width = int64(Widthint)
+ }
+ }
+}
+
+func newplist() *obj.Plist {
+ var pl *obj.Plist
+
+ pl = obj.Linknewplist(Ctxt)
+
+ Pc = Ctxt.NewProg()
+ Clearp(Pc)
+ pl.Firstpc = Pc
+
+ return pl
+}
+
+func nodarg(t *Type, fp int) *Node {
+ var n *Node
+ var l *NodeList
+ var first *Type
+ var savet Iter
+
+ // entire argument struct, not just one arg
+ if t.Etype == TSTRUCT && t.Funarg != 0 {
+ n = Nod(ONAME, nil, nil)
+ n.Sym = Lookup(".args")
+ n.Type = t
+ first = Structfirst(&savet, &t)
+ if first == nil {
+ Fatal("nodarg: bad struct")
+ }
+ if first.Width == BADWIDTH {
+ Fatal("nodarg: offset not computed for %v", Tconv(t, 0))
+ }
+ n.Xoffset = first.Width
+ n.Addable = 1
+ goto fp
+ }
+
+ if t.Etype != TFIELD {
+ Fatal("nodarg: not field %v", Tconv(t, 0))
+ }
+
+ if fp == 1 {
+ for l = Curfn.Dcl; l != nil; l = l.Next {
+ n = l.N
+ if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
+ return n
+ }
+ }
+ }
+
+ n = Nod(ONAME, nil, nil)
+ n.Type = t.Type
+ n.Sym = t.Sym
+
+ if t.Width == BADWIDTH {
+ Fatal("nodarg: offset not computed for %v", Tconv(t, 0))
+ }
+ n.Xoffset = t.Width
+ n.Addable = 1
+ n.Orig = t.Nname
+
+ // Rewrite argument named _ to __,
+ // or else the assignment to _ will be
+ // discarded during code generation.
+fp:
+ if isblank(n) {
+ n.Sym = Lookup("__")
+ }
+
+ switch fp {
+ case 0: // output arg
+ n.Op = OINDREG
+
+ n.Val.U.Reg = int16(Thearch.REGSP)
+ if Thearch.Thechar == '5' {
+ n.Xoffset += 4
+ }
+ if Thearch.Thechar == '9' {
+ n.Xoffset += 8
+ }
+
+ case 1: // input arg
+ n.Class = PPARAM
+
+ case 2: // offset output arg
+ Fatal("shouldn't be used")
+
+ n.Op = OINDREG
+ n.Val.U.Reg = int16(Thearch.REGSP)
+ n.Xoffset += Types[Tptr].Width
+ }
+
+ n.Typecheck = 1
+ return n
+}
+
+func Patch(p *obj.Prog, to *obj.Prog) {
+ if p.To.Type != obj.TYPE_BRANCH {
+ Fatal("patch: not a branch")
+ }
+ p.To.U.Branch = to
+ p.To.Offset = to.Pc
+}
+
+func unpatch(p *obj.Prog) *obj.Prog {
+ var q *obj.Prog
+
+ if p.To.Type != obj.TYPE_BRANCH {
+ Fatal("unpatch: not a branch")
+ }
+ q = p.To.U.Branch
+ p.To.U.Branch = nil
+ p.To.Offset = 0
+ return q
+}