Splits an OpCopyMemory into an OpLoad followed by an OpStore. This is because we want to be able to mem2reg variables used in OpCopyMemory, but analysis becomes very difficult: we only analyze one variable at a time, but OpCopyMemory can copy between two local variables (both of which are getting mem2reg'd), requiring cross-analysis shenanigans. So, if we know at least one side of the OpCopyMemory
(
header: &mut ModuleHeader,
blocks: &mut [Block],
var_map: &FxHashMap<Word, VarInfo>,
)
| 306 | // Finally, an edge case to keep in mind is that an OpCopyMemory can happen between two vars in the |
| 307 | // same var map (e.g. `s.x = s.y;`). |
| 308 | fn split_copy_memory( |
| 309 | header: &mut ModuleHeader, |
| 310 | blocks: &mut [Block], |
| 311 | var_map: &FxHashMap<Word, VarInfo>, |
| 312 | ) { |
| 313 | for block in blocks { |
| 314 | let mut inst_index = 0; |
| 315 | while inst_index < block.instructions.len() { |
| 316 | let inst = &block.instructions[inst_index]; |
| 317 | if inst.class.opcode == Op::CopyMemory { |
| 318 | let target = inst.operands[0].id_ref_any().unwrap(); |
| 319 | let source = inst.operands[1].id_ref_any().unwrap(); |
| 320 | if inst.operands.len() > 2 { |
| 321 | // TODO: Copy the memory operands to the load/store |
| 322 | bug!("mem2reg OpCopyMemory doesn't support memory operands yet"); |
| 323 | } |
| 324 | let ty = match (var_map.get(&target), var_map.get(&source)) { |
| 325 | (None, None) => { |
| 326 | inst_index += 1; |
| 327 | continue; |
| 328 | } |
| 329 | (Some(target), None) => target.ty, |
| 330 | (None, Some(source)) => source.ty, |
| 331 | (Some(target), Some(source)) => { |
| 332 | assert_eq!(target.ty, source.ty); |
| 333 | target.ty |
| 334 | } |
| 335 | }; |
| 336 | let temp_id = id(header); |
| 337 | block.instructions[inst_index] = Instruction::new( |
| 338 | Op::Load, |
| 339 | Some(ty), |
| 340 | Some(temp_id), |
| 341 | vec![Operand::IdRef(source)], |
| 342 | ); |
| 343 | inst_index += 1; |
| 344 | block.instructions.insert( |
| 345 | inst_index, |
| 346 | Instruction::new( |
| 347 | Op::Store, |
| 348 | None, |
| 349 | None, |
| 350 | vec![Operand::IdRef(target), Operand::IdRef(temp_id)], |
| 351 | ), |
| 352 | ); |
| 353 | } |
| 354 | inst_index += 1; |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | fn has_store(block: &Block, var_map: &FxHashMap<Word, VarInfo>) -> bool { |
| 360 | block.instructions.iter().any(|inst| { |
no test coverage detected