| 121 | } |
| 122 | |
| 123 | void LoadStore(uint64_t offset, |
| 124 | Opcode opc, |
| 125 | Type type, |
| 126 | Address align, |
| 127 | const Node& addr_exp) { |
| 128 | auto byte_size = opc.GetMemorySize(); |
| 129 | type = GetMemoryType(type, opc); |
| 130 | // We want to associate memory ops of a certain offset & size as being |
| 131 | // relative to a uniquely identifiable pointer, such as a local. |
| 132 | auto name = AddrExpName(addr_exp); |
| 133 | if (name.empty()) { |
| 134 | return; |
| 135 | } |
| 136 | auto& var = vars[name]; |
| 137 | auto& access = var.accesses[offset]; |
| 138 | // Check if previous access at this offset (if any) is of same size |
| 139 | // and type (see Checklayouts below). |
| 140 | if (access.byte_size && ((access.byte_size != byte_size) || |
| 141 | (access.type != type) || (access.align != align))) |
| 142 | access.is_uniform = false; |
| 143 | // Also exclude weird alignment accesses from structs. |
| 144 | if (!opc.IsNaturallyAligned(align)) |
| 145 | access.is_uniform = false; |
| 146 | access.byte_size = byte_size; |
| 147 | access.type = type; |
| 148 | access.align = align; |
| 149 | // Additionally, check if all accesses are to the same type, so |
| 150 | // if layout check fails, we can at least declare it as pointer to |
| 151 | // a type. |
| 152 | if ((var.same_type == type || var.same_type == Type::Any) && |
| 153 | (var.same_align == align || var.same_align == kInvalidAddress)) { |
| 154 | var.same_type = type; |
| 155 | var.same_align = align; |
| 156 | var.last_opc = opc; |
| 157 | } else { |
| 158 | var.same_type = Type::Void; |
| 159 | var.same_align = kInvalidAddress; |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | void CheckLayouts() { |
| 164 | // Here we check if the set of accesses we have collected form a sequence |
nothing calls this directly
no test coverage detected