github.com/freddyisaac/sicortex-golang@v0.0.0-20231019035217-e03519e66f60/src/cmd/compile/internal/gc/pgen.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gc 6 7 import ( 8 "cmd/compile/internal/ssa" 9 "cmd/internal/obj" 10 "cmd/internal/sys" 11 "fmt" 12 "sort" 13 "strings" 14 ) 15 16 // "Portable" code generation. 17 18 var makefuncdatasym_nsym int 19 20 func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym { 21 sym := lookupN(nameprefix, makefuncdatasym_nsym) 22 makefuncdatasym_nsym++ 23 pnod := newname(sym) 24 pnod.Class = PEXTERN 25 p := Gins(obj.AFUNCDATA, nil, pnod) 26 Addrconst(&p.From, funcdatakind) 27 return sym 28 } 29 30 // gvardef inserts a VARDEF for n into the instruction stream. 31 // VARDEF is an annotation for the liveness analysis, marking a place 32 // where a complete initialization (definition) of a variable begins. 33 // Since the liveness analysis can see initialization of single-word 34 // variables quite easy, gvardef is usually only called for multi-word 35 // or 'fat' variables, those satisfying isfat(n->type). 36 // However, gvardef is also called when a non-fat variable is initialized 37 // via a block move; the only time this happens is when you have 38 // return f() 39 // for a function with multiple return values exactly matching the return 40 // types of the current function. 41 // 42 // A 'VARDEF x' annotation in the instruction stream tells the liveness 43 // analysis to behave as though the variable x is being initialized at that 44 // point in the instruction stream. The VARDEF must appear before the 45 // actual (multi-instruction) initialization, and it must also appear after 46 // any uses of the previous value, if any. For example, if compiling: 47 // 48 // x = x[1:] 49 // 50 // it is important to generate code like: 51 // 52 // base, len, cap = pieces of x[1:] 53 // VARDEF x 54 // x = {base, len, cap} 55 // 56 // If instead the generated code looked like: 57 // 58 // VARDEF x 59 // base, len, cap = pieces of x[1:] 60 // x = {base, len, cap} 61 // 62 // then the liveness analysis would decide the previous value of x was 63 // unnecessary even though it is about to be used by the x[1:] computation. 64 // Similarly, if the generated code looked like: 65 // 66 // base, len, cap = pieces of x[1:] 67 // x = {base, len, cap} 68 // VARDEF x 69 // 70 // then the liveness analysis will not preserve the new value of x, because 71 // the VARDEF appears to have "overwritten" it. 72 // 73 // VARDEF is a bit of a kludge to work around the fact that the instruction 74 // stream is working on single-word values but the liveness analysis 75 // wants to work on individual variables, which might be multi-word 76 // aggregates. It might make sense at some point to look into letting 77 // the liveness analysis work on single-word values as well, although 78 // there are complications around interface values, slices, and strings, 79 // all of which cannot be treated as individual words. 80 // 81 // VARKILL is the opposite of VARDEF: it marks a value as no longer needed, 82 // even if its address has been taken. That is, a VARKILL annotation asserts 83 // that its argument is certainly dead, for use when the liveness analysis 84 // would not otherwise be able to deduce that fact. 85 86 func gvardefx(n *Node, as obj.As) { 87 if n == nil { 88 Fatalf("gvardef nil") 89 } 90 if n.Op != ONAME { 91 yyerror("gvardef %#v; %v", n.Op, n) 92 return 93 } 94 95 switch n.Class { 96 case PAUTO, PPARAM, PPARAMOUT: 97 if !n.Used { 98 Prog(obj.ANOP) 99 return 100 } 101 102 if as == obj.AVARLIVE { 103 Gins(as, n, nil) 104 } else { 105 Gins(as, nil, n) 106 } 107 } 108 } 109 110 func Gvardef(n *Node) { 111 gvardefx(n, obj.AVARDEF) 112 } 113 114 func Gvarkill(n *Node) { 115 gvardefx(n, obj.AVARKILL) 116 } 117 118 func Gvarlive(n *Node) { 119 gvardefx(n, obj.AVARLIVE) 120 } 121 122 func removevardef(firstp *obj.Prog) { 123 // At VARKILLs, zero variable if it is ambiguously live. 124 // After the VARKILL anything this variable references 125 // might be collected. If it were to become live again later, 126 // the GC will see references to already-collected objects. 127 // See issue 20029. 128 for p := firstp; p != nil; p = p.Link { 129 if p.As != obj.AVARKILL { 130 continue 131 } 132 n := p.To.Node.(*Node) 133 if !n.Name.Needzero { 134 continue 135 } 136 if n.Class != PAUTO { 137 Fatalf("zero of variable which isn't PAUTO %v", n) 138 } 139 if n.Type.Size()%int64(Widthptr) != 0 { 140 Fatalf("zero of variable not a multiple of ptr size %v", n) 141 } 142 Thearch.ZeroAuto(n, p) 143 } 144 145 for p := firstp; p != nil; p = p.Link { 146 147 for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) { 148 p.Link = p.Link.Link 149 } 150 if p.To.Type == obj.TYPE_BRANCH { 151 for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL || p.To.Val.(*obj.Prog).As == obj.AVARLIVE) { 152 p.To.Val = p.To.Val.(*obj.Prog).Link 153 } 154 } 155 } 156 } 157 158 func emitptrargsmap() { 159 if Curfn.Func.Nname.Sym.Name == "_" { 160 return 161 } 162 sym := lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name)) 163 164 nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr)) 165 bv := bvalloc(int32(nptr) * 2) 166 nbitmap := 1 167 if Curfn.Type.Results().NumFields() > 0 { 168 nbitmap = 2 169 } 170 off := duint32(sym, 0, uint32(nbitmap)) 171 off = duint32(sym, off, uint32(bv.n)) 172 var xoffset int64 173 if Curfn.IsMethod() { 174 xoffset = 0 175 onebitwalktype1(Curfn.Type.Recvs(), &xoffset, bv) 176 } 177 178 if Curfn.Type.Params().NumFields() > 0 { 179 xoffset = 0 180 onebitwalktype1(Curfn.Type.Params(), &xoffset, bv) 181 } 182 183 off = dbvec(sym, off, bv) 184 if Curfn.Type.Results().NumFields() > 0 { 185 xoffset = 0 186 onebitwalktype1(Curfn.Type.Results(), &xoffset, bv) 187 off = dbvec(sym, off, bv) 188 } 189 190 ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL) 191 } 192 193 // cmpstackvarlt reports whether the stack variable a sorts before b. 194 // 195 // Sort the list of stack variables. Autos after anything else, 196 // within autos, unused after used, within used, things with 197 // pointers first, zeroed things first, and then decreasing size. 198 // Because autos are laid out in decreasing addresses 199 // on the stack, pointers first, zeroed things first and decreasing size 200 // really means, in memory, things with pointers needing zeroing at 201 // the top of the stack and increasing in size. 202 // Non-autos sort on offset. 203 func cmpstackvarlt(a, b *Node) bool { 204 if (a.Class == PAUTO) != (b.Class == PAUTO) { 205 return b.Class == PAUTO 206 } 207 208 if a.Class != PAUTO { 209 return a.Xoffset < b.Xoffset 210 } 211 212 if a.Used != b.Used { 213 return a.Used 214 } 215 216 ap := haspointers(a.Type) 217 bp := haspointers(b.Type) 218 if ap != bp { 219 return ap 220 } 221 222 ap = a.Name.Needzero 223 bp = b.Name.Needzero 224 if ap != bp { 225 return ap 226 } 227 228 if a.Type.Width != b.Type.Width { 229 return a.Type.Width > b.Type.Width 230 } 231 232 return a.Sym.Name < b.Sym.Name 233 } 234 235 // byStackvar implements sort.Interface for []*Node using cmpstackvarlt. 236 type byStackVar []*Node 237 238 func (s byStackVar) Len() int { return len(s) } 239 func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) } 240 func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 241 242 var scratchFpMem *Node 243 244 func (s *ssaExport) AllocFrame(f *ssa.Func) { 245 Stksize = 0 246 stkptrsize = 0 247 248 // Mark the PAUTO's unused. 249 for _, ln := range Curfn.Func.Dcl { 250 if ln.Class == PAUTO { 251 ln.Used = false 252 } 253 } 254 255 for _, l := range f.RegAlloc { 256 if ls, ok := l.(ssa.LocalSlot); ok { 257 ls.N.(*Node).Used = true 258 } 259 260 } 261 262 scratchUsed := false 263 for _, b := range f.Blocks { 264 for _, v := range b.Values { 265 switch a := v.Aux.(type) { 266 case *ssa.ArgSymbol: 267 a.Node.(*Node).Used = true 268 case *ssa.AutoSymbol: 269 a.Node.(*Node).Used = true 270 } 271 272 if !scratchUsed { 273 scratchUsed = v.Op.UsesScratch() 274 } 275 } 276 } 277 278 if f.Config.NeedsFpScratch { 279 scratchFpMem = temp(Types[TUINT64]) 280 scratchFpMem.Used = scratchUsed 281 } 282 283 sort.Sort(byStackVar(Curfn.Func.Dcl)) 284 285 // Reassign stack offsets of the locals that are used. 286 for i, n := range Curfn.Func.Dcl { 287 if n.Op != ONAME || n.Class != PAUTO { 288 continue 289 } 290 if !n.Used { 291 Curfn.Func.Dcl = Curfn.Func.Dcl[:i] 292 break 293 } 294 295 dowidth(n.Type) 296 w := n.Type.Width 297 if w >= Thearch.MAXWIDTH || w < 0 { 298 Fatalf("bad width") 299 } 300 Stksize += w 301 Stksize = Rnd(Stksize, int64(n.Type.Align)) 302 if haspointers(n.Type) { 303 stkptrsize = Stksize 304 } 305 if Thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { 306 Stksize = Rnd(Stksize, int64(Widthptr)) 307 } 308 if Stksize >= 1<<31 { 309 setlineno(Curfn) 310 yyerror("stack frame too large (>2GB)") 311 } 312 313 n.Xoffset = -Stksize 314 } 315 316 Stksize = Rnd(Stksize, int64(Widthreg)) 317 stkptrsize = Rnd(stkptrsize, int64(Widthreg)) 318 } 319 320 func compile(fn *Node) { 321 if Newproc == nil { 322 Newproc = Sysfunc("newproc") 323 Deferproc = Sysfunc("deferproc") 324 Deferreturn = Sysfunc("deferreturn") 325 panicindex = Sysfunc("panicindex") 326 panicslice = Sysfunc("panicslice") 327 panicdivide = Sysfunc("panicdivide") 328 growslice = Sysfunc("growslice") 329 panicdottype = Sysfunc("panicdottype") 330 panicnildottype = Sysfunc("panicnildottype") 331 assertE2I = Sysfunc("assertE2I") 332 assertE2I2 = Sysfunc("assertE2I2") 333 assertI2I = Sysfunc("assertI2I") 334 assertI2I2 = Sysfunc("assertI2I2") 335 } 336 337 defer func(lno int32) { 338 lineno = lno 339 }(setlineno(fn)) 340 341 Curfn = fn 342 dowidth(Curfn.Type) 343 344 if fn.Nbody.Len() == 0 { 345 if pure_go || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { 346 yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) 347 return 348 } 349 350 emitptrargsmap() 351 return 352 } 353 354 saveerrors() 355 356 if Curfn.Type.FuncType().Outnamed { 357 // add clearing of the output parameters 358 for _, t := range Curfn.Type.Results().Fields().Slice() { 359 if t.Nname != nil { 360 n := nod(OAS, t.Nname, nil) 361 n = typecheck(n, Etop) 362 Curfn.Nbody.Prepend(n) 363 } 364 } 365 } 366 367 order(Curfn) 368 if nerrors != 0 { 369 return 370 } 371 372 hasdefer = false 373 walk(Curfn) 374 if nerrors != 0 { 375 return 376 } 377 if instrumenting { 378 instrument(Curfn) 379 } 380 if nerrors != 0 { 381 return 382 } 383 384 // Build an SSA backend function. 385 ssafn := buildssa(Curfn) 386 if nerrors != 0 { 387 return 388 } 389 390 newplist() 391 392 setlineno(Curfn) 393 394 nam := Curfn.Func.Nname 395 if isblank(nam) { 396 nam = nil 397 } 398 ptxt := Gins(obj.ATEXT, nam, nil) 399 ptxt.From3 = new(obj.Addr) 400 if fn.Func.Dupok { 401 ptxt.From3.Offset |= obj.DUPOK 402 } 403 if fn.Func.Wrapper { 404 ptxt.From3.Offset |= obj.WRAPPER 405 } 406 if fn.Func.NoFramePointer { 407 ptxt.From3.Offset |= obj.NOFRAME 408 } 409 if fn.Func.Needctxt { 410 ptxt.From3.Offset |= obj.NEEDCTXT 411 } 412 if fn.Func.Pragma&Nosplit != 0 { 413 ptxt.From3.Offset |= obj.NOSPLIT 414 } 415 if fn.Func.ReflectMethod { 416 ptxt.From3.Offset |= obj.REFLECTMETHOD 417 } 418 if fn.Func.Pragma&Systemstack != 0 { 419 ptxt.From.Sym.Set(obj.AttrCFunc, true) 420 } 421 422 // Clumsy but important. 423 // See test/recover.go for test cases and src/reflect/value.go 424 // for the actual functions being considered. 425 if myimportpath == "reflect" { 426 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" { 427 ptxt.From3.Offset |= obj.WRAPPER 428 } 429 } 430 431 gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps) 432 gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps) 433 434 if obj.Fieldtrack_enabled != 0 && len(Curfn.Func.FieldTrack) > 0 { 435 trackSyms := make([]*Sym, 0, len(Curfn.Func.FieldTrack)) 436 for sym := range Curfn.Func.FieldTrack { 437 trackSyms = append(trackSyms, sym) 438 } 439 sort.Sort(symByName(trackSyms)) 440 for _, sym := range trackSyms { 441 gtrack(sym) 442 } 443 } 444 445 for _, n := range fn.Func.Dcl { 446 if n.Op != ONAME { // might be OTYPE or OLITERAL 447 continue 448 } 449 switch n.Class { 450 case PAUTO: 451 if !n.Used { 452 continue 453 } 454 fallthrough 455 case PPARAM, PPARAMOUT: 456 // The symbol is excluded later from debugging info if its name begins ".autotmp_", but the type is still necessary. 457 // See bugs #17644 and #17830 and cmd/internal/dwarf/dwarf.go 458 p := Gins(obj.ATYPE, n, nil) 459 p.From.Sym = obj.Linklookup(Ctxt, n.Sym.Name, 0) 460 p.To.Type = obj.TYPE_MEM 461 p.To.Name = obj.NAME_EXTERN 462 p.To.Sym = Linksym(ngotype(n)) 463 } 464 } 465 466 genssa(ssafn, ptxt, gcargs, gclocals) 467 ssafn.Free() 468 } 469 470 type symByName []*Sym 471 472 func (a symByName) Len() int { return len(a) } 473 func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name } 474 func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }