use std::collections::HashMap;
use crate::arch::x86::DecodedInsn;
use crate::ast::Stmt;
mod arith;
mod cmp_jcc;
mod imul;
mod lea;
mod load_modify_store;
mod mem_via_reg;
mod mov;
mod mov_extend;
mod push_imm_pop_reg;
mod simd_expr;
mod stack_arg_call;
mod tail_jmp;
mod unary;
mod x87_expr;
mod xor_zero;
pub struct PatternCtx<'a> {
#[allow(dead_code)]
pub fn_addr_start: u64,
pub fn_addr_end: u64,
pub name_at: &'a HashMap<u64, String>,
pub sp_delta_at: &'a HashMap<u64, i64>,
}
#[derive(Debug, Clone)]
pub struct Candidate {
pub pattern: &'static str,
pub start: usize,
pub consumed: usize,
pub priority: u32,
pub stmts: Vec<Stmt>,
}
#[derive(Debug, Clone)]
pub struct AppliedMatch {
pub consumed: usize,
pub stmts: Vec<Stmt>,
}
pub trait Pattern: Sync {
fn name(&self) -> &'static str;
fn tentative(&self, ctx: &PatternCtx, insns: &[DecodedInsn], start: usize)
-> Option<Candidate>;
fn confirm(&self, _ctx: &PatternCtx, _cand: &Candidate, _all: &[Candidate]) -> bool {
true
}
}
fn registry() -> Vec<&'static dyn Pattern> {
vec![
&stack_arg_call::StackArgCall,
&tail_jmp::TailJmp,
&push_imm_pop_reg::PushImmPopReg,
&xor_zero::XorZero,
&load_modify_store::LoadModifyStore,
&mem_via_reg::MemViaReg,
&mov::Mov,
&mov_extend::MovExtend,
&lea::Lea,
&arith::Arith,
&unary::Unary,
&imul::Imul,
&cmp_jcc::CmpJcc,
&simd_expr::SimdExpr,
&x87_expr::X87Expr,
]
}
pub fn apply_patterns(ctx: &PatternCtx, insns: &[DecodedInsn]) -> HashMap<usize, AppliedMatch> {
let mut tentative: Vec<Candidate> = Vec::new();
for p in registry() {
for i in 0..insns.len() {
if let Some(c) = p.tentative(ctx, insns, i) {
tentative.push(c);
}
}
}
let confirmed: Vec<Candidate> = tentative
.iter()
.filter(|c| {
registry()
.iter()
.find(|p| p.name() == c.pattern)
.is_some_and(|p| p.confirm(ctx, c, &tentative))
})
.cloned()
.collect();
let mut sorted = confirmed;
sorted.sort_by(|a, b| {
b.priority
.cmp(&a.priority)
.then(b.consumed.cmp(&a.consumed))
.then(a.start.cmp(&b.start))
});
let mut consumed = vec![false; insns.len()];
let mut out: HashMap<usize, AppliedMatch> = HashMap::new();
for cand in sorted {
let end = cand.start.saturating_add(cand.consumed);
if end > insns.len() {
continue;
}
if (cand.start..end).any(|i| consumed[i]) {
continue;
}
for slot in &mut consumed[cand.start..end] {
*slot = true;
}
out.insert(
cand.start,
AppliedMatch {
consumed: cand.consumed,
stmts: cand.stmts,
},
);
}
out
}