Home | History | Annotate | Download | only in gc
      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 (a] 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 (a] 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 }
    313