diff --git a/src/ir/equiv.rs b/src/ir/equiv.rs index ebf78b4..e92ce4d 100644 --- a/src/ir/equiv.rs +++ b/src/ir/equiv.rs @@ -110,13 +110,143 @@ fn is_equiv_block(lhs: &Block, rhs: &Block, map: &HashMap) -> return false; } - if lhs.instructions != rhs.instructions { + if lhs.instructions.len() != rhs.instructions.len() { return false; } + for (l, r) in izip!(&lhs.instructions, &rhs.instructions) { + if !is_equiv_instruction(l, r, map) { + return false; + } + } + is_equiv_block_exit(&lhs.exit, &rhs.exit, map) } +fn is_equiv_instruction( + lhs: &Instruction, + rhs: &Instruction, + map: &HashMap, +) -> bool { + match (lhs, rhs) { + (Instruction::Nop, Instruction::Nop) => true, + ( + Instruction::BinOp { + op, + lhs, + rhs, + dtype, + }, + Instruction::BinOp { + op: op_other, + lhs: lhs_other, + rhs: rhs_other, + dtype: dtype_other, + }, + ) => { + op == op_other + && is_equiv_operand(lhs, lhs_other, map) + && is_equiv_operand(rhs, rhs_other, map) + && dtype == dtype_other + } + ( + Instruction::UnaryOp { op, operand, dtype }, + Instruction::UnaryOp { + op: op_other, + operand: operand_other, + dtype: dtype_other, + }, + ) => { + op == op_other && is_equiv_operand(operand, operand_other, map) && dtype == dtype_other + } + ( + Instruction::Store { ptr, value }, + Instruction::Store { + ptr: ptr_other, + value: value_other, + }, + ) => is_equiv_operand(ptr, ptr_other, map) && is_equiv_operand(value, value_other, map), + (Instruction::Load { ptr }, Instruction::Load { ptr: ptr_other }) => { + is_equiv_operand(ptr, ptr_other, map) + } + ( + Instruction::Call { + callee, + args, + return_type, + }, + Instruction::Call { + callee: callee_other, + args: args_other, + return_type: return_type_other, + }, + ) => { + is_equiv_operand(callee, callee_other, map) + && args.len() == args_other.len() + && izip!(args, args_other).all(|(l, r)| is_equiv_operand(l, r, map)) + && return_type == return_type_other + } + ( + Instruction::TypeCast { + value, + target_dtype, + }, + Instruction::TypeCast { + value: value_other, + target_dtype: target_dtype_other, + }, + ) => is_equiv_operand(value, value_other, map) && target_dtype == target_dtype_other, + ( + Instruction::GetElementPtr { ptr, offset, dtype }, + Instruction::GetElementPtr { + ptr: ptr_other, + offset: offset_other, + dtype: dtype_other, + }, + ) => { + is_equiv_operand(ptr, ptr_other, map) + && is_equiv_operand(offset, offset_other, map) + && dtype == dtype_other + } + _ => false, + } +} + +fn is_equiv_operand(lhs: &Operand, rhs: &Operand, map: &HashMap) -> bool { + match (lhs, rhs) { + (Operand::Constant(_), Operand::Constant(_)) => lhs == rhs, + ( + Operand::Register { rid, dtype }, + Operand::Register { + rid: rid_other, + dtype: dtype_other, + }, + ) => is_equiv_rid(rid, rid_other, map) && dtype == dtype_other, + _ => false, + } +} + +fn is_equiv_rid(lhs: &RegisterId, rhs: &RegisterId, map: &HashMap) -> bool { + match (lhs, rhs) { + (RegisterId::Local { .. }, RegisterId::Local { .. }) => lhs == rhs, + ( + RegisterId::Arg { bid, aid }, + RegisterId::Arg { + bid: bid_other, + aid: aid_other, + }, + ) => map.get(bid) == Some(bid_other) && aid == aid_other, + ( + RegisterId::Temp { bid, iid }, + RegisterId::Temp { + bid: bid_other, + iid: iid_other, + }, + ) => map.get(bid) == Some(bid_other) && iid == iid_other, + _ => false, + } +} + fn is_equiv_block_exit(lhs: &BlockExit, rhs: &BlockExit, map: &HashMap) -> bool { match (lhs, rhs) { (BlockExit::Jump { arg }, BlockExit::Jump { arg: arg_other }) => {