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