<commit_before>use std::collections::{HashMap, HashSet};
use analysis::{self, Loc};
use ir::{Function, BinaryOp, BitOp, IntOp, UnaryOp, Signedness, Size, Program, Reg, Block, Instruction, Value, BlockEnd, BlockId};


#[derive(Debug, Clone)]
enum Val {
    Ir(Value),
    Ref(Reg, u32),
    Unknown,
    Any,
}

impl Val {
    fn merge(self, other: Val) -> Val {
        match (self, other) {
            (Val::Any, other) | (other, Val::Any) => other,
            (Val::Unknown, _) | (_, Val::Unknown) => Val::Unknown,
            (Val::Ref(a, oa), Val::Ref(b, ob)) if (a, oa) == (b, ob) => Val::Ref(a, oa),
            (Val::Ir(a), Val::Ir(b)) => if a == b {
                Val::Ir(a)
            } else {
                Val::Unknown
            },
            _ => Val::Unknown,
        }
    }
}

struct Context<'a> {
    volatile: HashMap<Reg, HashSet<Loc>>,
    f: &'a Function,
    incoming: &'a HashMap<BlockId, Vec<BlockId>>,
    visited: HashSet<Loc>,
}

impl<'a> Context<'a> {
    fn is_volatile_at(&self, reg: Reg, loc: Loc) -> bool {
        if let Some(locs) = self.volatile.get(&reg) {
            locs.contains(&loc)
        } else {
            false
        }
    }

    fn dfs(&mut self, reg: Reg, block_id: BlockId, block: &Block, mut pos: usize) -> Val {
        loop {
            let loc = Loc { block: block_id, pos };
            if self.visited.contains(&loc) {
                return Val::Any;
            }
            self.visited.insert(loc);
            if pos == 0 {
                let mut total = Val::Any;
                if let Some(inc) = self.incoming.get(&block_id) {
                    for &parent in inc {
                        total = total.merge(self.dfs_block_end(reg, parent));
                    }
                }
                return total;
            } else {
                let loc = Loc { block: block_id, pos: pos - 1 };
                let op = &block.ops[pos - 1];
                match *op {
                    Instruction::Assign(r, ref val) |
                    Instruction::CastAssign(r, ref val) if r == reg => return Val::Ir(val.clone()),
                    Instruction::BinaryOp(r, _, _, _) |
                    Instruction::DerefLoad(r, _, _) |
                    Instruction::Load(r, _, _) |
                    Instruction::Store(r, _, _) if r == reg => return Val::Unknown,
                    Instruction::Call(r, _, _) |
                    Instruction::CallVirt(r, _, _) => {
                        if r == reg || self.is_volatile_at(reg, loc) {
                            return Val::Unknown;
                        }
                    }
                    Instruction::CallProc(_, _) |
                    Instruction::CallProcVirt(_, _) |
                    Instruction::DerefStore(_, _, _) => {
                        if self.is_volatile_at(reg, loc) {
                            return Val::Unknown;
                        }
                    }
                    Instruction::Drop(r) |
                    Instruction::Init(r) if r == reg => {
                        return Val::Any;<commit_msg>constant fold fix<commit_after>use std::collections::{HashMap, HashSet};
use analysis::{self, Loc};
use ir::{Function, BinaryOp, BitOp, IntOp, UnaryOp, Signedness, Size, Program, Reg, Block, Instruction, Value, BlockEnd, BlockId};


#[derive(Debug, Clone)]
enum Val {
    Ir(Value),
    Ref(Reg, u32),
    Unknown,
    Any,
}

impl Val {
    fn from_ir(v: &Value) -> Val {
        if let Value::Reg(_) = *v {
            Val::Unknown
        } else {
            Val::Ir(v.clone())
        }
    }

    fn merge(self, other: Val) -> Val {
        match (self, other) {
            (Val::Any, other) | (other, Val::Any) => other,
            (Val::Unknown, _) | (_, Val::Unknown) => Val::Unknown,
            (Val::Ref(a, oa), Val::Ref(b, ob)) if (a, oa) == (b, ob) => Val::Ref(a, oa),
            (Val::Ir(a), Val::Ir(b)) => if a == b {
                Val::Ir(a)
            } else {
                Val::Unknown
            },
            _ => Val::Unknown,
        }
    }
}

struct Context<'a> {
    volatile: HashMap<Reg, HashSet<Loc>>,
    f: &'a Function,
    incoming: &'a HashMap<BlockId, Vec<BlockId>>,
    visited: HashSet<Loc>,
}

impl<'a> Context<'a> {
    fn is_volatile_at(&self, reg: Reg, loc: Loc) -> bool {
        if let Some(locs) = self.volatile.get(&reg) {
            locs.contains(&loc)
        } else {
            false
        }
    }

    fn dfs(&mut self, reg: Reg, block_id: BlockId, block: &Block, mut pos: usize) -> Val {
        loop {
            let loc = Loc { block: block_id, pos };
            if self.visited.contains(&loc) {
                return Val::Any;
            }
            self.visited.insert(loc);
            if pos == 0 {
                let mut total = Val::Any;
                if let Some(inc) = self.incoming.get(&block_id) {
                    for &parent in inc {
                        total = total.merge(self.dfs_block_end(reg, parent));
                    }
                }
                return total;
            } else {
                let loc = Loc { block: block_id, pos: pos - 1 };
                let op = &block.ops[pos - 1];
                match *op {
                    Instruction::Assign(r, ref val) |
                    Instruction::CastAssign(r, ref val) if r == reg => return Val::from_ir(val),
                    Instruction::BinaryOp(r, _, _, _) |
                    Instruction::DerefLoad(r, _, _) |
                    Instruction::Load(r, _, _) |
                    Instruction::Store(r, _, _) if r == reg => return Val::Unknown,
                    Instruction::Call(r, _, _) |
                    Instruction::CallVirt(r, _, _) => {
                        if r == reg || self.is_volatile_at(reg, loc) {
                            return Val::Unknown;
                        }
                    }
                    Instruction::CallProc(_, _) |
                    Instruction::CallProcVirt(_, _) |
                    Instruction::DerefStore(_, _, _) => {
                        if self.is_volatile_at(reg, loc) {
                            return Val::Unknown;
                        }
                    }
                    Instruction::Drop(r) |
                    Instruction::Init(r) if r == reg => {
                        return Val::Any;
{'fraction_non_alphanumeric': 0.1428122050959421, 'fraction_numerical': 0.0015728216420257944, 'mean_word_length': 1.3499630450849962, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7648271', 'n_tokens_mistral': 1936, 'n_tokens_neox': 1861, 'n_words': 416}