github.com/freddyisaac/sicortex-golang@v0.0.0-20231019035217-e03519e66f60/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 AddAsmAfter(as obj.As, p *obj.Prog) *obj.Prog {
    76  	q := Ctxt.NewProg()
    77  	Clearp(q)
    78  	q.As = as
    79  	q.Link = p.Link
    80  	p.Link = q
    81  	return q
    82  }
    83  
    84  func ggloblnod(nam *Node) {
    85  	s := Linksym(nam.Sym)
    86  	s.Gotype = Linksym(ngotype(nam))
    87  	flags := 0
    88  	if nam.Name.Readonly {
    89  		flags = obj.RODATA
    90  	}
    91  	if nam.Type != nil && !haspointers(nam.Type) {
    92  		flags |= obj.NOPTR
    93  	}
    94  	Ctxt.Globl(s, nam.Type.Width, flags)
    95  }
    96  
    97  func ggloblsym(s *Sym, width int32, flags int16) {
    98  	ggloblLSym(Linksym(s), width, flags)
    99  }
   100  
   101  func ggloblLSym(s *obj.LSym, width int32, flags int16) {
   102  	if flags&obj.LOCAL != 0 {
   103  		s.Set(obj.AttrLocal, true)
   104  		flags &^= obj.LOCAL
   105  	}
   106  	Ctxt.Globl(s, int64(width), int(flags))
   107  }
   108  
   109  func gtrack(s *Sym) {
   110  	p := Gins(obj.AUSEFIELD, nil, nil)
   111  	p.From.Type = obj.TYPE_MEM
   112  	p.From.Name = obj.NAME_EXTERN
   113  	p.From.Sym = Linksym(s)
   114  }
   115  
   116  func isfat(t *Type) bool {
   117  	if t != nil {
   118  		switch t.Etype {
   119  		case TSTRUCT, TARRAY, TSLICE, TSTRING,
   120  			TINTER: // maybe remove later
   121  			return true
   122  		}
   123  	}
   124  
   125  	return false
   126  }
   127  
   128  // Naddr rewrites a to refer to n.
   129  // It assumes that a is zeroed on entry.
   130  func Naddr(a *obj.Addr, n *Node) {
   131  	if n == nil {
   132  		return
   133  	}
   134  
   135  	if n.Op != ONAME {
   136  		Debug['h'] = 1
   137  		Dump("naddr", n)
   138  		Fatalf("naddr: bad %v %v", n.Op, Ctxt.Dconv(a))
   139  	}
   140  
   141  	a.Offset = n.Xoffset
   142  	s := n.Sym
   143  	a.Node = n.Orig
   144  
   145  	if s == nil {
   146  		Fatalf("naddr: nil sym %v", n)
   147  	}
   148  
   149  	a.Type = obj.TYPE_MEM
   150  	switch n.Class {
   151  	default:
   152  		Fatalf("naddr: ONAME class %v %d\n", n.Sym, n.Class)
   153  
   154  	case PEXTERN, PFUNC:
   155  		a.Name = obj.NAME_EXTERN
   156  
   157  	case PAUTO:
   158  		a.Name = obj.NAME_AUTO
   159  
   160  	case PPARAM, PPARAMOUT:
   161  		a.Name = obj.NAME_PARAM
   162  	}
   163  
   164  	a.Sym = Linksym(s)
   165  }
   166  
   167  func Addrconst(a *obj.Addr, v int64) {
   168  	a.Sym = nil
   169  	a.Type = obj.TYPE_CONST
   170  	a.Offset = v
   171  }
   172  
   173  func newplist() *obj.Plist {
   174  	pl := obj.Linknewplist(Ctxt)
   175  
   176  	pc = Ctxt.NewProg()
   177  	Clearp(pc)
   178  	pl.Firstpc = pc
   179  
   180  	return pl
   181  }
   182  
   183  // nodarg returns a Node for the function argument denoted by t,
   184  // which is either the entire function argument or result struct (t is a  struct *Type)
   185  // or a specific argument (t is a *Field within a struct *Type).
   186  //
   187  // If fp is 0, the node is for use by a caller invoking the given
   188  // function, preparing the arguments before the call
   189  // or retrieving the results after the call.
   190  // In this case, the node will correspond to an outgoing argument
   191  // slot like 8(SP).
   192  //
   193  // If fp is 1, the node is for use by the function itself
   194  // (the callee), to retrieve its arguments or write its results.
   195  // In this case the node will be an ONAME with an appropriate
   196  // type and offset.
   197  func nodarg(t interface{}, fp int) *Node {
   198  	var n *Node
   199  
   200  	var funarg Funarg
   201  	switch t := t.(type) {
   202  	default:
   203  		Fatalf("bad nodarg %T(%v)", t, t)
   204  
   205  	case *Type:
   206  		// Entire argument struct, not just one arg
   207  		if !t.IsFuncArgStruct() {
   208  			Fatalf("nodarg: bad type %v", t)
   209  		}
   210  		funarg = t.StructType().Funarg
   211  
   212  		// Build fake variable name for whole arg struct.
   213  		n = nod(ONAME, nil, nil)
   214  		n.Sym = lookup(".args")
   215  		n.Type = t
   216  		first := t.Field(0)
   217  		if first == nil {
   218  			Fatalf("nodarg: bad struct")
   219  		}
   220  		if first.Offset == BADWIDTH {
   221  			Fatalf("nodarg: offset not computed for %v", t)
   222  		}
   223  		n.Xoffset = first.Offset
   224  		n.Addable = true
   225  
   226  	case *Field:
   227  		funarg = t.Funarg
   228  		if fp == 1 {
   229  			// NOTE(rsc): This should be using t.Nname directly,
   230  			// except in the case where t.Nname.Sym is the blank symbol and
   231  			// so the assignment would be discarded during code generation.
   232  			// In that case we need to make a new node, and there is no harm
   233  			// in optimization passes to doing so. But otherwise we should
   234  			// definitely be using the actual declaration and not a newly built node.
   235  			// The extra Fatalf checks here are verifying that this is the case,
   236  			// without changing the actual logic (at time of writing, it's getting
   237  			// toward time for the Go 1.7 beta).
   238  			// At some quieter time (assuming we've never seen these Fatalfs happen)
   239  			// we could change this code to use "expect" directly.
   240  			expect := t.Nname
   241  			if expect.isParamHeapCopy() {
   242  				expect = expect.Name.Param.Stackcopy
   243  			}
   244  
   245  			for _, n := range Curfn.Func.Dcl {
   246  				if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
   247  					if n != expect {
   248  						Fatalf("nodarg: unexpected node: %v (%p %v) vs %v (%p %v)", n, n, n.Op, t.Nname, t.Nname, t.Nname.Op)
   249  					}
   250  					return n
   251  				}
   252  			}
   253  
   254  			if !isblanksym(expect.Sym) {
   255  				Fatalf("nodarg: did not find node in dcl list: %v", expect)
   256  			}
   257  		}
   258  
   259  		// Build fake name for individual variable.
   260  		// This is safe because if there was a real declared name
   261  		// we'd have used it above.
   262  		n = nod(ONAME, nil, nil)
   263  		n.Type = t.Type
   264  		n.Sym = t.Sym
   265  		if t.Offset == BADWIDTH {
   266  			Fatalf("nodarg: offset not computed for %v", t)
   267  		}
   268  		n.Xoffset = t.Offset
   269  		n.Addable = true
   270  		n.Orig = t.Nname
   271  	}
   272  
   273  	// Rewrite argument named _ to __,
   274  	// or else the assignment to _ will be
   275  	// discarded during code generation.
   276  	if isblank(n) {
   277  		n.Sym = lookup("__")
   278  	}
   279  
   280  	switch fp {
   281  	default:
   282  		Fatalf("bad fp")
   283  
   284  	case 0: // preparing arguments for call
   285  		n.Op = OINDREGSP
   286  		n.Xoffset += Ctxt.FixedFrameSize()
   287  
   288  	case 1: // reading arguments inside call
   289  		n.Class = PPARAM
   290  		if funarg == FunargResults {
   291  			n.Class = PPARAMOUT
   292  		}
   293  	}
   294  
   295  	n.Typecheck = 1
   296  	n.Addrtaken = true // keep optimizers at bay
   297  	return n
   298  }
   299  
   300  func Patch(p *obj.Prog, to *obj.Prog) {
   301  	if p.To.Type != obj.TYPE_BRANCH {
   302  		Fatalf("patch: not a branch")
   303  	}
   304  	p.To.Val = to
   305  	p.To.Offset = to.Pc
   306  }
   307  
   308  // Gins inserts instruction as. f is from, t is to.
   309  func Gins(as obj.As, f, t *Node) *obj.Prog {
   310  	switch as {
   311  	case obj.AVARKILL, obj.AVARLIVE, obj.AVARDEF, obj.ATYPE,
   312  		obj.ATEXT, obj.AFUNCDATA, obj.AUSEFIELD:
   313  	default:
   314  		Fatalf("unhandled gins op %v", as)
   315  	}
   316  
   317  	p := Prog(as)
   318  	Naddr(&p.From, f)
   319  	Naddr(&p.To, t)
   320  	return p
   321  }