| 2230 | } |
| 2231 | |
| 2232 | void Differ::MatchTypeForwardPointers() { |
| 2233 | // Bunch all of type forward pointers as potential matches. |
| 2234 | PotentialIdMap potential_id_map; |
| 2235 | auto get_pointer_type_id = [](const opt::Instruction& inst) { |
| 2236 | return inst.GetSingleWordOperand(0); |
| 2237 | }; |
| 2238 | auto accept_type_forward_pointer_ops = [](const opt::Instruction& inst) { |
| 2239 | return inst.opcode() == spv::Op::OpTypeForwardPointer; |
| 2240 | }; |
| 2241 | |
| 2242 | PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true, |
| 2243 | accept_type_forward_pointer_ops, get_pointer_type_id); |
| 2244 | PoolPotentialIds(dst_->types_values(), potential_id_map.dst_ids, false, |
| 2245 | accept_type_forward_pointer_ops, get_pointer_type_id); |
| 2246 | |
| 2247 | // Matching types with cyclical references (i.e. in the style of linked lists) |
| 2248 | // can get very complex. Currently, the diff tool matches types bottom up, so |
| 2249 | // on every instruction it expects to know if its operands are already matched |
| 2250 | // or not. With cyclical references, it cannot know that. Type matching may |
| 2251 | // need significant modifications to be able to support this use case. |
| 2252 | // |
| 2253 | // Currently, forwarded types are only matched by storage class and debug |
| 2254 | // info, with minimal matching of the type being forwarded: |
| 2255 | // |
| 2256 | // - Group by class |
| 2257 | // - Group by OpType being pointed to |
| 2258 | // - Group by debug info |
| 2259 | // - If same name and unique, match |
| 2260 | // - If leftover is unique, match |
| 2261 | |
| 2262 | // Group forwarded pointers by storage class first and loop over them. |
| 2263 | GroupIdsAndMatch<spv::StorageClass>( |
| 2264 | potential_id_map.src_ids, potential_id_map.dst_ids, |
| 2265 | spv::StorageClass::Max, &Differ::GroupIdsHelperGetTypePointerStorageClass, |
| 2266 | [this](const IdGroup& src_group_by_storage_class, |
| 2267 | const IdGroup& dst_group_by_storage_class) { |
| 2268 | // Group them further by the type they are pointing to and loop over |
| 2269 | // them. |
| 2270 | GroupIdsAndMatch<spv::Op>( |
| 2271 | src_group_by_storage_class, dst_group_by_storage_class, |
| 2272 | spv::Op::Max, &Differ::GroupIdsHelperGetTypePointerTypeOp, |
| 2273 | [this](const IdGroup& src_group_by_type_op, |
| 2274 | const IdGroup& dst_group_by_type_op) { |
| 2275 | // Group them even further by debug info, if possible and match by |
| 2276 | // debug name. |
| 2277 | MatchTypeForwardPointersByName(src_group_by_type_op, |
| 2278 | dst_group_by_type_op); |
| 2279 | |
| 2280 | // Match the leftovers only if they lack debug info and there is |
| 2281 | // only one instance of them. |
| 2282 | MatchTypeForwardPointersByTypeOp(src_group_by_type_op, |
| 2283 | dst_group_by_type_op); |
| 2284 | }); |
| 2285 | }); |
| 2286 | |
| 2287 | // Match the instructions that forward declare the same type themselves |
| 2288 | for (uint32_t src_id : potential_id_map.src_ids) { |
| 2289 | uint32_t dst_id = id_map_.MappedDstId(src_id); |
no test coverage detected