github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/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/shogo82148/std/cmd/compile/internal/abt" 9 "github.com/shogo82148/std/cmd/compile/internal/ir" 10 "github.com/shogo82148/std/cmd/internal/obj" 11 ) 12 13 type SlotID int32 14 type VarID int32 15 16 // A FuncDebug contains all the debug information for the variables in a 17 // function. Variables are identified by their LocalSlot, which may be 18 // the result of decomposing a larger variable. 19 type FuncDebug struct { 20 // Slots is all the slots used in the debug info, indexed by their SlotID. 21 Slots []LocalSlot 22 // The user variables, indexed by VarID. 23 Vars []*ir.Name 24 // The slots that make up each variable, indexed by VarID. 25 VarSlots [][]SlotID 26 // The location list data, indexed by VarID. Must be processed by PutLocationList. 27 LocationLists [][]byte 28 // Register-resident output parameters for the function. This is filled in at 29 // SSA generation time. 30 RegOutputParams []*ir.Name 31 // Variable declarations that were removed during optimization 32 OptDcl []*ir.Name 33 34 // Filled in by the user. Translates Block and Value ID to PC. 35 // 36 // NOTE: block is only used if value is BlockStart.ID or BlockEnd.ID. 37 // Otherwise, it is ignored. 38 GetPC func(block, value ID) int64 39 } 40 41 type BlockDebug struct { 42 // State at the start and end of the block. These are initialized, 43 // and updated from new information that flows on back edges. 44 startState, endState abt.T 45 // Use these to avoid excess work in the merge. If none of the 46 // predecessors has changed since the last check, the old answer is 47 // still good. 48 lastCheckedTime, lastChangedTime int32 49 // Whether the block had any changes to user variables at all. 50 relevant bool 51 // false until the block has been processed at least once. This 52 // affects how the merge is done; the goal is to maximize sharing 53 // and avoid allocation. 54 everProcessed bool 55 } 56 57 // StackOffset encodes whether a value is on the stack and if so, where. 58 // It is a 31-bit integer followed by a presence flag at the low-order 59 // bit. 60 type StackOffset int32 61 62 // A VarLoc describes the storage for part of a user variable. 63 type VarLoc struct { 64 // The registers this variable is available in. There can be more than 65 // one in various situations, e.g. it's being moved between registers. 66 Registers RegisterSet 67 68 StackOffset 69 } 70 71 var BlockStart = &Value{ 72 ID: -10000, 73 Op: OpInvalid, 74 Aux: StringToAux("BlockStart"), 75 } 76 77 var BlockEnd = &Value{ 78 ID: -20000, 79 Op: OpInvalid, 80 Aux: StringToAux("BlockEnd"), 81 } 82 83 var FuncEnd = &Value{ 84 ID: -30000, 85 Op: OpInvalid, 86 Aux: StringToAux("FuncEnd"), 87 } 88 89 // RegisterSet is a bitmap of registers, indexed by Register.num. 90 type RegisterSet uint64 91 92 type SlKeyIdx uint32 93 94 // PopulateABIInRegArgOps examines the entry block of the function 95 // and looks for incoming parameters that have missing or partial 96 // OpArg{Int,Float}Reg values, inserting additional values in 97 // cases where they are missing. Example: 98 // 99 // func foo(s string, used int, notused int) int { 100 // return len(s) + used 101 // } 102 // 103 // In the function above, the incoming parameter "used" is fully live, 104 // "notused" is not live, and "s" is partially live (only the length 105 // field of the string is used). At the point where debug value 106 // analysis runs, we might expect to see an entry block with: 107 // 108 // b1: 109 // v4 = ArgIntReg <uintptr> {s+8} [0] : BX 110 // v5 = ArgIntReg <int> {used} [0] : CX 111 // 112 // While this is an accurate picture of the live incoming params, 113 // we also want to have debug locations for non-live params (or 114 // their non-live pieces), e.g. something like 115 // 116 // b1: 117 // v9 = ArgIntReg <*uint8> {s+0} [0] : AX 118 // v4 = ArgIntReg <uintptr> {s+8} [0] : BX 119 // v5 = ArgIntReg <int> {used} [0] : CX 120 // v10 = ArgIntReg <int> {unused} [0] : DI 121 // 122 // This function examines the live OpArg{Int,Float}Reg values and 123 // synthesizes new (dead) values for the non-live params or the 124 // non-live pieces of partially live params. 125 func PopulateABIInRegArgOps(f *Func) 126 127 // BuildFuncDebug debug information for f, placing the results 128 // in "rval". f must be fully processed, so that each Value is where it 129 // will be when machine code is emitted. 130 func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingLevel int, stackOffset func(LocalSlot) int32, rval *FuncDebug) 131 132 // PutLocationList adds list (a location list in its intermediate representation) to listSym. 133 func (debugInfo *FuncDebug) PutLocationList(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) 134 135 // BuildFuncDebugNoOptimized populates a FuncDebug object "rval" with 136 // entries corresponding to the register-resident input parameters for 137 // the function "f"; it is used when we are compiling without 138 // optimization but the register ABI is enabled. For each reg param, 139 // it constructs a 2-element location list: the first element holds 140 // the input register, and the second element holds the stack location 141 // of the param (the assumption being that when optimization is off, 142 // each input param reg will be spilled in the prolog). 143 func BuildFuncDebugNoOptimized(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset func(LocalSlot) int32, rval *FuncDebug)