github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/compile/internal/gc/gsubr.go (about)

     1  // Derived from Inferno utils/6c/txt.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/txt.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package gc
    32  
    33  import "cmd/internal/obj"
    34  
    35  func Prog(as obj.As) *obj.Prog {
    36  	var p *obj.Prog
    37  
    38  	p = pc
    39  	pc = Ctxt.NewProg()
    40  	Clearp(pc)
    41  	p.Link = pc
    42  
    43  	if lineno == 0 && Debug['K'] != 0 {
    44  		Warn("prog: line 0")
    45  	}
    46  
    47  	p.As = as
    48  	p.Lineno = lineno
    49  	return p
    50  }
    51  
    52  func Clearp(p *obj.Prog) {
    53  	obj.Nopout(p)
    54  	p.As = obj.AEND
    55  	p.Pc = int64(pcloc)
    56  	pcloc++
    57  }
    58  
    59  func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset int64, ttype obj.AddrType, treg int16, toffset int64) *obj.Prog {
    60  	q := Ctxt.NewProg()
    61  	Clearp(q)
    62  	q.As = as
    63  	q.Lineno = p.Lineno
    64  	q.From.Type = ftype
    65  	q.From.Reg = freg
    66  	q.From.Offset = foffset
    67  	q.To.Type = ttype
    68  	q.To.Reg = treg
    69  	q.To.Offset = toffset
    70  	q.Link = p.Link
    71  	p.Link = q
    72  	return q
    73  }
    74  
    75  func ggloblnod(nam *Node) {
    76  	s := Linksym(nam.Sym)
    77  	s.Gotype = Linksym(ngotype(nam))
    78  	flags := 0
    79  	if nam.Name.Readonly {
    80  		flags = obj.RODATA
    81  	}
    82  	if nam.Type != nil && !haspointers(nam.Type) {
    83  		flags |= obj.NOPTR
    84  	}
    85  	Ctxt.Globl(s, nam.Type.Width, flags)
    86  }
    87  
    88  func ggloblsym(s *Sym, width int32, flags int16) {
    89  	ggloblLSym(Linksym(s), width, flags)
    90  }
    91  
    92  func ggloblLSym(s *obj.LSym, width int32, flags int16) {
    93  	if flags&obj.LOCAL != 0 {
    94  		s.Set(obj.AttrLocal, true)
    95  		flags &^= obj.LOCAL
    96  	}
    97  	Ctxt.Globl(s, int64(width), int(flags))
    98  }
    99  
   100  func gtrack(s *Sym) {
   101  	p := Gins(obj.AUSEFIELD, nil, nil)
   102  	p.From.Type = obj.TYPE_MEM
   103  	p.From.Name = obj.NAME_EXTERN
   104  	p.From.Sym = Linksym(s)
   105  }
   106  
   107  func isfat(t *Type) bool {
   108  	if t != nil {
   109  		switch t.Etype {
   110  		case TSTRUCT, TARRAY, TSLICE, TSTRING,
   111  			TINTER: // maybe remove later
   112  			return true
   113  		}
   114  	}
   115  
   116  	return false
   117  }
   118  
   119  // Naddr rewrites a to refer to n.
   120  // It assumes that a is zeroed on entry.
   121  func Naddr(a *obj.Addr, n *Node) {
   122  	if n == nil {
   123  		return
   124  	}
   125  
   126  	if n.Op != ONAME {
   127  		Debug['h'] = 1
   128  		Dump("naddr", n)
   129  		Fatalf("naddr: bad %v %v", n.Op, Ctxt.Dconv(a))
   130  	}
   131  
   132  	a.Offset = n.Xoffset
   133  	s := n.Sym
   134  	a.Node = n.Orig
   135  
   136  	if s == nil {
   137  		Fatalf("naddr: nil sym %v", n)
   138  	}
   139  
   140  	a.Type = obj.TYPE_MEM
   141  	switch n.Class {
   142  	default:
   143  		Fatalf("naddr: ONAME class %v %d\n", n.Sym, n.Class)
   144  
   145  	case PEXTERN, PFUNC:
   146  		a.Name = obj.NAME_EXTERN
   147  
   148  	case PAUTO:
   149  		a.Name = obj.NAME_AUTO
   150  
   151  	case PPARAM, PPARAMOUT:
   152  		a.Name = obj.NAME_PARAM
   153  	}
   154  
   155  	a.Sym = Linksym(s)
   156  }
   157  
   158  func Addrconst(a *obj.Addr, v int64) {
   159  	a.Sym = nil
   160  	a.Type = obj.TYPE_CONST
   161  	a.Offset = v
   162  }
   163  
   164  func newplist() *obj.Plist {
   165  	pl := obj.Linknewplist(Ctxt)
   166  
   167  	pc = Ctxt.NewProg()
   168  	Clearp(pc)
   169  	pl.Firstpc = pc
   170  
   171  	return pl
   172  }
   173  
   174  // nodarg returns a Node for the function argument denoted by t,
   175  // which is either the entire function argument or result struct (t is a  struct *Type)
   176  // or a specific argument (t is a *Field within a struct *Type).
   177  //
   178  // If fp is 0, the node is for use by a caller invoking the given
   179  // function, preparing the arguments before the call
   180  // or retrieving the results after the call.
   181  // In this case, the node will correspond to an outgoing argument
   182  // slot like 8(SP).
   183  //
   184  // If fp is 1, the node is for use by the function itself
   185  // (the callee), to retrieve its arguments or write its results.
   186  // In this case the node will be an ONAME with an appropriate
   187  // type and offset.
   188  func nodarg(t interface{}, fp int) *Node {
   189  	var n *Node
   190  
   191  	var funarg Funarg
   192  	switch t := t.(type) {
   193  	default:
   194  		Fatalf("bad nodarg %T(%v)", t, t)
   195  
   196  	case *Type:
   197  		// Entire argument struct, not just one arg
   198  		if !t.IsFuncArgStruct() {
   199  			Fatalf("nodarg: bad type %v", t)
   200  		}
   201  		funarg = t.StructType().Funarg
   202  
   203  		// Build fake variable name for whole arg struct.
   204  		n = nod(ONAME, nil, nil)
   205  		n.Sym = lookup(".args")
   206  		n.Type = t
   207  		first := t.Field(0)
   208  		if first == nil {
   209  			Fatalf("nodarg: bad struct")
   210  		}
   211  		if first.Offset == BADWIDTH {
   212  			Fatalf("nodarg: offset not computed for %v", t)
   213  		}
   214  		n.Xoffset = first.Offset
   215  		n.Addable = true
   216  
   217  	case *Field:
   218  		funarg = t.Funarg
   219  		if fp == 1 {
   220  			// NOTE(rsc): This should be using t.Nname directly,
   221  			// except in the case where t.Nname.Sym is the blank symbol and
   222  			// so the assignment would be discarded during code generation.
   223  			// In that case we need to make a new node, and there is no harm
   224  			// in optimization passes to doing so. But otherwise we should
   225  			// definitely be using the actual declaration and not a newly built node.
   226  			// The extra Fatalf checks here are verifying that this is the case,
   227  			// without changing the actual logic (at time of writing, it's getting
   228  			// toward time for the Go 1.7 beta).
   229  			// At some quieter time (assuming we've never seen these Fatalfs happen)
   230  			// we could change this code to use "expect" directly.
   231  			expect := t.Nname
   232  			if expect.isParamHeapCopy() {
   233  				expect = expect.Name.Param.Stackcopy
   234  			}
   235  
   236  			for _, n := range Curfn.Func.Dcl {
   237  				if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
   238  					if n != expect {
   239  						Fatalf("nodarg: unexpected node: %v (%p %v) vs %v (%p %v)", n, n, n.Op, t.Nname, t.Nname, t.Nname.Op)
   240  					}
   241  					return n
   242  				}
   243  			}
   244  
   245  			if !isblanksym(expect.Sym) {
   246  				Fatalf("nodarg: did not find node in dcl list: %v", expect)
   247  			}
   248  		}
   249  
   250  		// Build fake name for individual variable.
   251  		// This is safe because if there was a real declared name
   252  		// we'd have used it above.
   253  		n = nod(ONAME, nil, nil)
   254  		n.Type = t.Type
   255  		n.Sym = t.Sym
   256  		if t.Offset == BADWIDTH {
   257  			Fatalf("nodarg: offset not computed for %v", t)
   258  		}
   259  		n.Xoffset = t.Offset
   260  		n.Addable = true
   261  		n.Orig = t.Nname
   262  	}
   263  
   264  	// Rewrite argument named _ to __,
   265  	// or else the assignment to _ will be
   266  	// discarded during code generation.
   267  	if isblank(n) {
   268  		n.Sym = lookup("__")
   269  	}
   270  
   271  	switch fp {
   272  	default:
   273  		Fatalf("bad fp")
   274  
   275  	case 0: // preparing arguments for call
   276  		n.Op = OINDREGSP
   277  		n.Xoffset += Ctxt.FixedFrameSize()
   278  
   279  	case 1: // reading arguments inside call
   280  		n.Class = PPARAM
   281  		if funarg == FunargResults {
   282  			n.Class = PPARAMOUT
   283  		}
   284  	}
   285  
   286  	n.Typecheck = 1
   287  	n.Addrtaken = true // keep optimizers at bay
   288  	return n
   289  }
   290  
   291  func Patch(p *obj.Prog, to *obj.Prog) {
   292  	if p.To.Type != obj.TYPE_BRANCH {
   293  		Fatalf("patch: not a branch")
   294  	}
   295  	p.To.Val = to
   296  	p.To.Offset = to.Pc
   297  }
   298  
   299  // Gins inserts instruction as. f is from, t is to.
   300  func Gins(as obj.As, f, t *Node) *obj.Prog {
   301  	switch as {
   302  	case obj.AVARKILL, obj.AVARLIVE, obj.AVARDEF, obj.ATYPE,
   303  		obj.ATEXT, obj.AFUNCDATA, obj.AUSEFIELD:
   304  	default:
   305  		Fatalf("unhandled gins op %v", as)
   306  	}
   307  
   308  	p := Prog(as)
   309  	Naddr(&p.From, f)
   310  	Naddr(&p.To, t)
   311  	return p
   312  }