(
pointer_to_pointee: &FxHashMap<Word, Word>,
constants: &FxHashMap<Word, u32>,
blocks: &[Block],
base_var: Word,
base_var_ty: Word,
)
| 214 | } |
| 215 | |
| 216 | fn collect_access_chains( |
| 217 | pointer_to_pointee: &FxHashMap<Word, Word>, |
| 218 | constants: &FxHashMap<Word, u32>, |
| 219 | blocks: &[Block], |
| 220 | base_var: Word, |
| 221 | base_var_ty: Word, |
| 222 | ) -> Option<FxHashMap<Word, VarInfo>> { |
| 223 | fn construct_access_chain_info( |
| 224 | pointer_to_pointee: &FxHashMap<Word, Word>, |
| 225 | constants: &FxHashMap<Word, u32>, |
| 226 | inst: &Instruction, |
| 227 | base: &VarInfo, |
| 228 | ) -> Option<VarInfo> { |
| 229 | Some(VarInfo { |
| 230 | ty: *pointer_to_pointee.get(&inst.result_type.unwrap()).unwrap(), |
| 231 | indices: { |
| 232 | let mut base_indicies = base.indices.clone(); |
| 233 | for op in inst.operands.iter().skip(1) { |
| 234 | base_indicies.push(*constants.get(&op.id_ref_any().unwrap())?); |
| 235 | } |
| 236 | base_indicies |
| 237 | }, |
| 238 | }) |
| 239 | } |
| 240 | |
| 241 | let mut variables = FxHashMap::default(); |
| 242 | variables.insert( |
| 243 | base_var, |
| 244 | VarInfo { |
| 245 | ty: base_var_ty, |
| 246 | indices: vec![], |
| 247 | }, |
| 248 | ); |
| 249 | // Loop in case a previous block references a later AccessChain |
| 250 | loop { |
| 251 | let mut changed = false; |
| 252 | for inst in blocks.iter().flat_map(|b| &b.instructions) { |
| 253 | for (index, op) in inst.operands.iter().enumerate() { |
| 254 | if let Operand::IdRef(id) = op { |
| 255 | if variables.contains_key(id) { |
| 256 | match inst.class.opcode { |
| 257 | // Only allow store if pointer is the lhs, not rhs |
| 258 | Op::Store if index == 0 => {} |
| 259 | Op::Load |
| 260 | | Op::AccessChain |
| 261 | | Op::InBoundsAccessChain |
| 262 | | Op::CopyMemory => {} |
| 263 | _ => return None, |
| 264 | } |
| 265 | } |
| 266 | } |
| 267 | } |
| 268 | if let Op::AccessChain | Op::InBoundsAccessChain = inst.class.opcode { |
| 269 | if let Some(base) = variables.get(&inst.operands[0].id_ref_any().unwrap()) { |
| 270 | let info = |
| 271 | construct_access_chain_info(pointer_to_pointee, constants, inst, base)?; |
| 272 | match variables.entry(inst.result_id.unwrap()) { |
| 273 | hash_map::Entry::Vacant(entry) => { |
no test coverage detected