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 }