github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/pgen.go (about) 1 // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/pgen.go 2 3 // Copyright 2011 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package gc 8 9 import ( 10 "rsc.io/tmp/bootstrap/internal/obj" 11 "crypto/md5" 12 "fmt" 13 "strings" 14 ) 15 16 // "Portable" code generation. 17 18 var makefuncdatasym_nsym int32 19 20 func makefuncdatasym(namefmt string, funcdatakind int64) *Sym { 21 var nod Node 22 23 sym := Lookupf(namefmt, makefuncdatasym_nsym) 24 makefuncdatasym_nsym++ 25 pnod := newname(sym) 26 pnod.Class = PEXTERN 27 Nodconst(&nod, Types[TINT32], funcdatakind) 28 Thearch.Gins(obj.AFUNCDATA, &nod, pnod) 29 return sym 30 } 31 32 // gvardef inserts a VARDEF for n into the instruction stream. 33 // VARDEF is an annotation for the liveness analysis, marking a place 34 // where a complete initialization (definition) of a variable begins. 35 // Since the liveness analysis can see initialization of single-word 36 // variables quite easy, gvardef is usually only called for multi-word 37 // or 'fat' variables, those satisfying isfat(n->type). 38 // However, gvardef is also called when a non-fat variable is initialized 39 // via a block move; the only time this happens is when you have 40 // return f() 41 // for a function with multiple return values exactly matching the return 42 // types of the current function. 43 // 44 // A 'VARDEF x' annotation in the instruction stream tells the liveness 45 // analysis to behave as though the variable x is being initialized at that 46 // point in the instruction stream. The VARDEF must appear before the 47 // actual (multi-instruction) initialization, and it must also appear after 48 // any uses of the previous value, if any. For example, if compiling: 49 // 50 // x = x[1:] 51 // 52 // it is important to generate code like: 53 // 54 // base, len, cap = pieces of x[1:] 55 // VARDEF x 56 // x = {base, len, cap} 57 // 58 // If instead the generated code looked like: 59 // 60 // VARDEF x 61 // base, len, cap = pieces of x[1:] 62 // x = {base, len, cap} 63 // 64 // then the liveness analysis would decide the previous value of x was 65 // unnecessary even though it is about to be used by the x[1:] computation. 66 // Similarly, if the generated code looked like: 67 // 68 // base, len, cap = pieces of x[1:] 69 // x = {base, len, cap} 70 // VARDEF x 71 // 72 // then the liveness analysis will not preserve the new value of x, because 73 // the VARDEF appears to have "overwritten" it. 74 // 75 // VARDEF is a bit of a kludge to work around the fact that the instruction 76 // stream is working on single-word values but the liveness analysis 77 // wants to work on individual variables, which might be multi-word 78 // aggregates. It might make sense at some point to look into letting 79 // the liveness analysis work on single-word values as well, although 80 // there are complications around interface values, slices, and strings, 81 // all of which cannot be treated as individual words. 82 // 83 // VARKILL is the opposite of VARDEF: it marks a value as no longer needed, 84 // even if its address has been taken. That is, a VARKILL annotation asserts 85 // that its argument is certainly dead, for use when the liveness analysis 86 // would not otherwise be able to deduce that fact. 87 88 func gvardefx(n *Node, as int) { 89 if n == nil { 90 Fatal("gvardef nil") 91 } 92 if n.Op != ONAME { 93 Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n) 94 return 95 } 96 97 switch n.Class { 98 case PAUTO, PPARAM, PPARAMOUT: 99 Thearch.Gins(as, nil, n) 100 } 101 } 102 103 func Gvardef(n *Node) { 104 gvardefx(n, obj.AVARDEF) 105 } 106 107 func gvarkill(n *Node) { 108 gvardefx(n, obj.AVARKILL) 109 } 110 111 func removevardef(firstp *obj.Prog) { 112 for p := firstp; p != nil; p = p.Link { 113 for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) { 114 p.Link = p.Link.Link 115 } 116 if p.To.Type == obj.TYPE_BRANCH { 117 for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL) { 118 p.To.Val = p.To.Val.(*obj.Prog).Link 119 } 120 } 121 } 122 } 123 124 func gcsymdup(s *Sym) { 125 ls := Linksym(s) 126 if len(ls.R) > 0 { 127 Fatal("cannot rosymdup %s with relocations", ls.Name) 128 } 129 ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P)) 130 ls.Dupok = 1 131 } 132 133 func emitptrargsmap() { 134 sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Nname.Sym.Name)) 135 136 nptr := int(Curfn.Type.Argwid / int64(Widthptr)) 137 bv := bvalloc(int32(nptr) * 2) 138 nbitmap := 1 139 if Curfn.Type.Outtuple > 0 { 140 nbitmap = 2 141 } 142 off := duint32(sym, 0, uint32(nbitmap)) 143 off = duint32(sym, off, uint32(bv.n)) 144 var xoffset int64 145 if Curfn.Type.Thistuple > 0 { 146 xoffset = 0 147 onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv) 148 } 149 150 if Curfn.Type.Intuple > 0 { 151 xoffset = 0 152 onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv) 153 } 154 155 for j := 0; int32(j) < bv.n; j += 32 { 156 off = duint32(sym, off, bv.b[j/32]) 157 } 158 if Curfn.Type.Outtuple > 0 { 159 xoffset = 0 160 onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv) 161 for j := 0; int32(j) < bv.n; j += 32 { 162 off = duint32(sym, off, bv.b[j/32]) 163 } 164 } 165 166 ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL) 167 } 168 169 // Sort the list of stack variables. Autos after anything else, 170 // within autos, unused after used, within used, things with 171 // pointers first, zeroed things first, and then decreasing size. 172 // Because autos are laid out in decreasing addresses 173 // on the stack, pointers first, zeroed things first and decreasing size 174 // really means, in memory, things with pointers needing zeroing at 175 // the top of the stack and increasing in size. 176 // Non-autos sort on offset. 177 func cmpstackvar(a *Node, b *Node) int { 178 if a.Class != b.Class { 179 if a.Class == PAUTO { 180 return +1 181 } 182 return -1 183 } 184 185 if a.Class != PAUTO { 186 if a.Xoffset < b.Xoffset { 187 return -1 188 } 189 if a.Xoffset > b.Xoffset { 190 return +1 191 } 192 return 0 193 } 194 195 if a.Used != b.Used { 196 return obj.Bool2int(b.Used) - obj.Bool2int(a.Used) 197 } 198 199 ap := obj.Bool2int(haspointers(a.Type)) 200 bp := obj.Bool2int(haspointers(b.Type)) 201 if ap != bp { 202 return bp - ap 203 } 204 205 ap = obj.Bool2int(a.Needzero) 206 bp = obj.Bool2int(b.Needzero) 207 if ap != bp { 208 return bp - ap 209 } 210 211 if a.Type.Width < b.Type.Width { 212 return +1 213 } 214 if a.Type.Width > b.Type.Width { 215 return -1 216 } 217 218 return stringsCompare(a.Sym.Name, b.Sym.Name) 219 } 220 221 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 222 func allocauto(ptxt *obj.Prog) { 223 Stksize = 0 224 stkptrsize = 0 225 226 if Curfn.Func.Dcl == nil { 227 return 228 } 229 230 // Mark the PAUTO's unused. 231 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 232 if ll.N.Class == PAUTO { 233 ll.N.Used = false 234 } 235 } 236 237 markautoused(ptxt) 238 239 listsort(&Curfn.Func.Dcl, cmpstackvar) 240 241 // Unused autos are at the end, chop 'em off. 242 ll := Curfn.Func.Dcl 243 244 n := ll.N 245 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 246 // No locals used at all 247 Curfn.Func.Dcl = nil 248 249 fixautoused(ptxt) 250 return 251 } 252 253 for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next { 254 n = ll.Next.N 255 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 256 ll.Next = nil 257 Curfn.Func.Dcl.End = ll 258 break 259 } 260 } 261 262 // Reassign stack offsets of the locals that are still there. 263 var w int64 264 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 265 n = ll.N 266 if n.Class != PAUTO || n.Op != ONAME { 267 continue 268 } 269 270 dowidth(n.Type) 271 w = n.Type.Width 272 if w >= Thearch.MAXWIDTH || w < 0 { 273 Fatal("bad width") 274 } 275 Stksize += w 276 Stksize = Rnd(Stksize, int64(n.Type.Align)) 277 if haspointers(n.Type) { 278 stkptrsize = Stksize 279 } 280 if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { 281 Stksize = Rnd(Stksize, int64(Widthptr)) 282 } 283 if Stksize >= 1<<31 { 284 setlineno(Curfn) 285 Yyerror("stack frame too large (>2GB)") 286 } 287 288 n.Stkdelta = -Stksize - n.Xoffset 289 } 290 291 Stksize = Rnd(Stksize, int64(Widthreg)) 292 stkptrsize = Rnd(stkptrsize, int64(Widthreg)) 293 294 fixautoused(ptxt) 295 296 // The debug information needs accurate offsets on the symbols. 297 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 298 if ll.N.Class != PAUTO || ll.N.Op != ONAME { 299 continue 300 } 301 ll.N.Xoffset += ll.N.Stkdelta 302 ll.N.Stkdelta = 0 303 } 304 } 305 306 func movelarge(l *NodeList) { 307 for ; l != nil; l = l.Next { 308 if l.N.Op == ODCLFUNC { 309 movelargefn(l.N) 310 } 311 } 312 } 313 314 func movelargefn(fn *Node) { 315 var n *Node 316 317 for l := fn.Func.Dcl; l != nil; l = l.Next { 318 n = l.N 319 if n.Class == PAUTO && n.Type != nil && n.Type.Width > MaxStackVarSize { 320 addrescapes(n) 321 } 322 } 323 } 324 325 func Cgen_checknil(n *Node) { 326 if Disable_checknil != 0 { 327 return 328 } 329 330 // Ideally we wouldn't see any integer types here, but we do. 331 if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) { 332 Dump("checknil", n) 333 Fatal("bad checknil") 334 } 335 336 if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL { 337 var reg Node 338 Regalloc(®, Types[Tptr], n) 339 Cgen(n, ®) 340 Thearch.Gins(obj.ACHECKNIL, ®, nil) 341 Regfree(®) 342 return 343 } 344 345 Thearch.Gins(obj.ACHECKNIL, n, nil) 346 } 347 348 func compile(fn *Node) { 349 if Newproc == nil { 350 Newproc = Sysfunc("newproc") 351 Deferproc = Sysfunc("deferproc") 352 Deferreturn = Sysfunc("deferreturn") 353 Panicindex = Sysfunc("panicindex") 354 panicslice = Sysfunc("panicslice") 355 throwreturn = Sysfunc("throwreturn") 356 } 357 358 lno := setlineno(fn) 359 360 Curfn = fn 361 dowidth(Curfn.Type) 362 363 var oldstksize int64 364 var nod1 Node 365 var ptxt *obj.Prog 366 var pl *obj.Plist 367 var p *obj.Prog 368 var n *Node 369 var nam *Node 370 var gcargs *Sym 371 var gclocals *Sym 372 if fn.Nbody == nil { 373 if pure_go != 0 || strings.HasPrefix(fn.Nname.Sym.Name, "init.") { 374 Yyerror("missing function body for %q", fn.Nname.Sym.Name) 375 goto ret 376 } 377 378 if Debug['A'] != 0 { 379 goto ret 380 } 381 emitptrargsmap() 382 goto ret 383 } 384 385 saveerrors() 386 387 // set up domain for labels 388 clearlabels() 389 390 if Curfn.Type.Outnamed != 0 { 391 // add clearing of the output parameters 392 var save Iter 393 t := Structfirst(&save, Getoutarg(Curfn.Type)) 394 395 for t != nil { 396 if t.Nname != nil { 397 n = Nod(OAS, t.Nname, nil) 398 typecheck(&n, Etop) 399 Curfn.Nbody = concat(list1(n), Curfn.Nbody) 400 } 401 402 t = structnext(&save) 403 } 404 } 405 406 order(Curfn) 407 if nerrors != 0 { 408 goto ret 409 } 410 411 Hasdefer = 0 412 walk(Curfn) 413 if nerrors != 0 { 414 goto ret 415 } 416 if flag_race != 0 { 417 racewalk(Curfn) 418 } 419 if nerrors != 0 { 420 goto ret 421 } 422 423 continpc = nil 424 breakpc = nil 425 426 pl = newplist() 427 pl.Name = Linksym(Curfn.Nname.Sym) 428 429 setlineno(Curfn) 430 431 Nodconst(&nod1, Types[TINT32], 0) 432 nam = Curfn.Nname 433 if isblank(nam) { 434 nam = nil 435 } 436 ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1) 437 if fn.Func.Dupok { 438 ptxt.From3.Offset |= obj.DUPOK 439 } 440 if fn.Func.Wrapper { 441 ptxt.From3.Offset |= obj.WRAPPER 442 } 443 if fn.Func.Needctxt { 444 ptxt.From3.Offset |= obj.NEEDCTXT 445 } 446 if fn.Func.Nosplit { 447 ptxt.From3.Offset |= obj.NOSPLIT 448 } 449 450 // Clumsy but important. 451 // See test/recover.go for test cases and src/reflect/value.go 452 // for the actual functions being considered. 453 if myimportpath != "" && myimportpath == "reflect" { 454 if Curfn.Nname.Sym.Name == "callReflect" || Curfn.Nname.Sym.Name == "callMethod" { 455 ptxt.From3.Offset |= obj.WRAPPER 456 } 457 } 458 459 Afunclit(&ptxt.From, Curfn.Nname) 460 461 ginit() 462 463 gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps) 464 gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps) 465 466 for t := Curfn.Paramfld; t != nil; t = t.Down { 467 gtrack(tracksym(t.Type)) 468 } 469 470 for l := fn.Func.Dcl; l != nil; l = l.Next { 471 n = l.N 472 if n.Op != ONAME { // might be OTYPE or OLITERAL 473 continue 474 } 475 switch n.Class { 476 case PAUTO, PPARAM, PPARAMOUT: 477 Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width) 478 p = Thearch.Gins(obj.ATYPE, l.N, &nod1) 479 p.From.Gotype = Linksym(ngotype(l.N)) 480 } 481 } 482 483 Genlist(Curfn.Func.Enter) 484 Genlist(Curfn.Nbody) 485 gclean() 486 checklabels() 487 if nerrors != 0 { 488 goto ret 489 } 490 if Curfn.Func.Endlineno != 0 { 491 lineno = Curfn.Func.Endlineno 492 } 493 494 if Curfn.Type.Outtuple != 0 { 495 Ginscall(throwreturn, 0) 496 } 497 498 ginit() 499 500 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? 501 cgen_ret(nil) 502 503 if Hasdefer != 0 { 504 // deferreturn pretends to have one uintptr argument. 505 // Reserve space for it so stack scanner is happy. 506 if Maxarg < int64(Widthptr) { 507 Maxarg = int64(Widthptr) 508 } 509 } 510 511 gclean() 512 if nerrors != 0 { 513 goto ret 514 } 515 516 Pc.As = obj.ARET // overwrite AEND 517 Pc.Lineno = lineno 518 519 fixjmp(ptxt) 520 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 { 521 regopt(ptxt) 522 nilopt(ptxt) 523 } 524 525 Thearch.Expandchecks(ptxt) 526 527 oldstksize = Stksize 528 allocauto(ptxt) 529 530 if false { 531 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize)) 532 } 533 534 setlineno(Curfn) 535 if int64(Stksize)+Maxarg > 1<<31 { 536 Yyerror("stack frame too large (>2GB)") 537 goto ret 538 } 539 540 // Emit garbage collection symbols. 541 liveness(Curfn, ptxt, gcargs, gclocals) 542 543 gcsymdup(gcargs) 544 gcsymdup(gclocals) 545 546 Thearch.Defframe(ptxt) 547 548 if Debug['f'] != 0 { 549 frame(0) 550 } 551 552 // Remove leftover instrumentation from the instruction stream. 553 removevardef(ptxt) 554 555 ret: 556 lineno = lno 557 }