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/internal/obj" 9 "crypto/md5" 10 "fmt" 11 "strings" 12 ) 13 14 // "Portable" code generation. 15 16 var makefuncdatasym_nsym int32 17 18 func makefuncdatasym(namefmt string, funcdatakind int64) *Sym { 19 var nod Node 20 21 sym := Lookupf(namefmt, makefuncdatasym_nsym) 22 makefuncdatasym_nsym++ 23 pnod := newname(sym) 24 pnod.Class = PEXTERN 25 Nodconst(&nod, Types[TINT32], funcdatakind) 26 Thearch.Gins(obj.AFUNCDATA, &nod, pnod) 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 int) { 87 if n == nil { 88 Fatal("gvardef nil") 89 } 90 if n.Op != ONAME { 91 Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n) 92 return 93 } 94 95 switch n.Class { 96 case PAUTO, PPARAM, PPARAMOUT: 97 Thearch.Gins(as, nil, n) 98 } 99 } 100 101 func Gvardef(n *Node) { 102 gvardefx(n, obj.AVARDEF) 103 } 104 105 func gvarkill(n *Node) { 106 gvardefx(n, obj.AVARKILL) 107 } 108 109 func removevardef(firstp *obj.Prog) { 110 for p := firstp; p != nil; p = p.Link { 111 for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) { 112 p.Link = p.Link.Link 113 } 114 if p.To.Type == obj.TYPE_BRANCH { 115 for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL) { 116 p.To.Val = p.To.Val.(*obj.Prog).Link 117 } 118 } 119 } 120 } 121 122 func gcsymdup(s *Sym) { 123 ls := Linksym(s) 124 if len(ls.R) > 0 { 125 Fatal("cannot rosymdup %s with relocations", ls.Name) 126 } 127 ls.Name = fmt.Sprintf("gclocals%x", md5.Sum(ls.P)) 128 ls.Dupok = 1 129 } 130 131 func emitptrargsmap() { 132 sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name)) 133 134 nptr := int(Curfn.Type.Argwid / int64(Widthptr)) 135 bv := bvalloc(int32(nptr) * 2) 136 nbitmap := 1 137 if Curfn.Type.Outtuple > 0 { 138 nbitmap = 2 139 } 140 off := duint32(sym, 0, uint32(nbitmap)) 141 off = duint32(sym, off, uint32(bv.n)) 142 var xoffset int64 143 if Curfn.Type.Thistuple > 0 { 144 xoffset = 0 145 onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv) 146 } 147 148 if Curfn.Type.Intuple > 0 { 149 xoffset = 0 150 onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv) 151 } 152 153 for j := 0; int32(j) < bv.n; j += 32 { 154 off = duint32(sym, off, bv.b[j/32]) 155 } 156 if Curfn.Type.Outtuple > 0 { 157 xoffset = 0 158 onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv) 159 for j := 0; int32(j) < bv.n; j += 32 { 160 off = duint32(sym, off, bv.b[j/32]) 161 } 162 } 163 164 ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL) 165 } 166 167 // Sort the list of stack variables. Autos after anything else, 168 // within autos, unused after used, within used, things with 169 // pointers first, zeroed things first, and then decreasing size. 170 // Because autos are laid out in decreasing addresses 171 // on the stack, pointers first, zeroed things first and decreasing size 172 // really means, in memory, things with pointers needing zeroing at 173 // the top of the stack and increasing in size. 174 // Non-autos sort on offset. 175 func cmpstackvar(a *Node, b *Node) int { 176 if a.Class != b.Class { 177 if a.Class == PAUTO { 178 return +1 179 } 180 return -1 181 } 182 183 if a.Class != PAUTO { 184 if a.Xoffset < b.Xoffset { 185 return -1 186 } 187 if a.Xoffset > b.Xoffset { 188 return +1 189 } 190 return 0 191 } 192 193 if a.Used != b.Used { 194 return obj.Bool2int(b.Used) - obj.Bool2int(a.Used) 195 } 196 197 ap := obj.Bool2int(haspointers(a.Type)) 198 bp := obj.Bool2int(haspointers(b.Type)) 199 if ap != bp { 200 return bp - ap 201 } 202 203 ap = obj.Bool2int(a.Name.Needzero) 204 bp = obj.Bool2int(b.Name.Needzero) 205 if ap != bp { 206 return bp - ap 207 } 208 209 if a.Type.Width < b.Type.Width { 210 return +1 211 } 212 if a.Type.Width > b.Type.Width { 213 return -1 214 } 215 216 return stringsCompare(a.Sym.Name, b.Sym.Name) 217 } 218 219 // stkdelta records the stack offset delta for a node 220 // during the compaction of the stack frame to remove 221 // unused stack slots. 222 var stkdelta = map[*Node]int64{} 223 224 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 225 func allocauto(ptxt *obj.Prog) { 226 Stksize = 0 227 stkptrsize = 0 228 229 if Curfn.Func.Dcl == nil { 230 return 231 } 232 233 // Mark the PAUTO's unused. 234 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 235 if ll.N.Class == PAUTO { 236 ll.N.Used = false 237 } 238 } 239 240 markautoused(ptxt) 241 242 listsort(&Curfn.Func.Dcl, cmpstackvar) 243 244 // Unused autos are at the end, chop 'em off. 245 ll := Curfn.Func.Dcl 246 247 n := ll.N 248 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 249 // No locals used at all 250 Curfn.Func.Dcl = nil 251 252 fixautoused(ptxt) 253 return 254 } 255 256 for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next { 257 n = ll.Next.N 258 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 259 ll.Next = nil 260 Curfn.Func.Dcl.End = ll 261 break 262 } 263 } 264 265 // Reassign stack offsets of the locals that are still there. 266 var w int64 267 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 268 n = ll.N 269 if n.Class != PAUTO || n.Op != ONAME { 270 continue 271 } 272 273 dowidth(n.Type) 274 w = n.Type.Width 275 if w >= Thearch.MAXWIDTH || w < 0 { 276 Fatal("bad width") 277 } 278 Stksize += w 279 Stksize = Rnd(Stksize, int64(n.Type.Align)) 280 if haspointers(n.Type) { 281 stkptrsize = Stksize 282 } 283 if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { 284 Stksize = Rnd(Stksize, int64(Widthptr)) 285 } 286 if Stksize >= 1<<31 { 287 setlineno(Curfn) 288 Yyerror("stack frame too large (>2GB)") 289 } 290 291 stkdelta[n] = -Stksize - n.Xoffset 292 } 293 294 Stksize = Rnd(Stksize, int64(Widthreg)) 295 stkptrsize = Rnd(stkptrsize, int64(Widthreg)) 296 297 fixautoused(ptxt) 298 299 // The debug information needs accurate offsets on the symbols. 300 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 301 if ll.N.Class != PAUTO || ll.N.Op != ONAME { 302 continue 303 } 304 ll.N.Xoffset += stkdelta[ll.N] 305 delete(stkdelta, ll.N) 306 } 307 } 308 309 func Cgen_checknil(n *Node) { 310 if Disable_checknil != 0 { 311 return 312 } 313 314 // Ideally we wouldn't see any integer types here, but we do. 315 if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) { 316 Dump("checknil", n) 317 Fatal("bad checknil") 318 } 319 320 if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL { 321 var reg Node 322 Regalloc(®, Types[Tptr], n) 323 Cgen(n, ®) 324 Thearch.Gins(obj.ACHECKNIL, ®, nil) 325 Regfree(®) 326 return 327 } 328 329 Thearch.Gins(obj.ACHECKNIL, n, nil) 330 } 331 332 func compile(fn *Node) { 333 if Newproc == nil { 334 Newproc = Sysfunc("newproc") 335 Deferproc = Sysfunc("deferproc") 336 Deferreturn = Sysfunc("deferreturn") 337 Panicindex = Sysfunc("panicindex") 338 panicslice = Sysfunc("panicslice") 339 throwreturn = Sysfunc("throwreturn") 340 } 341 342 lno := setlineno(fn) 343 344 Curfn = fn 345 dowidth(Curfn.Type) 346 347 var oldstksize int64 348 var nod1 Node 349 var ptxt *obj.Prog 350 var pl *obj.Plist 351 var p *obj.Prog 352 var n *Node 353 var nam *Node 354 var gcargs *Sym 355 var gclocals *Sym 356 if fn.Nbody == nil { 357 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { 358 Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) 359 goto ret 360 } 361 362 if Debug['A'] != 0 { 363 goto ret 364 } 365 emitptrargsmap() 366 goto ret 367 } 368 369 saveerrors() 370 371 // set up domain for labels 372 clearlabels() 373 374 if Curfn.Type.Outnamed != 0 { 375 // add clearing of the output parameters 376 var save Iter 377 t := Structfirst(&save, Getoutarg(Curfn.Type)) 378 379 for t != nil { 380 if t.Nname != nil { 381 n = Nod(OAS, t.Nname, nil) 382 typecheck(&n, Etop) 383 Curfn.Nbody = concat(list1(n), Curfn.Nbody) 384 } 385 386 t = structnext(&save) 387 } 388 } 389 390 order(Curfn) 391 if nerrors != 0 { 392 goto ret 393 } 394 395 Hasdefer = 0 396 walk(Curfn) 397 if nerrors != 0 { 398 goto ret 399 } 400 if flag_race != 0 { 401 racewalk(Curfn) 402 } 403 if nerrors != 0 { 404 goto ret 405 } 406 407 continpc = nil 408 breakpc = nil 409 410 pl = newplist() 411 pl.Name = Linksym(Curfn.Func.Nname.Sym) 412 413 setlineno(Curfn) 414 415 Nodconst(&nod1, Types[TINT32], 0) 416 nam = Curfn.Func.Nname 417 if isblank(nam) { 418 nam = nil 419 } 420 ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1) 421 Afunclit(&ptxt.From, Curfn.Func.Nname) 422 ptxt.From3 = new(obj.Addr) 423 if fn.Func.Dupok { 424 ptxt.From3.Offset |= obj.DUPOK 425 } 426 if fn.Func.Wrapper { 427 ptxt.From3.Offset |= obj.WRAPPER 428 } 429 if fn.Func.Needctxt { 430 ptxt.From3.Offset |= obj.NEEDCTXT 431 } 432 if fn.Func.Nosplit { 433 ptxt.From3.Offset |= obj.NOSPLIT 434 } 435 if fn.Func.Systemstack { 436 ptxt.From.Sym.Cfunc = 1 437 } 438 439 // Clumsy but important. 440 // See test/recover.go for test cases and src/reflect/value.go 441 // for the actual functions being considered. 442 if myimportpath != "" && myimportpath == "reflect" { 443 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" { 444 ptxt.From3.Offset |= obj.WRAPPER 445 } 446 } 447 448 ginit() 449 450 gcargs = makefuncdatasym("gcargs%d", obj.FUNCDATA_ArgsPointerMaps) 451 gclocals = makefuncdatasym("gclocals%d", obj.FUNCDATA_LocalsPointerMaps) 452 453 for _, t := range Curfn.Func.Fieldtrack { 454 gtrack(tracksym(t)) 455 } 456 457 for l := fn.Func.Dcl; l != nil; l = l.Next { 458 n = l.N 459 if n.Op != ONAME { // might be OTYPE or OLITERAL 460 continue 461 } 462 switch n.Class { 463 case PAUTO, PPARAM, PPARAMOUT: 464 Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width) 465 p = Thearch.Gins(obj.ATYPE, l.N, &nod1) 466 p.From.Gotype = Linksym(ngotype(l.N)) 467 } 468 } 469 470 Genlist(Curfn.Func.Enter) 471 Genlist(Curfn.Nbody) 472 gclean() 473 checklabels() 474 if nerrors != 0 { 475 goto ret 476 } 477 if Curfn.Func.Endlineno != 0 { 478 lineno = Curfn.Func.Endlineno 479 } 480 481 if Curfn.Type.Outtuple != 0 { 482 Ginscall(throwreturn, 0) 483 } 484 485 ginit() 486 487 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? 488 cgen_ret(nil) 489 490 if Hasdefer != 0 { 491 // deferreturn pretends to have one uintptr argument. 492 // Reserve space for it so stack scanner is happy. 493 if Maxarg < int64(Widthptr) { 494 Maxarg = int64(Widthptr) 495 } 496 } 497 498 gclean() 499 if nerrors != 0 { 500 goto ret 501 } 502 503 Pc.As = obj.ARET // overwrite AEND 504 Pc.Lineno = lineno 505 506 fixjmp(ptxt) 507 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 { 508 regopt(ptxt) 509 nilopt(ptxt) 510 } 511 512 Thearch.Expandchecks(ptxt) 513 514 oldstksize = Stksize 515 allocauto(ptxt) 516 517 if false { 518 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize)) 519 } 520 521 setlineno(Curfn) 522 if int64(Stksize)+Maxarg > 1<<31 { 523 Yyerror("stack frame too large (>2GB)") 524 goto ret 525 } 526 527 // Emit garbage collection symbols. 528 liveness(Curfn, ptxt, gcargs, gclocals) 529 530 gcsymdup(gcargs) 531 gcsymdup(gclocals) 532 533 Thearch.Defframe(ptxt) 534 535 if Debug['f'] != 0 { 536 frame(0) 537 } 538 539 // Remove leftover instrumentation from the instruction stream. 540 removevardef(ptxt) 541 542 ret: 543 lineno = lno 544 } 545