查找起作用的Pass

Bash
python3 ./fork.py --order 从上一个优化开始
python3 ./fork.py         每次都从input.ll开始
python3 ./fork.py  myinput.ll  
Python
#/usr/bin/env python3
# pass请修改pass_list

import subprocess
import os
import argparse
import tempfile

# 检查工具是否可用
def check_tool_available(tool_name):
    try:
        subprocess.run([tool_name, "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
    except subprocess.CalledProcessError:
        raise RuntimeError(f"{tool_name} not found. Please ensure LLVM is installed and {tool_name} is in your PATH.")

# 运行 opt 并返回输出文件路径
def run_opt_pass(input_file, pass_name):
    output_file = "output_" + pass_name + ".ll"

    # 构建并运行 opt 命令
    cmd = ["opt", "-S", f"-{pass_name}", input_file, "-o", output_file]
    print(f"Running opt command: {' '.join(cmd)}")
    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

    if result.returncode != 0:
        print(f"Error running pass {pass_name}: {result.stderr}")
        os.remove(output_file)
        return None

    return output_file

# 使用 llvm-diff 比较两个 IR 文件
def compare_ir_with_llvm_diff(file1, file2):
    cmd = ["llvm-diff", file1, file2]
    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

    # llvm-diff 返回 0 表示文件相同,非 0 表示有差异
    return result.returncode == 0

# 主函数:分析哪些 Pass 起作用
# order 表面是依次执行,还是每次的输入都是Input.ll
def analyze_passes(input_file, pass_list, order):
    effective_passes = []
    ineffective_passes = []

    # 逐个运行 Pass 并检查效果
    for pass_name in pass_list:
        print(f"\nAnalyzing pass: {pass_name}")
        output_file = run_opt_pass(input_file, pass_name)

        if output_file is None:
            print(f"Skipping {pass_name} due to execution error.")
            ineffective_passes.append(pass_name)
            continue

        # 使用 llvm-diff 比较
        is_identical = compare_ir_with_llvm_diff(input_file, output_file)

        if is_identical:
            ineffective_passes.append(pass_name)
            print(f"Pass {pass_name} had no effect (IR unchanged).")
        else:
            effective_passes.append(pass_name)
            print(f"Pass {pass_name} modified the IR.")

        # 删除临时文件
        # os.remove(output_file)
        if (order):
            input_file = output_file

    return effective_passes, ineffective_passes

# 打印结果
def print_results(effective_passes, ineffective_passes):
    print("\n=== Results ===")
    print("Passes that had an effect:")
    for p in effective_passes:
        print(f"  - {p}")
    print("Passes that had no effect:")
    for p in ineffective_passes:
        print(f"  - {p}")

# 命令行参数解析
def main():
    parser = argparse.ArgumentParser(description="Analyze which LLVM passes affect a given .ll file using llvm-diff.")
    parser.add_argument("input_file", nargs = '?', help="Path to the input .ll file", default = "input.ll")
    parser.add_argument("--order", action="store_true", help="Order execute the arg passes, default is false")
    args = parser.parse_args()

    input_file = args.input_file
    order = args.order

    pass_list = ["bdce", "dce", "inline", "simplifycfg"]
    print(f"pass_list: {pass_list}")

    # 验证输入文件是否存在
    if not os.path.exists(input_file):
        print(f"Error: Input file {input_file} does not exist.")
        return

    # 检查 opt 和 llvm-diff 工具
    check_tool_available("opt")
    check_tool_available("llvm-diff")

    # 分析 Pass
    effective_passes, ineffective_passes = analyze_passes(input_file, pass_list, order)

    # 输出结果
    print_results(effective_passes, ineffective_passes)

if __name__ == "__main__":
    main()