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 }