You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Rust更优雅地实现汇编指令窗口的窥孔优化模式匹配?

窥孔优化代码的重构实现方案

问题背景

基于抽象栈机模型的编译器需要实现窥孔优化,将Vec<LLStackInstruction>转换为优化后的指令序列。针对初始化/赋值操作,原流程是将右值入栈、左值地址入栈,再执行弹出和STR指令,目标是简化为直接将右值入栈并通过地址指定符存储,但当前的匹配代码嵌套层级极深,可读性差且维护困难。

当前实现代码

pub fn peephole_optimiser(instrs: Vec<LLStackInstruction>) -> Vec<LLStackInstruction> {
    let mut optimized_instructions: Vec<LLStackInstruction> = Vec::new();

    let mut iter = instrs.iter().peekable();

    while let Some(instruction) = iter.next() {
        let window_iter = iter.clone();
        let window: Vec<_> = [vec![instruction], window_iter.take(10).collect()].concat();
        
        if let Some(LLStackInstruction::Push(Register::FP)) = window.get(0) {
            if let Some(LLStackInstruction::Mov(Condition::None, r1, ArgType::Imm(n))) = window.get(1) {
                if let Some(LLStackInstruction::Push(r2)) = window.get(2) {
                    if let Some(LLStackInstruction::Pop(_)) = window.get(3) {
                        if let Some(LLStackInstruction::Pop(_)) = window.get(4) {
                            if let Some(LLStackInstruction::Sub(..)) = window.get(5) {
                                if let Some(LLStackInstruction::Branch(..)) = window.get(6) {
                                    if let Some(LLStackInstruction::Push(_)) = window.get(7) {
                                        if let Some(LLStackInstruction::Pop(_)) = window.get(8) {
                                            if let Some(LLStackInstruction::Pop(_)) = window.get(9) {
                                                if let Some(LLStackInstruction::Str(..)) = window.get(10) {
                                                    if r1 == r2 {
                                                        optimized_instructions.push(LLStackInstruction::Pop(Register::R4));
                                                        optimized_instructions.push(LLStackInstruction::Str(Register::R4, AddressSpecifier::ImmediateOffset(Register::FP, -n)));
                                                        iter.nth(9);
                                                        continue;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        optimized_instructions.push(instruction.clone());
    }
    optimized_instructions
}

优化示例

// 紧凑初始化/赋值语句
// push {fp}
// mov r1, #88
// push {r1}
// pop {r0}
// pop {r1}
// subs r0, r1, r0
// bvs _overflow_err
// push {r0}
// pop {r3}
// pop {r4}
// str r4, [r3]

// 转换为
// pop {r4}
// str r4, [fp, #-88]

更优实现方案

1. 链式替代嵌套匹配

利用Rust的Option链式调用(and_then),把多层嵌套的if let拆成线性逻辑,大幅提升可读性:

pub fn peephole_optimiser(instrs: Vec<LLStackInstruction>) -> Vec<LLStackInstruction> {
    let mut optimized = Vec::new();
    let mut iter = instrs.iter().peekable();

    while let Some(first) = iter.next() {
        // 构建匹配窗口:当前指令+后续10条
        let mut window = vec![first];
        window.extend(iter.clone().take(10));

        let match_result = (window.get(0), window.get(1), window.get(2), window.get(3), window.get(4), window.get(5), window.get(6), window.get(7), window.get(8), window.get(9), window.get(10))
            .and_then(|(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10)| {
                let fp_push = matches!(i0, Some(LLStackInstruction::Push(Register::FP)));
                let mov_imm = if let Some(LLStackInstruction::Mov(Condition::None, r1, ArgType::Imm(n))) = i1 {
                    Some((r1.clone(), *n))
                } else {
                    None
                };
                let r_push = if let Some(LLStackInstruction::Push(r2)) = i2 {
                    Some(r2.clone())
                } else {
                    None
                };
                let pop1 = matches!(i3, Some(LLStackInstruction::Pop(_)));
                let pop2 = matches!(i4, Some(LLStackInstruction::Pop(_)));
                let sub = matches!(i5, Some(LLStackInstruction::Sub(..)));
                let branch = matches!(i6, Some(LLStackInstruction::Branch(..)));
                let push_r0 = matches!(i7, Some(LLStackInstruction::Push(_)));
                let pop3 = matches!(i8, Some(LLStackInstruction::Pop(_)));
                let pop4 = matches!(i9, Some(LLStackInstruction::Pop(_)));
                let str = matches!(i10, Some(LLStackInstruction::Str(..)));

                if fp_push && pop1 && pop2 && sub && branch && push_r0 && pop3 && pop4 && str {
                    mov_imm.zip(r_push).filter(|(r1, r2)| r1 == r2)
                } else {
                    None
                }
            });

        if let Some((_r, n)) = match_result {
            // 应用优化替换
            optimized.push(LLStackInstruction::Pop(Register::R4));
            optimized.push(LLStackInstruction::Str(Register::R4, AddressSpecifier::ImmediateOffset(Register::FP, -n)));
            // 跳过已匹配的后续10条指令
            iter.nth(9);
            continue;
        }

        // 无匹配则保留原指令
        optimized.push(first.clone());
    }

    optimized
}

2. 封装优化规则为结构体

如果后续要添加更多窥孔优化规则,可以把每个规则的匹配逻辑、条件判断、替换逻辑封装成独立结构体,提升扩展性:

// 定义优化规则 trait
trait PeepholeRule {
    // 尝试匹配窗口内的指令,返回替换后的指令序列(匹配成功时)和需要跳过的指令数量
    fn apply(&self, window: &[&LLStackInstruction]) -> Option<(Vec<LLStackInstruction>, usize)>;
}

// 针对初始化/赋值的具体规则
struct AssignOptimizationRule;

impl PeepholeRule for AssignOptimizationRule {
    fn apply(&self, window: &[&LLStackInstruction]) -> Option<(Vec<LLStackInstruction>, usize)> {
        if window.len() < 11 {
            return None;
        }

        let i0 = window[0];
        let i1 = window[1];
        let i2 = window[2];
        let i3 = window[3];
        let i4 = window[4];
        let i5 = window[5];
        let i6 = window[6];
        let i7 = window[7];
        let i8 = window[8];
        let i9 = window[9];
        let i10 = window[10];

        // 匹配模式校验
        let fp_push = matches!(i0, LLStackInstruction::Push(Register::FP));
        let (r1, n) = if let LLStackInstruction::Mov(Condition::None, r, ArgType::Imm(num)) = i1 {
            (r.clone(), num)
        } else {
            return None;
        };
        let r2 = if let LLStackInstruction::Push(r) = i2 { r.clone() } else { return None; };
        let pop1 = matches!(i3, LLStackInstruction::Pop(_));
        let pop2 = matches!(i4, LLStackInstruction::Pop(_));
        let sub = matches!(i5, LLStackInstruction::Sub(..));
        let branch = matches!(i6, LLStackInstruction::Branch(..));
        let push_r0 = matches!(i7, LLStackInstruction::Push(_));
        let pop3 = matches!(i8, LLStackInstruction::Pop(_));
        let pop4 = matches!(i9, LLStackInstruction::Pop(_));
        let str = matches!(i10, LLStackInstruction::Str(..));

        if fp_push && r1 == r2 && pop1 && pop2 && sub && branch && push_r0 && pop3 && pop4 && str {
            let replacement = vec![
                LLStackInstruction::Pop(Register::R4),
                LLStackInstruction::Str(Register::R4, AddressSpecifier::ImmediateOffset(Register::FP, -n))
            ];
            // 总共匹配11条指令,跳过后续10条
            Some((replacement, 10))
        } else {
            None
        }
    }
}

pub fn peephole_optimiser(instrs: Vec<LLStackInstruction>) -> Vec<LLStackInstruction> {
    let mut optimized = Vec::new();
    let mut iter = instrs.iter().peekable();
    let rules: Vec<Box<dyn PeepholeRule>> = vec![Box::new(AssignOptimizationRule)];

    while let Some(first) = iter.next() {
        let mut window = vec![first];
        window.extend(iter.clone().take(20)); // 预留足够大的窗口容纳所有规则的匹配长度

        let mut matched = false;
        for rule in &rules {
            if let Some((replacement, skip_count)) = rule.apply(&window) {
                optimized.extend(replacement);
                iter.nth(skip_count - 1); // 已取第一个指令,跳过剩余skip_count个元素
                matched = true;
                break;
            }
        }

        if !matched {
            optimized.push(first.clone());
        }
    }

    optimized
}

3. 多轮优化处理

如果优化后的指令序列可能产生新的窥孔优化机会,可以加入多轮优化逻辑,直到无优化可应用:

pub fn peephole_optimiser(mut instrs: Vec<LLStackInstruction>) -> Vec<LLStackInstruction> {
    loop {
        let optimized = single_pass_optimise(instrs);
        if optimized.len() == instrs.len() {
            // 长度不变,无更多优化空间,退出
            break optimized;
        }
        instrs = optimized;
    }
}

// 单轮优化函数(复用前面的链式匹配或规则封装实现)
fn single_pass_optimise(instrs: Vec<LLStackInstruction>) -> Vec<LLStackInstruction> {
    // ... 此处放入单轮优化代码 ...
}

方案优势

  • 链式匹配让代码线性化,可读性和可维护性大幅提升
  • 规则封装模式便于后续添加新的窥孔优化规则,扩展性强
  • 多轮优化能处理优化后产生的新优化场景,优化更彻底

内容的提问来源于stack exchange,提问作者Ahmed Mahmud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 03:07:07