github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/ssa/debug.go (about) 1 // Copyright 2017 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 ssa 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/abi" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/abt" 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 12 "github.com/bir3/gocompiler/src/cmd/internal/dwarf" 13 "github.com/bir3/gocompiler/src/cmd/internal/obj" 14 "github.com/bir3/gocompiler/src/cmd/internal/src" 15 "encoding/hex" 16 "fmt" 17 "github.com/bir3/gocompiler/src/internal/buildcfg" 18 "math/bits" 19 "sort" 20 "strings" 21 ) 22 23 type SlotID int32 24 type VarID int32 25 26 // A FuncDebug contains all the debug information for the variables in a 27 // function. Variables are identified by their LocalSlot, which may be 28 // the result of decomposing a larger variable. 29 type FuncDebug struct { 30 // Slots is all the slots used in the debug info, indexed by their SlotID. 31 Slots []LocalSlot 32 // The user variables, indexed by VarID. 33 Vars []*ir.Name 34 // The slots that make up each variable, indexed by VarID. 35 VarSlots [][]SlotID 36 // The location list data, indexed by VarID. Must be processed by PutLocationList. 37 LocationLists [][]byte 38 // Register-resident output parameters for the function. This is filled in at 39 // SSA generation time. 40 RegOutputParams []*ir.Name 41 // Variable declarations that were removed during optimization 42 OptDcl []*ir.Name 43 44 // Filled in by the user. Translates Block and Value ID to PC. 45 // 46 // NOTE: block is only used if value is BlockStart.ID or BlockEnd.ID. 47 // Otherwise, it is ignored. 48 GetPC func(block, value ID) int64 49 } 50 51 type BlockDebug struct { 52 // State at the start and end of the block. These are initialized, 53 // and updated from new information that flows on back edges. 54 startState, endState abt.T 55 // Use these to avoid excess work in the merge. If none of the 56 // predecessors has changed since the last check, the old answer is 57 // still good. 58 lastCheckedTime, lastChangedTime int32 59 // Whether the block had any changes to user variables at all. 60 relevant bool 61 // false until the block has been processed at least once. This 62 // affects how the merge is done; the goal is to maximize sharing 63 // and avoid allocation. 64 everProcessed bool 65 } 66 67 // A liveSlot is a slot that's live in loc at entry/exit of a block. 68 type liveSlot struct { 69 VarLoc 70 } 71 72 func (ls *liveSlot) String() string { 73 return fmt.Sprintf("0x%x.%d.%d", ls.Registers, ls.stackOffsetValue(), int32(ls.StackOffset)&1) 74 } 75 76 func (ls liveSlot) absent() bool { 77 return ls.Registers == 0 && !ls.onStack() 78 } 79 80 // StackOffset encodes whether a value is on the stack and if so, where. 81 // It is a 31-bit integer followed by a presence flag at the low-order 82 // bit. 83 type StackOffset int32 84 85 func (s StackOffset) onStack() bool { 86 return s != 0 87 } 88 89 func (s StackOffset) stackOffsetValue() int32 { 90 return int32(s) >> 1 91 } 92 93 // stateAtPC is the current state of all variables at some point. 94 type stateAtPC struct { 95 // The location of each known slot, indexed by SlotID. 96 slots []VarLoc 97 // The slots present in each register, indexed by register number. 98 registers [][]SlotID 99 } 100 101 // reset fills state with the live variables from live. 102 func (state *stateAtPC) reset(live abt.T) { 103 slots, registers := state.slots, state.registers 104 for i := range slots { 105 slots[i] = VarLoc{} 106 } 107 for i := range registers { 108 registers[i] = registers[i][:0] 109 } 110 for it := live.Iterator(); !it.Done(); { 111 k, d := it.Next() 112 live := d.(*liveSlot) 113 slots[k] = live.VarLoc 114 if live.VarLoc.Registers == 0 { 115 continue 116 } 117 118 mask := uint64(live.VarLoc.Registers) 119 for { 120 if mask == 0 { 121 break 122 } 123 reg := uint8(bits.TrailingZeros64(mask)) 124 mask &^= 1 << reg 125 126 registers[reg] = append(registers[reg], SlotID(k)) 127 } 128 } 129 state.slots, state.registers = slots, registers 130 } 131 132 func (s *debugState) LocString(loc VarLoc) string { 133 if loc.absent() { 134 return "<nil>" 135 } 136 137 var storage []string 138 if loc.onStack() { 139 storage = append(storage, fmt.Sprintf("@%+d", loc.stackOffsetValue())) 140 } 141 142 mask := uint64(loc.Registers) 143 for { 144 if mask == 0 { 145 break 146 } 147 reg := uint8(bits.TrailingZeros64(mask)) 148 mask &^= 1 << reg 149 150 storage = append(storage, s.registers[reg].String()) 151 } 152 return strings.Join(storage, ",") 153 } 154 155 // A VarLoc describes the storage for part of a user variable. 156 type VarLoc struct { 157 // The registers this variable is available in. There can be more than 158 // one in various situations, e.g. it's being moved between registers. 159 Registers RegisterSet 160 161 StackOffset 162 } 163 164 func (loc VarLoc) absent() bool { 165 return loc.Registers == 0 && !loc.onStack() 166 } 167 168 func (loc VarLoc) intersect(other VarLoc) VarLoc { 169 if !loc.onStack() || !other.onStack() || loc.StackOffset != other.StackOffset { 170 loc.StackOffset = 0 171 } 172 loc.Registers &= other.Registers 173 return loc 174 } 175 176 var BlockStart = &Value{ 177 ID: -10000, 178 Op: OpInvalid, 179 Aux: StringToAux("BlockStart"), 180 } 181 182 var BlockEnd = &Value{ 183 ID: -20000, 184 Op: OpInvalid, 185 Aux: StringToAux("BlockEnd"), 186 } 187 188 var FuncEnd = &Value{ 189 ID: -30000, 190 Op: OpInvalid, 191 Aux: StringToAux("FuncEnd"), 192 } 193 194 // RegisterSet is a bitmap of registers, indexed by Register.num. 195 type RegisterSet uint64 196 197 // logf prints debug-specific logging to stdout (always stdout) if the 198 // current function is tagged by GOSSAFUNC (for ssa output directed 199 // either to stdout or html). 200 func (s *debugState) logf(msg string, args ...interface{}) { 201 if s.f.PrintOrHtmlSSA { 202 fmt.Printf(msg, args...) 203 } 204 } 205 206 type debugState struct { 207 // See FuncDebug. 208 slots []LocalSlot 209 vars []*ir.Name 210 varSlots [][]SlotID 211 lists [][]byte 212 213 // The user variable that each slot rolls up to, indexed by SlotID. 214 slotVars []VarID 215 216 f *Func 217 loggingLevel int 218 convergeCount int // testing; iterate over block debug state this many times 219 registers []Register 220 stackOffset func(LocalSlot) int32 221 ctxt *obj.Link 222 223 // The names (slots) associated with each value, indexed by Value ID. 224 valueNames [][]SlotID 225 226 // The current state of whatever analysis is running. 227 currentState stateAtPC 228 changedVars *sparseSet 229 changedSlots *sparseSet 230 231 // The pending location list entry for each user variable, indexed by VarID. 232 pendingEntries []pendingEntry 233 234 varParts map[*ir.Name][]SlotID 235 blockDebug []BlockDebug 236 pendingSlotLocs []VarLoc 237 partsByVarOffset sort.Interface 238 } 239 240 func (state *debugState) initializeCache(f *Func, numVars, numSlots int) { 241 // One blockDebug per block. Initialized in allocBlock. 242 if cap(state.blockDebug) < f.NumBlocks() { 243 state.blockDebug = make([]BlockDebug, f.NumBlocks()) 244 } else { 245 // This local variable, and the ones like it below, enable compiler 246 // optimizations. Don't inline them. 247 b := state.blockDebug[:f.NumBlocks()] 248 for i := range b { 249 b[i] = BlockDebug{} 250 } 251 } 252 253 // A list of slots per Value. Reuse the previous child slices. 254 if cap(state.valueNames) < f.NumValues() { 255 old := state.valueNames 256 state.valueNames = make([][]SlotID, f.NumValues()) 257 copy(state.valueNames, old) 258 } 259 vn := state.valueNames[:f.NumValues()] 260 for i := range vn { 261 vn[i] = vn[i][:0] 262 } 263 264 // Slot and register contents for currentState. Cleared by reset(). 265 if cap(state.currentState.slots) < numSlots { 266 state.currentState.slots = make([]VarLoc, numSlots) 267 } else { 268 state.currentState.slots = state.currentState.slots[:numSlots] 269 } 270 if cap(state.currentState.registers) < len(state.registers) { 271 state.currentState.registers = make([][]SlotID, len(state.registers)) 272 } else { 273 state.currentState.registers = state.currentState.registers[:len(state.registers)] 274 } 275 276 // A relatively small slice, but used many times as the return from processValue. 277 state.changedVars = newSparseSet(numVars) 278 state.changedSlots = newSparseSet(numSlots) 279 280 // A pending entry per user variable, with space to track each of its pieces. 281 numPieces := 0 282 for i := range state.varSlots { 283 numPieces += len(state.varSlots[i]) 284 } 285 if cap(state.pendingSlotLocs) < numPieces { 286 state.pendingSlotLocs = make([]VarLoc, numPieces) 287 } else { 288 psl := state.pendingSlotLocs[:numPieces] 289 for i := range psl { 290 psl[i] = VarLoc{} 291 } 292 } 293 if cap(state.pendingEntries) < numVars { 294 state.pendingEntries = make([]pendingEntry, numVars) 295 } 296 pe := state.pendingEntries[:numVars] 297 freePieceIdx := 0 298 for varID, slots := range state.varSlots { 299 pe[varID] = pendingEntry{ 300 pieces: state.pendingSlotLocs[freePieceIdx : freePieceIdx+len(slots)], 301 } 302 freePieceIdx += len(slots) 303 } 304 state.pendingEntries = pe 305 306 if cap(state.lists) < numVars { 307 state.lists = make([][]byte, numVars) 308 } else { 309 state.lists = state.lists[:numVars] 310 for i := range state.lists { 311 state.lists[i] = nil 312 } 313 } 314 } 315 316 func (state *debugState) allocBlock(b *Block) *BlockDebug { 317 return &state.blockDebug[b.ID] 318 } 319 320 func (s *debugState) blockEndStateString(b *BlockDebug) string { 321 endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.registers))} 322 endState.reset(b.endState) 323 return s.stateString(endState) 324 } 325 326 func (s *debugState) stateString(state stateAtPC) string { 327 var strs []string 328 for slotID, loc := range state.slots { 329 if !loc.absent() { 330 strs = append(strs, fmt.Sprintf("\t%v = %v\n", s.slots[slotID], s.LocString(loc))) 331 } 332 } 333 334 strs = append(strs, "\n") 335 for reg, slots := range state.registers { 336 if len(slots) != 0 { 337 var slotStrs []string 338 for _, slot := range slots { 339 slotStrs = append(slotStrs, s.slots[slot].String()) 340 } 341 strs = append(strs, fmt.Sprintf("\t%v = %v\n", &s.registers[reg], slotStrs)) 342 } 343 } 344 345 if len(strs) == 1 { 346 return "(no vars)\n" 347 } 348 return strings.Join(strs, "") 349 } 350 351 // slotCanonicalizer is a table used to lookup and canonicalize 352 // LocalSlot's in a type insensitive way (e.g. taking into account the 353 // base name, offset, and width of the slot, but ignoring the slot 354 // type). 355 type slotCanonicalizer struct { 356 slmap map[slotKey]SlKeyIdx 357 slkeys []LocalSlot 358 } 359 360 func newSlotCanonicalizer() *slotCanonicalizer { 361 return &slotCanonicalizer{ 362 slmap: make(map[slotKey]SlKeyIdx), 363 slkeys: []LocalSlot{LocalSlot{N: nil}}, 364 } 365 } 366 367 type SlKeyIdx uint32 368 369 const noSlot = SlKeyIdx(0) 370 371 // slotKey is a type-insensitive encapsulation of a LocalSlot; it 372 // is used to key a map within slotCanonicalizer. 373 type slotKey struct { 374 name *ir.Name 375 offset int64 376 width int64 377 splitOf SlKeyIdx // idx in slkeys slice in slotCanonicalizer 378 splitOffset int64 379 } 380 381 // lookup looks up a LocalSlot in the slot canonicalizer "sc", returning 382 // a canonical index for the slot, and adding it to the table if need 383 // be. Return value is the canonical slot index, and a boolean indicating 384 // whether the slot was found in the table already (TRUE => found). 385 func (sc *slotCanonicalizer) lookup(ls LocalSlot) (SlKeyIdx, bool) { 386 split := noSlot 387 if ls.SplitOf != nil { 388 split, _ = sc.lookup(*ls.SplitOf) 389 } 390 k := slotKey{ 391 name: ls.N, offset: ls.Off, width: ls.Type.Size(), 392 splitOf: split, splitOffset: ls.SplitOffset, 393 } 394 if idx, ok := sc.slmap[k]; ok { 395 return idx, true 396 } 397 rv := SlKeyIdx(len(sc.slkeys)) 398 sc.slkeys = append(sc.slkeys, ls) 399 sc.slmap[k] = rv 400 return rv, false 401 } 402 403 func (sc *slotCanonicalizer) canonSlot(idx SlKeyIdx) LocalSlot { 404 return sc.slkeys[idx] 405 } 406 407 // PopulateABIInRegArgOps examines the entry block of the function 408 // and looks for incoming parameters that have missing or partial 409 // OpArg{Int,Float}Reg values, inserting additional values in 410 // cases where they are missing. Example: 411 // 412 // func foo(s string, used int, notused int) int { 413 // return len(s) + used 414 // } 415 // 416 // In the function above, the incoming parameter "used" is fully live, 417 // "notused" is not live, and "s" is partially live (only the length 418 // field of the string is used). At the point where debug value 419 // analysis runs, we might expect to see an entry block with: 420 // 421 // b1: 422 // v4 = ArgIntReg <uintptr> {s+8} [0] : BX 423 // v5 = ArgIntReg <int> {used} [0] : CX 424 // 425 // While this is an accurate picture of the live incoming params, 426 // we also want to have debug locations for non-live params (or 427 // their non-live pieces), e.g. something like 428 // 429 // b1: 430 // v9 = ArgIntReg <*uint8> {s+0} [0] : AX 431 // v4 = ArgIntReg <uintptr> {s+8} [0] : BX 432 // v5 = ArgIntReg <int> {used} [0] : CX 433 // v10 = ArgIntReg <int> {unused} [0] : DI 434 // 435 // This function examines the live OpArg{Int,Float}Reg values and 436 // synthesizes new (dead) values for the non-live params or the 437 // non-live pieces of partially live params. 438 func PopulateABIInRegArgOps(f *Func) { 439 pri := f.ABISelf.ABIAnalyzeFuncType(f.Type) 440 441 // When manufacturing new slots that correspond to splits of 442 // composite parameters, we want to avoid creating a new sub-slot 443 // that differs from some existing sub-slot only by type, since 444 // the debug location analysis will treat that slot as a separate 445 // entity. To achieve this, create a lookup table of existing 446 // slots that is type-insenstitive. 447 sc := newSlotCanonicalizer() 448 for _, sl := range f.Names { 449 sc.lookup(*sl) 450 } 451 452 // Add slot -> value entry to f.NamedValues if not already present. 453 addToNV := func(v *Value, sl LocalSlot) { 454 values, ok := f.NamedValues[sl] 455 if !ok { 456 // Haven't seen this slot yet. 457 sla := f.localSlotAddr(sl) 458 f.Names = append(f.Names, sla) 459 } else { 460 for _, ev := range values { 461 if v == ev { 462 return 463 } 464 } 465 } 466 values = append(values, v) 467 f.NamedValues[sl] = values 468 } 469 470 newValues := []*Value{} 471 472 abiRegIndexToRegister := func(reg abi.RegIndex) int8 { 473 i := f.ABISelf.FloatIndexFor(reg) 474 if i >= 0 { // float PR 475 return f.Config.floatParamRegs[i] 476 } else { 477 return f.Config.intParamRegs[reg] 478 } 479 } 480 481 // Helper to construct a new OpArg{Float,Int}Reg op value. 482 var pos src.XPos 483 if len(f.Entry.Values) != 0 { 484 pos = f.Entry.Values[0].Pos 485 } 486 synthesizeOpIntFloatArg := func(n *ir.Name, t *types.Type, reg abi.RegIndex, sl LocalSlot) *Value { 487 aux := &AuxNameOffset{n, sl.Off} 488 op, auxInt := ArgOpAndRegisterFor(reg, f.ABISelf) 489 v := f.newValueNoBlock(op, t, pos) 490 v.AuxInt = auxInt 491 v.Aux = aux 492 v.Args = nil 493 v.Block = f.Entry 494 newValues = append(newValues, v) 495 addToNV(v, sl) 496 f.setHome(v, &f.Config.registers[abiRegIndexToRegister(reg)]) 497 return v 498 } 499 500 // Make a pass through the entry block looking for 501 // OpArg{Int,Float}Reg ops. Record the slots they use in a table 502 // ("sc"). We use a type-insensitive lookup for the slot table, 503 // since the type we get from the ABI analyzer won't always match 504 // what the compiler uses when creating OpArg{Int,Float}Reg ops. 505 for _, v := range f.Entry.Values { 506 if v.Op == OpArgIntReg || v.Op == OpArgFloatReg { 507 aux := v.Aux.(*AuxNameOffset) 508 sl := LocalSlot{N: aux.Name, Type: v.Type, Off: aux.Offset} 509 // install slot in lookup table 510 idx, _ := sc.lookup(sl) 511 // add to f.NamedValues if not already present 512 addToNV(v, sc.canonSlot(idx)) 513 } else if v.Op.IsCall() { 514 // if we hit a call, we've gone too far. 515 break 516 } 517 } 518 519 // Now make a pass through the ABI in-params, looking for params 520 // or pieces of params that we didn't encounter in the loop above. 521 for _, inp := range pri.InParams() { 522 if !isNamedRegParam(inp) { 523 continue 524 } 525 n := inp.Name 526 527 // Param is spread across one or more registers. Walk through 528 // each piece to see whether we've seen an arg reg op for it. 529 types, offsets := inp.RegisterTypesAndOffsets() 530 for k, t := range types { 531 // Note: this recipe for creating a LocalSlot is designed 532 // to be compatible with the one used in expand_calls.go 533 // as opposed to decompose.go. The expand calls code just 534 // takes the base name and creates an offset into it, 535 // without using the SplitOf/SplitOffset fields. The code 536 // in decompose.go does the opposite -- it creates a 537 // LocalSlot object with "Off" set to zero, but with 538 // SplitOf pointing to a parent slot, and SplitOffset 539 // holding the offset into the parent object. 540 pieceSlot := LocalSlot{N: n, Type: t, Off: offsets[k]} 541 542 // Look up this piece to see if we've seen a reg op 543 // for it. If not, create one. 544 _, found := sc.lookup(pieceSlot) 545 if !found { 546 // This slot doesn't appear in the map, meaning it 547 // corresponds to an in-param that is not live, or 548 // a portion of an in-param that is not live/used. 549 // Add a new dummy OpArg{Int,Float}Reg for it. 550 synthesizeOpIntFloatArg(n, t, inp.Registers[k], 551 pieceSlot) 552 } 553 } 554 } 555 556 // Insert the new values into the head of the block. 557 f.Entry.Values = append(newValues, f.Entry.Values...) 558 } 559 560 // BuildFuncDebug debug information for f, placing the results 561 // in "rval". f must be fully processed, so that each Value is where it 562 // will be when machine code is emitted. 563 func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingLevel int, stackOffset func(LocalSlot) int32, rval *FuncDebug) { 564 if f.RegAlloc == nil { 565 f.Fatalf("BuildFuncDebug on func %v that has not been fully processed", f) 566 } 567 state := &f.Cache.debugState 568 state.loggingLevel = loggingLevel % 1000 569 570 // A specific number demands exactly that many iterations. Under 571 // particular circumstances it make require more than the total of 572 // 2 passes implied by a single run through liveness and a single 573 // run through location list generation. 574 state.convergeCount = loggingLevel / 1000 575 state.f = f 576 state.registers = f.Config.registers 577 state.stackOffset = stackOffset 578 state.ctxt = ctxt 579 580 if buildcfg.Experiment.RegabiArgs { 581 PopulateABIInRegArgOps(f) 582 } 583 584 if state.loggingLevel > 0 { 585 state.logf("Generating location lists for function %q\n", f.Name) 586 } 587 588 if state.varParts == nil { 589 state.varParts = make(map[*ir.Name][]SlotID) 590 } else { 591 for n := range state.varParts { 592 delete(state.varParts, n) 593 } 594 } 595 596 // Recompose any decomposed variables, and establish the canonical 597 // IDs for each var and slot by filling out state.vars and state.slots. 598 599 state.slots = state.slots[:0] 600 state.vars = state.vars[:0] 601 for i, slot := range f.Names { 602 state.slots = append(state.slots, *slot) 603 if ir.IsSynthetic(slot.N) { 604 continue 605 } 606 607 topSlot := slot 608 for topSlot.SplitOf != nil { 609 topSlot = topSlot.SplitOf 610 } 611 if _, ok := state.varParts[topSlot.N]; !ok { 612 state.vars = append(state.vars, topSlot.N) 613 } 614 state.varParts[topSlot.N] = append(state.varParts[topSlot.N], SlotID(i)) 615 } 616 617 // Recreate the LocalSlot for each stack-only variable. 618 // This would probably be better as an output from stackframe. 619 for _, b := range f.Blocks { 620 for _, v := range b.Values { 621 if v.Op == OpVarDef { 622 n := v.Aux.(*ir.Name) 623 if ir.IsSynthetic(n) { 624 continue 625 } 626 627 if _, ok := state.varParts[n]; !ok { 628 slot := LocalSlot{N: n, Type: v.Type, Off: 0} 629 state.slots = append(state.slots, slot) 630 state.varParts[n] = []SlotID{SlotID(len(state.slots) - 1)} 631 state.vars = append(state.vars, n) 632 } 633 } 634 } 635 } 636 637 // Fill in the var<->slot mappings. 638 if cap(state.varSlots) < len(state.vars) { 639 state.varSlots = make([][]SlotID, len(state.vars)) 640 } else { 641 state.varSlots = state.varSlots[:len(state.vars)] 642 for i := range state.varSlots { 643 state.varSlots[i] = state.varSlots[i][:0] 644 } 645 } 646 if cap(state.slotVars) < len(state.slots) { 647 state.slotVars = make([]VarID, len(state.slots)) 648 } else { 649 state.slotVars = state.slotVars[:len(state.slots)] 650 } 651 652 if state.partsByVarOffset == nil { 653 state.partsByVarOffset = &partsByVarOffset{} 654 } 655 for varID, n := range state.vars { 656 parts := state.varParts[n] 657 state.varSlots[varID] = parts 658 for _, slotID := range parts { 659 state.slotVars[slotID] = VarID(varID) 660 } 661 *state.partsByVarOffset.(*partsByVarOffset) = partsByVarOffset{parts, state.slots} 662 sort.Sort(state.partsByVarOffset) 663 } 664 665 state.initializeCache(f, len(state.varParts), len(state.slots)) 666 667 for i, slot := range f.Names { 668 if ir.IsSynthetic(slot.N) { 669 continue 670 } 671 for _, value := range f.NamedValues[*slot] { 672 state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i)) 673 } 674 } 675 676 blockLocs := state.liveness() 677 state.buildLocationLists(blockLocs) 678 679 // Populate "rval" with what we've computed. 680 rval.Slots = state.slots 681 rval.VarSlots = state.varSlots 682 rval.Vars = state.vars 683 rval.LocationLists = state.lists 684 } 685 686 // liveness walks the function in control flow order, calculating the start 687 // and end state of each block. 688 func (state *debugState) liveness() []*BlockDebug { 689 blockLocs := make([]*BlockDebug, state.f.NumBlocks()) 690 counterTime := int32(1) 691 692 // Reverse postorder: visit a block after as many as possible of its 693 // predecessors have been visited. 694 po := state.f.Postorder() 695 converged := false 696 697 // The iteration rule is that by default, run until converged, but 698 // if a particular iteration count is specified, run that many 699 // iterations, no more, no less. A count is specified as the 700 // thousands digit of the location lists debug flag, 701 // e.g. -d=locationlists=4000 702 keepGoing := func(k int) bool { 703 if state.convergeCount == 0 { 704 return !converged 705 } 706 return k < state.convergeCount 707 } 708 for k := 0; keepGoing(k); k++ { 709 if state.loggingLevel > 0 { 710 state.logf("Liveness pass %d\n", k) 711 } 712 converged = true 713 for i := len(po) - 1; i >= 0; i-- { 714 b := po[i] 715 locs := blockLocs[b.ID] 716 if locs == nil { 717 locs = state.allocBlock(b) 718 blockLocs[b.ID] = locs 719 } 720 721 // Build the starting state for the block from the final 722 // state of its predecessors. 723 startState, blockChanged := state.mergePredecessors(b, blockLocs, nil, false) 724 locs.lastCheckedTime = counterTime 725 counterTime++ 726 if state.loggingLevel > 1 { 727 state.logf("Processing %v, block changed %v, initial state:\n%v", b, blockChanged, state.stateString(state.currentState)) 728 } 729 730 if blockChanged { 731 // If the start did not change, then the old endState is good 732 converged = false 733 changed := false 734 state.changedSlots.clear() 735 736 // Update locs/registers with the effects of each Value. 737 for _, v := range b.Values { 738 slots := state.valueNames[v.ID] 739 740 // Loads and stores inherit the names of their sources. 741 var source *Value 742 switch v.Op { 743 case OpStoreReg: 744 source = v.Args[0] 745 case OpLoadReg: 746 switch a := v.Args[0]; a.Op { 747 case OpArg, OpPhi: 748 source = a 749 case OpStoreReg: 750 source = a.Args[0] 751 default: 752 if state.loggingLevel > 1 { 753 state.logf("at %v: load with unexpected source op: %v (%v)\n", v, a.Op, a) 754 } 755 } 756 } 757 // Update valueNames with the source so that later steps 758 // don't need special handling. 759 if source != nil && k == 0 { 760 // limit to k == 0 otherwise there are duplicates. 761 slots = append(slots, state.valueNames[source.ID]...) 762 state.valueNames[v.ID] = slots 763 } 764 765 reg, _ := state.f.getHome(v.ID).(*Register) 766 c := state.processValue(v, slots, reg) 767 changed = changed || c 768 } 769 770 if state.loggingLevel > 1 { 771 state.logf("Block %v done, locs:\n%v", b, state.stateString(state.currentState)) 772 } 773 774 locs.relevant = locs.relevant || changed 775 if !changed { 776 locs.endState = startState 777 } else { 778 for _, id := range state.changedSlots.contents() { 779 slotID := SlotID(id) 780 slotLoc := state.currentState.slots[slotID] 781 if slotLoc.absent() { 782 startState.Delete(int32(slotID)) 783 continue 784 } 785 old := startState.Find(int32(slotID)) // do NOT replace existing values 786 if oldLS, ok := old.(*liveSlot); !ok || oldLS.VarLoc != slotLoc { 787 startState.Insert(int32(slotID), 788 &liveSlot{VarLoc: slotLoc}) 789 } 790 } 791 locs.endState = startState 792 } 793 locs.lastChangedTime = counterTime 794 } 795 counterTime++ 796 } 797 } 798 return blockLocs 799 } 800 801 // mergePredecessors takes the end state of each of b's predecessors and 802 // intersects them to form the starting state for b. It puts that state 803 // in blockLocs[b.ID].startState, and fills state.currentState with it. 804 // It returns the start state and whether this is changed from the 805 // previously approximated value of startState for this block. After 806 // the first call, subsequent calls can only shrink startState. 807 // 808 // Passing forLocationLists=true enables additional side-effects that 809 // are necessary for building location lists but superfluous while still 810 // iterating to an answer. 811 // 812 // If previousBlock is non-nil, it registers changes vs. that block's 813 // end state in state.changedVars. Note that previousBlock will often 814 // not be a predecessor. 815 // 816 // Note that mergePredecessors behaves slightly differently between 817 // first and subsequent calls for a block. For the first call, the 818 // starting state is approximated by taking the state from the 819 // predecessor whose state is smallest, and removing any elements not 820 // in all the other predecessors; this makes the smallest number of 821 // changes and shares the most state. On subsequent calls the old 822 // value of startState is adjusted with new information; this is judged 823 // to do the least amount of extra work. 824 // 825 // To improve performance, each block's state information is marked with 826 // lastChanged and lastChecked "times" so unchanged predecessors can be 827 // skipped on after-the-first iterations. Doing this allows extra 828 // iterations by the caller to be almost free. 829 // 830 // It is important to know that the set representation used for 831 // startState, endState, and merges can share data for two sets where 832 // one is a small delta from the other. Doing this does require a 833 // little care in how sets are updated, both in mergePredecessors, and 834 // using its result. 835 func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug, previousBlock *Block, forLocationLists bool) (abt.T, bool) { 836 // Filter out back branches. 837 var predsBuf [10]*Block 838 839 preds := predsBuf[:0] 840 locs := blockLocs[b.ID] 841 842 blockChanged := !locs.everProcessed // the first time it always changes. 843 updating := locs.everProcessed 844 845 // For the first merge, exclude predecessors that have not been seen yet. 846 // I.e., backedges. 847 for _, pred := range b.Preds { 848 if bl := blockLocs[pred.b.ID]; bl != nil && bl.everProcessed { 849 // crucially, a self-edge has bl != nil, but bl.everProcessed is false the first time. 850 preds = append(preds, pred.b) 851 } 852 } 853 854 locs.everProcessed = true 855 856 if state.loggingLevel > 1 { 857 // The logf below would cause preds to be heap-allocated if 858 // it were passed directly. 859 preds2 := make([]*Block, len(preds)) 860 copy(preds2, preds) 861 state.logf("Merging %v into %v (changed=%d, checked=%d)\n", preds2, b, locs.lastChangedTime, locs.lastCheckedTime) 862 } 863 864 state.changedVars.clear() 865 866 markChangedVars := func(slots, merged abt.T) { 867 if !forLocationLists { 868 return 869 } 870 // Fill changedVars with those that differ between the previous 871 // block (in the emit order, not necessarily a flow predecessor) 872 // and the start state for this block. 873 for it := slots.Iterator(); !it.Done(); { 874 k, v := it.Next() 875 m := merged.Find(k) 876 if m == nil || v.(*liveSlot).VarLoc != m.(*liveSlot).VarLoc { 877 state.changedVars.add(ID(state.slotVars[k])) 878 } 879 } 880 } 881 882 reset := func(ourStartState abt.T) { 883 if !(forLocationLists || blockChanged) { 884 // there is no change and this is not for location lists, do 885 // not bother to reset currentState because it will not be 886 // examined. 887 return 888 } 889 state.currentState.reset(ourStartState) 890 } 891 892 // Zero predecessors 893 if len(preds) == 0 { 894 if previousBlock != nil { 895 state.f.Fatalf("Function %v, block %s with no predecessors is not first block, has previous %s", state.f, b.String(), previousBlock.String()) 896 } 897 // startState is empty 898 reset(abt.T{}) 899 return abt.T{}, blockChanged 900 } 901 902 // One predecessor 903 l0 := blockLocs[preds[0].ID] 904 p0 := l0.endState 905 if len(preds) == 1 { 906 if previousBlock != nil && preds[0].ID != previousBlock.ID { 907 // Change from previous block is its endState minus the predecessor's endState 908 markChangedVars(blockLocs[previousBlock.ID].endState, p0) 909 } 910 locs.startState = p0 911 blockChanged = blockChanged || l0.lastChangedTime > locs.lastCheckedTime 912 reset(p0) 913 return p0, blockChanged 914 } 915 916 // More than one predecessor 917 918 if updating { 919 // After the first approximation, i.e., when updating, results 920 // can only get smaller, because initially backedge 921 // predecessors do not participate in the intersection. This 922 // means that for the update, given the prior approximation of 923 // startState, there is no need to re-intersect with unchanged 924 // blocks. Therefore remove unchanged blocks from the 925 // predecessor list. 926 for i := len(preds) - 1; i >= 0; i-- { 927 pred := preds[i] 928 if blockLocs[pred.ID].lastChangedTime > locs.lastCheckedTime { 929 continue // keep this predecessor 930 } 931 preds[i] = preds[len(preds)-1] 932 preds = preds[:len(preds)-1] 933 if state.loggingLevel > 2 { 934 state.logf("Pruned b%d, lastChanged was %d but b%d lastChecked is %d\n", pred.ID, blockLocs[pred.ID].lastChangedTime, b.ID, locs.lastCheckedTime) 935 } 936 } 937 // Check for an early out; this should always hit for the update 938 // if there are no cycles. 939 if len(preds) == 0 { 940 blockChanged = false 941 942 reset(locs.startState) 943 if state.loggingLevel > 2 { 944 state.logf("Early out, no predecessors changed since last check\n") 945 } 946 if previousBlock != nil { 947 markChangedVars(blockLocs[previousBlock.ID].endState, locs.startState) 948 } 949 return locs.startState, blockChanged 950 } 951 } 952 953 baseID := preds[0].ID 954 baseState := p0 955 956 // Choose the predecessor with the smallest endState for intersection work 957 for _, pred := range preds[1:] { 958 if blockLocs[pred.ID].endState.Size() < baseState.Size() { 959 baseState = blockLocs[pred.ID].endState 960 baseID = pred.ID 961 } 962 } 963 964 if state.loggingLevel > 2 { 965 state.logf("Starting %v with state from b%v:\n%v", b, baseID, state.blockEndStateString(blockLocs[baseID])) 966 for _, pred := range preds { 967 if pred.ID == baseID { 968 continue 969 } 970 state.logf("Merging in state from %v:\n%v", pred, state.blockEndStateString(blockLocs[pred.ID])) 971 } 972 } 973 974 state.currentState.reset(abt.T{}) 975 // The normal logic of "reset" is included in the intersection loop below. 976 977 slotLocs := state.currentState.slots 978 979 // If this is the first call, do updates on the "baseState"; if this 980 // is a subsequent call, tweak the startState instead. Note that 981 // these "set" values are values; there are no side effects to 982 // other values as these are modified. 983 newState := baseState 984 if updating { 985 newState = blockLocs[b.ID].startState 986 } 987 988 for it := newState.Iterator(); !it.Done(); { 989 k, d := it.Next() 990 thisSlot := d.(*liveSlot) 991 x := thisSlot.VarLoc 992 x0 := x // initial value in newState 993 994 // Intersect this slot with the slot in all the predecessors 995 for _, other := range preds { 996 if !updating && other.ID == baseID { 997 continue 998 } 999 otherSlot := blockLocs[other.ID].endState.Find(k) 1000 if otherSlot == nil { 1001 x = VarLoc{} 1002 break 1003 } 1004 y := otherSlot.(*liveSlot).VarLoc 1005 x = x.intersect(y) 1006 if x.absent() { 1007 x = VarLoc{} 1008 break 1009 } 1010 } 1011 1012 // Delete if necessary, but not otherwise (in order to maximize sharing). 1013 if x.absent() { 1014 if !x0.absent() { 1015 blockChanged = true 1016 newState.Delete(k) 1017 } 1018 slotLocs[k] = VarLoc{} 1019 continue 1020 } 1021 if x != x0 { 1022 blockChanged = true 1023 newState.Insert(k, &liveSlot{VarLoc: x}) 1024 } 1025 1026 slotLocs[k] = x 1027 mask := uint64(x.Registers) 1028 for { 1029 if mask == 0 { 1030 break 1031 } 1032 reg := uint8(bits.TrailingZeros64(mask)) 1033 mask &^= 1 << reg 1034 state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(k)) 1035 } 1036 } 1037 1038 if previousBlock != nil { 1039 markChangedVars(blockLocs[previousBlock.ID].endState, newState) 1040 } 1041 locs.startState = newState 1042 return newState, blockChanged 1043 } 1044 1045 // processValue updates locs and state.registerContents to reflect v, a 1046 // value with the names in vSlots and homed in vReg. "v" becomes 1047 // visible after execution of the instructions evaluating it. It 1048 // returns which VarIDs were modified by the Value's execution. 1049 func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register) bool { 1050 locs := state.currentState 1051 changed := false 1052 setSlot := func(slot SlotID, loc VarLoc) { 1053 changed = true 1054 state.changedVars.add(ID(state.slotVars[slot])) 1055 state.changedSlots.add(ID(slot)) 1056 state.currentState.slots[slot] = loc 1057 } 1058 1059 // Handle any register clobbering. Call operations, for example, 1060 // clobber all registers even though they don't explicitly write to 1061 // them. 1062 clobbers := uint64(opcodeTable[v.Op].reg.clobbers) 1063 for { 1064 if clobbers == 0 { 1065 break 1066 } 1067 reg := uint8(bits.TrailingZeros64(clobbers)) 1068 clobbers &^= 1 << reg 1069 1070 for _, slot := range locs.registers[reg] { 1071 if state.loggingLevel > 1 { 1072 state.logf("at %v: %v clobbered out of %v\n", v, state.slots[slot], &state.registers[reg]) 1073 } 1074 1075 last := locs.slots[slot] 1076 if last.absent() { 1077 state.f.Fatalf("at %v: slot %v in register %v with no location entry", v, state.slots[slot], &state.registers[reg]) 1078 continue 1079 } 1080 regs := last.Registers &^ (1 << reg) 1081 setSlot(slot, VarLoc{regs, last.StackOffset}) 1082 } 1083 1084 locs.registers[reg] = locs.registers[reg][:0] 1085 } 1086 1087 switch { 1088 case v.Op == OpVarDef: 1089 n := v.Aux.(*ir.Name) 1090 if ir.IsSynthetic(n) { 1091 break 1092 } 1093 1094 slotID := state.varParts[n][0] 1095 var stackOffset StackOffset 1096 if v.Op == OpVarDef { 1097 stackOffset = StackOffset(state.stackOffset(state.slots[slotID])<<1 | 1) 1098 } 1099 setSlot(slotID, VarLoc{0, stackOffset}) 1100 if state.loggingLevel > 1 { 1101 if v.Op == OpVarDef { 1102 state.logf("at %v: stack-only var %v now live\n", v, state.slots[slotID]) 1103 } else { 1104 state.logf("at %v: stack-only var %v now dead\n", v, state.slots[slotID]) 1105 } 1106 } 1107 1108 case v.Op == OpArg: 1109 home := state.f.getHome(v.ID).(LocalSlot) 1110 stackOffset := state.stackOffset(home)<<1 | 1 1111 for _, slot := range vSlots { 1112 if state.loggingLevel > 1 { 1113 state.logf("at %v: arg %v now on stack in location %v\n", v, state.slots[slot], home) 1114 if last := locs.slots[slot]; !last.absent() { 1115 state.logf("at %v: unexpected arg op on already-live slot %v\n", v, state.slots[slot]) 1116 } 1117 } 1118 1119 setSlot(slot, VarLoc{0, StackOffset(stackOffset)}) 1120 } 1121 1122 case v.Op == OpStoreReg: 1123 home := state.f.getHome(v.ID).(LocalSlot) 1124 stackOffset := state.stackOffset(home)<<1 | 1 1125 for _, slot := range vSlots { 1126 last := locs.slots[slot] 1127 if last.absent() { 1128 if state.loggingLevel > 1 { 1129 state.logf("at %v: unexpected spill of unnamed register %s\n", v, vReg) 1130 } 1131 break 1132 } 1133 1134 setSlot(slot, VarLoc{last.Registers, StackOffset(stackOffset)}) 1135 if state.loggingLevel > 1 { 1136 state.logf("at %v: %v spilled to stack location %v@%d\n", v, state.slots[slot], home, state.stackOffset(home)) 1137 } 1138 } 1139 1140 case vReg != nil: 1141 if state.loggingLevel > 1 { 1142 newSlots := make([]bool, len(state.slots)) 1143 for _, slot := range vSlots { 1144 newSlots[slot] = true 1145 } 1146 1147 for _, slot := range locs.registers[vReg.num] { 1148 if !newSlots[slot] { 1149 state.logf("at %v: overwrote %v in register %v\n", v, state.slots[slot], vReg) 1150 } 1151 } 1152 } 1153 1154 for _, slot := range locs.registers[vReg.num] { 1155 last := locs.slots[slot] 1156 setSlot(slot, VarLoc{last.Registers &^ (1 << uint8(vReg.num)), last.StackOffset}) 1157 } 1158 locs.registers[vReg.num] = locs.registers[vReg.num][:0] 1159 locs.registers[vReg.num] = append(locs.registers[vReg.num], vSlots...) 1160 for _, slot := range vSlots { 1161 if state.loggingLevel > 1 { 1162 state.logf("at %v: %v now in %s\n", v, state.slots[slot], vReg) 1163 } 1164 1165 last := locs.slots[slot] 1166 setSlot(slot, VarLoc{1<<uint8(vReg.num) | last.Registers, last.StackOffset}) 1167 } 1168 } 1169 return changed 1170 } 1171 1172 // varOffset returns the offset of slot within the user variable it was 1173 // decomposed from. This has nothing to do with its stack offset. 1174 func varOffset(slot LocalSlot) int64 { 1175 offset := slot.Off 1176 s := &slot 1177 for ; s.SplitOf != nil; s = s.SplitOf { 1178 offset += s.SplitOffset 1179 } 1180 return offset 1181 } 1182 1183 type partsByVarOffset struct { 1184 slotIDs []SlotID 1185 slots []LocalSlot 1186 } 1187 1188 func (a partsByVarOffset) Len() int { return len(a.slotIDs) } 1189 func (a partsByVarOffset) Less(i, j int) bool { 1190 return varOffset(a.slots[a.slotIDs[i]]) < varOffset(a.slots[a.slotIDs[j]]) 1191 } 1192 func (a partsByVarOffset) Swap(i, j int) { a.slotIDs[i], a.slotIDs[j] = a.slotIDs[j], a.slotIDs[i] } 1193 1194 // A pendingEntry represents the beginning of a location list entry, missing 1195 // only its end coordinate. 1196 type pendingEntry struct { 1197 present bool 1198 startBlock, startValue ID 1199 // The location of each piece of the variable, in the same order as the 1200 // SlotIDs in varParts. 1201 pieces []VarLoc 1202 } 1203 1204 func (e *pendingEntry) clear() { 1205 e.present = false 1206 e.startBlock = 0 1207 e.startValue = 0 1208 for i := range e.pieces { 1209 e.pieces[i] = VarLoc{} 1210 } 1211 } 1212 1213 // canMerge reports whether a new location description is a superset 1214 // of the (non-empty) pending location description, if so, the two 1215 // can be merged (i.e., pending is still a valid and useful location 1216 // description). 1217 func canMerge(pending, new VarLoc) bool { 1218 if pending.absent() && new.absent() { 1219 return true 1220 } 1221 if pending.absent() || new.absent() { 1222 return false 1223 } 1224 // pending is not absent, therefore it has either a stack mapping, 1225 // or registers, or both. 1226 if pending.onStack() && pending.StackOffset != new.StackOffset { 1227 // if pending has a stack offset, then new must also, and it 1228 // must be the same (StackOffset encodes onStack). 1229 return false 1230 } 1231 if pending.Registers&new.Registers != pending.Registers { 1232 // There is at least one register in pending not mentioned in new. 1233 return false 1234 } 1235 return true 1236 } 1237 1238 // firstReg returns the first register in set that is present. 1239 func firstReg(set RegisterSet) uint8 { 1240 if set == 0 { 1241 // This is wrong, but there seem to be some situations where we 1242 // produce locations with no storage. 1243 return 0 1244 } 1245 return uint8(bits.TrailingZeros64(uint64(set))) 1246 } 1247 1248 // buildLocationLists builds location lists for all the user variables 1249 // in state.f, using the information about block state in blockLocs. 1250 // The returned location lists are not fully complete. They are in 1251 // terms of SSA values rather than PCs, and have no base address/end 1252 // entries. They will be finished by PutLocationList. 1253 func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) { 1254 // Run through the function in program text order, building up location 1255 // lists as we go. The heavy lifting has mostly already been done. 1256 1257 var prevBlock *Block 1258 for _, b := range state.f.Blocks { 1259 state.mergePredecessors(b, blockLocs, prevBlock, true) 1260 1261 // Handle any differences among predecessor blocks and previous block (perhaps not a predecessor) 1262 for _, varID := range state.changedVars.contents() { 1263 state.updateVar(VarID(varID), b, BlockStart) 1264 } 1265 state.changedVars.clear() 1266 1267 if !blockLocs[b.ID].relevant { 1268 continue 1269 } 1270 1271 mustBeFirst := func(v *Value) bool { 1272 return v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() || 1273 v.Op == OpArgIntReg || v.Op == OpArgFloatReg 1274 } 1275 1276 blockPrologComplete := func(v *Value) bool { 1277 if b.ID != state.f.Entry.ID { 1278 return !opcodeTable[v.Op].zeroWidth 1279 } else { 1280 return v.Op == OpInitMem 1281 } 1282 } 1283 1284 // Examine the prolog portion of the block to process special 1285 // zero-width ops such as Arg, Phi, LoweredGetClosurePtr (etc) 1286 // whose lifetimes begin at the block starting point. In an 1287 // entry block, allow for the possibility that we may see Arg 1288 // ops that appear _after_ other non-zero-width operations. 1289 // Example: 1290 // 1291 // v33 = ArgIntReg <uintptr> {foo+0} [0] : AX (foo) 1292 // v34 = ArgIntReg <uintptr> {bar+0} [0] : BX (bar) 1293 // ... 1294 // v77 = StoreReg <unsafe.Pointer> v67 : ctx+8[unsafe.Pointer] 1295 // v78 = StoreReg <unsafe.Pointer> v68 : ctx[unsafe.Pointer] 1296 // v79 = Arg <*uint8> {args} : args[*uint8] (args[*uint8]) 1297 // v80 = Arg <int> {args} [8] : args+8[int] (args+8[int]) 1298 // ... 1299 // v1 = InitMem <mem> 1300 // 1301 // We can stop scanning the initial portion of the block when 1302 // we either see the InitMem op (for entry blocks) or the 1303 // first non-zero-width op (for other blocks). 1304 for idx := 0; idx < len(b.Values); idx++ { 1305 v := b.Values[idx] 1306 if blockPrologComplete(v) { 1307 break 1308 } 1309 // Consider only "lifetime begins at block start" ops. 1310 if !mustBeFirst(v) && v.Op != OpArg { 1311 continue 1312 } 1313 slots := state.valueNames[v.ID] 1314 reg, _ := state.f.getHome(v.ID).(*Register) 1315 changed := state.processValue(v, slots, reg) // changed == added to state.changedVars 1316 if changed { 1317 for _, varID := range state.changedVars.contents() { 1318 state.updateVar(VarID(varID), v.Block, BlockStart) 1319 } 1320 state.changedVars.clear() 1321 } 1322 } 1323 1324 // Now examine the block again, handling things other than the 1325 // "begins at block start" lifetimes. 1326 zeroWidthPending := false 1327 prologComplete := false 1328 // expect to see values in pattern (apc)* (zerowidth|real)* 1329 for _, v := range b.Values { 1330 if blockPrologComplete(v) { 1331 prologComplete = true 1332 } 1333 slots := state.valueNames[v.ID] 1334 reg, _ := state.f.getHome(v.ID).(*Register) 1335 changed := state.processValue(v, slots, reg) // changed == added to state.changedVars 1336 1337 if opcodeTable[v.Op].zeroWidth { 1338 if prologComplete && mustBeFirst(v) { 1339 panic(fmt.Errorf("Unexpected placement of op '%s' appearing after non-pseudo-op at beginning of block %s in %s\n%s", v.LongString(), b, b.Func.Name, b.Func)) 1340 } 1341 if changed { 1342 if mustBeFirst(v) || v.Op == OpArg { 1343 // already taken care of above 1344 continue 1345 } 1346 zeroWidthPending = true 1347 } 1348 continue 1349 } 1350 if !changed && !zeroWidthPending { 1351 continue 1352 } 1353 1354 // Not zero-width; i.e., a "real" instruction. 1355 zeroWidthPending = false 1356 for _, varID := range state.changedVars.contents() { 1357 state.updateVar(VarID(varID), v.Block, v) 1358 } 1359 state.changedVars.clear() 1360 } 1361 for _, varID := range state.changedVars.contents() { 1362 state.updateVar(VarID(varID), b, BlockEnd) 1363 } 1364 1365 prevBlock = b 1366 } 1367 1368 if state.loggingLevel > 0 { 1369 state.logf("location lists:\n") 1370 } 1371 1372 // Flush any leftover entries live at the end of the last block. 1373 for varID := range state.lists { 1374 state.writePendingEntry(VarID(varID), -1, FuncEnd.ID) 1375 list := state.lists[varID] 1376 if state.loggingLevel > 0 { 1377 if len(list) == 0 { 1378 state.logf("\t%v : empty list\n", state.vars[varID]) 1379 } else { 1380 state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(state.lists[varID])) 1381 } 1382 } 1383 } 1384 } 1385 1386 // updateVar updates the pending location list entry for varID to 1387 // reflect the new locations in curLoc, beginning at v in block b. 1388 // v may be one of the special values indicating block start or end. 1389 func (state *debugState) updateVar(varID VarID, b *Block, v *Value) { 1390 curLoc := state.currentState.slots 1391 // Assemble the location list entry with whatever's live. 1392 empty := true 1393 for _, slotID := range state.varSlots[varID] { 1394 if !curLoc[slotID].absent() { 1395 empty = false 1396 break 1397 } 1398 } 1399 pending := &state.pendingEntries[varID] 1400 if empty { 1401 state.writePendingEntry(varID, b.ID, v.ID) 1402 pending.clear() 1403 return 1404 } 1405 1406 // Extend the previous entry if possible. 1407 if pending.present { 1408 merge := true 1409 for i, slotID := range state.varSlots[varID] { 1410 if !canMerge(pending.pieces[i], curLoc[slotID]) { 1411 merge = false 1412 break 1413 } 1414 } 1415 if merge { 1416 return 1417 } 1418 } 1419 1420 state.writePendingEntry(varID, b.ID, v.ID) 1421 pending.present = true 1422 pending.startBlock = b.ID 1423 pending.startValue = v.ID 1424 for i, slot := range state.varSlots[varID] { 1425 pending.pieces[i] = curLoc[slot] 1426 } 1427 } 1428 1429 // writePendingEntry writes out the pending entry for varID, if any, 1430 // terminated at endBlock/Value. 1431 func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) { 1432 pending := state.pendingEntries[varID] 1433 if !pending.present { 1434 return 1435 } 1436 1437 // Pack the start/end coordinates into the start/end addresses 1438 // of the entry, for decoding by PutLocationList. 1439 start, startOK := encodeValue(state.ctxt, pending.startBlock, pending.startValue) 1440 end, endOK := encodeValue(state.ctxt, endBlock, endValue) 1441 if !startOK || !endOK { 1442 // If someone writes a function that uses >65K values, 1443 // they get incomplete debug info on 32-bit platforms. 1444 return 1445 } 1446 if start == end { 1447 if state.loggingLevel > 1 { 1448 // Printf not logf so not gated by GOSSAFUNC; this should fire very rarely. 1449 // TODO this fires a lot, need to figure out why. 1450 state.logf("Skipping empty location list for %v in %s\n", state.vars[varID], state.f.Name) 1451 } 1452 return 1453 } 1454 1455 list := state.lists[varID] 1456 list = appendPtr(state.ctxt, list, start) 1457 list = appendPtr(state.ctxt, list, end) 1458 // Where to write the length of the location description once 1459 // we know how big it is. 1460 sizeIdx := len(list) 1461 list = list[:len(list)+2] 1462 1463 if state.loggingLevel > 1 { 1464 var partStrs []string 1465 for i, slot := range state.varSlots[varID] { 1466 partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i]))) 1467 } 1468 state.logf("Add entry for %v: \tb%vv%v-b%vv%v = \t%v\n", state.vars[varID], pending.startBlock, pending.startValue, endBlock, endValue, strings.Join(partStrs, " ")) 1469 } 1470 1471 for i, slotID := range state.varSlots[varID] { 1472 loc := pending.pieces[i] 1473 slot := state.slots[slotID] 1474 1475 if !loc.absent() { 1476 if loc.onStack() { 1477 if loc.stackOffsetValue() == 0 { 1478 list = append(list, dwarf.DW_OP_call_frame_cfa) 1479 } else { 1480 list = append(list, dwarf.DW_OP_fbreg) 1481 list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue())) 1482 } 1483 } else { 1484 regnum := state.ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()] 1485 if regnum < 32 { 1486 list = append(list, dwarf.DW_OP_reg0+byte(regnum)) 1487 } else { 1488 list = append(list, dwarf.DW_OP_regx) 1489 list = dwarf.AppendUleb128(list, uint64(regnum)) 1490 } 1491 } 1492 } 1493 1494 if len(state.varSlots[varID]) > 1 { 1495 list = append(list, dwarf.DW_OP_piece) 1496 list = dwarf.AppendUleb128(list, uint64(slot.Type.Size())) 1497 } 1498 } 1499 state.ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2)) 1500 state.lists[varID] = list 1501 } 1502 1503 // PutLocationList adds list (a location list in its intermediate representation) to listSym. 1504 func (debugInfo *FuncDebug) PutLocationList(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) { 1505 getPC := debugInfo.GetPC 1506 1507 if ctxt.UseBASEntries { 1508 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, ^0) 1509 listSym.WriteAddr(ctxt, listSym.Size, ctxt.Arch.PtrSize, startPC, 0) 1510 } 1511 1512 // Re-read list, translating its address from block/value ID to PC. 1513 for i := 0; i < len(list); { 1514 begin := getPC(decodeValue(ctxt, readPtr(ctxt, list[i:]))) 1515 end := getPC(decodeValue(ctxt, readPtr(ctxt, list[i+ctxt.Arch.PtrSize:]))) 1516 1517 // Horrible hack. If a range contains only zero-width 1518 // instructions, e.g. an Arg, and it's at the beginning of the 1519 // function, this would be indistinguishable from an 1520 // end entry. Fudge it. 1521 if begin == 0 && end == 0 { 1522 end = 1 1523 } 1524 1525 if ctxt.UseBASEntries { 1526 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, int64(begin)) 1527 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, int64(end)) 1528 } else { 1529 listSym.WriteCURelativeAddr(ctxt, listSym.Size, startPC, int64(begin)) 1530 listSym.WriteCURelativeAddr(ctxt, listSym.Size, startPC, int64(end)) 1531 } 1532 1533 i += 2 * ctxt.Arch.PtrSize 1534 datalen := 2 + int(ctxt.Arch.ByteOrder.Uint16(list[i:])) 1535 listSym.WriteBytes(ctxt, listSym.Size, list[i:i+datalen]) // copy datalen and location encoding 1536 i += datalen 1537 } 1538 1539 // Location list contents, now with real PCs. 1540 // End entry. 1541 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0) 1542 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0) 1543 } 1544 1545 // Pack a value and block ID into an address-sized uint, returning 1546 // encoded value and boolean indicating whether the encoding succeeded. 1547 // For 32-bit architectures the process may fail for very large 1548 // procedures(the theory being that it's ok to have degraded debug 1549 // quality in this case). 1550 func encodeValue(ctxt *obj.Link, b, v ID) (uint64, bool) { 1551 if ctxt.Arch.PtrSize == 8 { 1552 result := uint64(b)<<32 | uint64(uint32(v)) 1553 //ctxt.Logf("b %#x (%d) v %#x (%d) -> %#x\n", b, b, v, v, result) 1554 return result, true 1555 } 1556 if ctxt.Arch.PtrSize != 4 { 1557 panic("unexpected pointer size") 1558 } 1559 if ID(int16(b)) != b || ID(int16(v)) != v { 1560 return 0, false 1561 } 1562 return uint64(b)<<16 | uint64(uint16(v)), true 1563 } 1564 1565 // Unpack a value and block ID encoded by encodeValue. 1566 func decodeValue(ctxt *obj.Link, word uint64) (ID, ID) { 1567 if ctxt.Arch.PtrSize == 8 { 1568 b, v := ID(word>>32), ID(word) 1569 //ctxt.Logf("%#x -> b %#x (%d) v %#x (%d)\n", word, b, b, v, v) 1570 return b, v 1571 } 1572 if ctxt.Arch.PtrSize != 4 { 1573 panic("unexpected pointer size") 1574 } 1575 return ID(word >> 16), ID(int16(word)) 1576 } 1577 1578 // Append a pointer-sized uint to buf. 1579 func appendPtr(ctxt *obj.Link, buf []byte, word uint64) []byte { 1580 if cap(buf) < len(buf)+20 { 1581 b := make([]byte, len(buf), 20+cap(buf)*2) 1582 copy(b, buf) 1583 buf = b 1584 } 1585 writeAt := len(buf) 1586 buf = buf[0 : len(buf)+ctxt.Arch.PtrSize] 1587 writePtr(ctxt, buf[writeAt:], word) 1588 return buf 1589 } 1590 1591 // Write a pointer-sized uint to the beginning of buf. 1592 func writePtr(ctxt *obj.Link, buf []byte, word uint64) { 1593 switch ctxt.Arch.PtrSize { 1594 case 4: 1595 ctxt.Arch.ByteOrder.PutUint32(buf, uint32(word)) 1596 case 8: 1597 ctxt.Arch.ByteOrder.PutUint64(buf, word) 1598 default: 1599 panic("unexpected pointer size") 1600 } 1601 1602 } 1603 1604 // Read a pointer-sized uint from the beginning of buf. 1605 func readPtr(ctxt *obj.Link, buf []byte) uint64 { 1606 switch ctxt.Arch.PtrSize { 1607 case 4: 1608 return uint64(ctxt.Arch.ByteOrder.Uint32(buf)) 1609 case 8: 1610 return ctxt.Arch.ByteOrder.Uint64(buf) 1611 default: 1612 panic("unexpected pointer size") 1613 } 1614 1615 } 1616 1617 // setupLocList creates the initial portion of a location list for a 1618 // user variable. It emits the encoded start/end of the range and a 1619 // placeholder for the size. Return value is the new list plus the 1620 // slot in the list holding the size (to be updated later). 1621 func setupLocList(ctxt *obj.Link, f *Func, list []byte, st, en ID) ([]byte, int) { 1622 start, startOK := encodeValue(ctxt, f.Entry.ID, st) 1623 end, endOK := encodeValue(ctxt, f.Entry.ID, en) 1624 if !startOK || !endOK { 1625 // This could happen if someone writes a function that uses 1626 // >65K values on a 32-bit platform. Hopefully a degraded debugging 1627 // experience is ok in that case. 1628 return nil, 0 1629 } 1630 list = appendPtr(ctxt, list, start) 1631 list = appendPtr(ctxt, list, end) 1632 1633 // Where to write the length of the location description once 1634 // we know how big it is. 1635 sizeIdx := len(list) 1636 list = list[:len(list)+2] 1637 return list, sizeIdx 1638 } 1639 1640 // locatePrologEnd walks the entry block of a function with incoming 1641 // register arguments and locates the last instruction in the prolog 1642 // that spills a register arg. It returns the ID of that instruction 1643 // Example: 1644 // 1645 // b1: 1646 // v3 = ArgIntReg <int> {p1+0} [0] : AX 1647 // ... more arg regs .. 1648 // v4 = ArgFloatReg <float32> {f1+0} [0] : X0 1649 // v52 = MOVQstore <mem> {p1} v2 v3 v1 1650 // ... more stores ... 1651 // v68 = MOVSSstore <mem> {f4} v2 v67 v66 1652 // v38 = MOVQstoreconst <mem> {blob} [val=0,off=0] v2 v32 1653 // 1654 // Important: locatePrologEnd is expected to work properly only with 1655 // optimization turned off (e.g. "-N"). If optimization is enabled 1656 // we can't be assured of finding all input arguments spilled in the 1657 // entry block prolog. 1658 func locatePrologEnd(f *Func) ID { 1659 1660 // returns true if this instruction looks like it moves an ABI 1661 // register to the stack, along with the value being stored. 1662 isRegMoveLike := func(v *Value) (bool, ID) { 1663 n, ok := v.Aux.(*ir.Name) 1664 var r ID 1665 if !ok || n.Class != ir.PPARAM { 1666 return false, r 1667 } 1668 regInputs, memInputs, spInputs := 0, 0, 0 1669 for _, a := range v.Args { 1670 if a.Op == OpArgIntReg || a.Op == OpArgFloatReg { 1671 regInputs++ 1672 r = a.ID 1673 } else if a.Type.IsMemory() { 1674 memInputs++ 1675 } else if a.Op == OpSP { 1676 spInputs++ 1677 } else { 1678 return false, r 1679 } 1680 } 1681 return v.Type.IsMemory() && memInputs == 1 && 1682 regInputs == 1 && spInputs == 1, r 1683 } 1684 1685 // OpArg*Reg values we've seen so far on our forward walk, 1686 // for which we have not yet seen a corresponding spill. 1687 regArgs := make([]ID, 0, 32) 1688 1689 // removeReg tries to remove a value from regArgs, returning true 1690 // if found and removed, or false otherwise. 1691 removeReg := func(r ID) bool { 1692 for i := 0; i < len(regArgs); i++ { 1693 if regArgs[i] == r { 1694 regArgs = append(regArgs[:i], regArgs[i+1:]...) 1695 return true 1696 } 1697 } 1698 return false 1699 } 1700 1701 // Walk forwards through the block. When we see OpArg*Reg, record 1702 // the value it produces in the regArgs list. When see a store that uses 1703 // the value, remove the entry. When we hit the last store (use) 1704 // then we've arrived at the end of the prolog. 1705 for k, v := range f.Entry.Values { 1706 if v.Op == OpArgIntReg || v.Op == OpArgFloatReg { 1707 regArgs = append(regArgs, v.ID) 1708 continue 1709 } 1710 if ok, r := isRegMoveLike(v); ok { 1711 if removed := removeReg(r); removed { 1712 if len(regArgs) == 0 { 1713 // Found our last spill; return the value after 1714 // it. Note that it is possible that this spill is 1715 // the last instruction in the block. If so, then 1716 // return the "end of block" sentinel. 1717 if k < len(f.Entry.Values)-1 { 1718 return f.Entry.Values[k+1].ID 1719 } 1720 return BlockEnd.ID 1721 } 1722 } 1723 } 1724 if v.Op.IsCall() { 1725 // if we hit a call, we've gone too far. 1726 return v.ID 1727 } 1728 } 1729 // nothing found 1730 return ID(-1) 1731 } 1732 1733 // isNamedRegParam returns true if the param corresponding to "p" 1734 // is a named, non-blank input parameter assigned to one or more 1735 // registers. 1736 func isNamedRegParam(p abi.ABIParamAssignment) bool { 1737 if p.Name == nil { 1738 return false 1739 } 1740 n := p.Name 1741 if n.Sym() == nil || n.Sym().IsBlank() { 1742 return false 1743 } 1744 if len(p.Registers) == 0 { 1745 return false 1746 } 1747 return true 1748 } 1749 1750 // BuildFuncDebugNoOptimized populates a FuncDebug object "rval" with 1751 // entries corresponding to the register-resident input parameters for 1752 // the function "f"; it is used when we are compiling without 1753 // optimization but the register ABI is enabled. For each reg param, 1754 // it constructs a 2-element location list: the first element holds 1755 // the input register, and the second element holds the stack location 1756 // of the param (the assumption being that when optimization is off, 1757 // each input param reg will be spilled in the prolog). 1758 func BuildFuncDebugNoOptimized(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset func(LocalSlot) int32, rval *FuncDebug) { 1759 1760 pri := f.ABISelf.ABIAnalyzeFuncType(f.Type) 1761 1762 // Look to see if we have any named register-promoted parameters. 1763 // If there are none, bail early and let the caller sort things 1764 // out for the remainder of the params/locals. 1765 numRegParams := 0 1766 for _, inp := range pri.InParams() { 1767 if isNamedRegParam(inp) { 1768 numRegParams++ 1769 } 1770 } 1771 if numRegParams == 0 { 1772 return 1773 } 1774 1775 state := debugState{f: f} 1776 1777 if loggingEnabled { 1778 state.logf("generating -N reg param loc lists for func %q\n", f.Name) 1779 } 1780 1781 // Allocate location lists. 1782 rval.LocationLists = make([][]byte, numRegParams) 1783 1784 // Locate the value corresponding to the last spill of 1785 // an input register. 1786 afterPrologVal := locatePrologEnd(f) 1787 1788 // Walk the input params again and process the register-resident elements. 1789 pidx := 0 1790 for _, inp := range pri.InParams() { 1791 if !isNamedRegParam(inp) { 1792 // will be sorted out elsewhere 1793 continue 1794 } 1795 1796 n := inp.Name 1797 sl := LocalSlot{N: n, Type: inp.Type, Off: 0} 1798 rval.Vars = append(rval.Vars, n) 1799 rval.Slots = append(rval.Slots, sl) 1800 slid := len(rval.VarSlots) 1801 rval.VarSlots = append(rval.VarSlots, []SlotID{SlotID(slid)}) 1802 1803 if afterPrologVal == ID(-1) { 1804 // This can happen for degenerate functions with infinite 1805 // loops such as that in issue 45948. In such cases, leave 1806 // the var/slot set up for the param, but don't try to 1807 // emit a location list. 1808 if loggingEnabled { 1809 state.logf("locatePrologEnd failed, skipping %v\n", n) 1810 } 1811 pidx++ 1812 continue 1813 } 1814 1815 // Param is arriving in one or more registers. We need a 2-element 1816 // location expression for it. First entry in location list 1817 // will correspond to lifetime in input registers. 1818 list, sizeIdx := setupLocList(ctxt, f, rval.LocationLists[pidx], 1819 BlockStart.ID, afterPrologVal) 1820 if list == nil { 1821 pidx++ 1822 continue 1823 } 1824 if loggingEnabled { 1825 state.logf("param %v:\n [<entry>, %d]:\n", n, afterPrologVal) 1826 } 1827 rtypes, _ := inp.RegisterTypesAndOffsets() 1828 padding := make([]uint64, 0, 32) 1829 padding = inp.ComputePadding(padding) 1830 for k, r := range inp.Registers { 1831 reg := ObjRegForAbiReg(r, f.Config) 1832 dwreg := ctxt.Arch.DWARFRegisters[reg] 1833 if dwreg < 32 { 1834 list = append(list, dwarf.DW_OP_reg0+byte(dwreg)) 1835 } else { 1836 list = append(list, dwarf.DW_OP_regx) 1837 list = dwarf.AppendUleb128(list, uint64(dwreg)) 1838 } 1839 if loggingEnabled { 1840 state.logf(" piece %d -> dwreg %d", k, dwreg) 1841 } 1842 if len(inp.Registers) > 1 { 1843 list = append(list, dwarf.DW_OP_piece) 1844 ts := rtypes[k].Size() 1845 list = dwarf.AppendUleb128(list, uint64(ts)) 1846 if padding[k] > 0 { 1847 if loggingEnabled { 1848 state.logf(" [pad %d bytes]", padding[k]) 1849 } 1850 list = append(list, dwarf.DW_OP_piece) 1851 list = dwarf.AppendUleb128(list, padding[k]) 1852 } 1853 } 1854 if loggingEnabled { 1855 state.logf("\n") 1856 } 1857 } 1858 // fill in length of location expression element 1859 ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2)) 1860 1861 // Second entry in the location list will be the stack home 1862 // of the param, once it has been spilled. Emit that now. 1863 list, sizeIdx = setupLocList(ctxt, f, list, 1864 afterPrologVal, FuncEnd.ID) 1865 if list == nil { 1866 pidx++ 1867 continue 1868 } 1869 soff := stackOffset(sl) 1870 if soff == 0 { 1871 list = append(list, dwarf.DW_OP_call_frame_cfa) 1872 } else { 1873 list = append(list, dwarf.DW_OP_fbreg) 1874 list = dwarf.AppendSleb128(list, int64(soff)) 1875 } 1876 if loggingEnabled { 1877 state.logf(" [%d, <end>): stackOffset=%d\n", afterPrologVal, soff) 1878 } 1879 1880 // fill in size 1881 ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2)) 1882 1883 rval.LocationLists[pidx] = list 1884 pidx++ 1885 } 1886 }