use crate::dataflow::DataFlow;
use crate::z80::dataflow::Register;
use crate::z80::Insn;
use crate::Constrain;
use crate::Sequence;
#[derive(Debug)]
pub struct RegPairFixup();
impl RegPairFixup {
fn reads(&self, candidate: &Sequence<Insn>, offset: usize, register: &Register) -> bool {
candidate
.iter()
.skip(offset + 1)
.any(|insn| insn.reads(register))
}
fn unnecessary_load(
&self,
candidate: &Sequence<Insn>,
offset: usize,
opcode: &[u8],
left: Register,
right: Register,
) -> bool {
use crate::Encode;
let enc = candidate[offset].encode();
if enc.len() < opcode.len() {
return false;
}
if enc[..opcode.len()] != opcode[..opcode.len()] {
return false;
}
if self.reads(candidate, offset, &left) && self.reads(candidate, offset, &right) {
return false;
}
true
}
fn check(&self, candidate: &Sequence<Insn>, offset: usize) -> Option<&'static str> {
if self.unnecessary_load(candidate, offset, &[0x01], Register::B, Register::C) {
Some("No need to load BC, since B and C is not used later")
} else if self.unnecessary_load(candidate, offset, &[0x11], Register::D, Register::E) {
Some("No need to load DE, since E is not used later")
} else if self.unnecessary_load(candidate, offset, &[0x21], Register::H, Register::L) {
Some("No need to load HL, since H and L is not used later")
} else {
None
}
}
}
impl Constrain<Insn> for RegPairFixup {
fn fixup(&self, candidate: &mut Sequence<Insn>) -> Option<(usize, &'static str)> {
for i in 0..(candidate.len() - 1) {
if let Some(r) = self.check(candidate, i) {
candidate.mut_at(Insn::next_opcode, i);
return Some((i, r));
}
}
None
}
}