Skip to content

Commit

Permalink
feat: Implement m_has_n_usags Instruction matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
AmrDeveloper committed Nov 13, 2024
1 parent fee3eab commit 6fbfb89
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 9 deletions.
1 change: 1 addition & 0 deletions docs/InstructionMatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Instructions Matchers are functions that build a instruction matcher to match ag
| m_unreachable | () | InstMatcher | Build Inst Matcher that match unreachable Instruction |
| m_unused | (m : InstMatcher?) | InstMatcher | Build Inst Matcher that match instruction that unused at all |
| m_has_one_use | (m : InstMatcher?) | InstMatcher | Build Inst Matcher that match instruction that has exactly on use |
| m_has_n_uses | (m : InstMatcher?, n: Int) | InstMatcher | Build Inst Matcher that match instruction that has n number of uses |

### Arithmetic Instructions Matchers functions

Expand Down
33 changes: 30 additions & 3 deletions src/functions/inst_matcher.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::HashMap;

use gitql_ast::types::boolean::BoolType;
use gitql_ast::types::integer::IntType;
use gitql_ast::types::optional::OptionType;
use gitql_ast::types::text::TextType;
use gitql_core::signature::Function;
Expand All @@ -19,11 +20,11 @@ use crate::matchers::instruction_matcher::ArgumentMatcher;
use crate::matchers::instruction_matcher::ConstFloatMatcher;
use crate::matchers::instruction_matcher::ConstIntMatcher;
use crate::matchers::instruction_matcher::ConstPointerNullMatcher;
use crate::matchers::instruction_matcher::HasOneUseInstMatcher;
use crate::matchers::instruction_matcher::LabelInstMatcher;
use crate::matchers::instruction_matcher::PoisonValueMatcher;
use crate::matchers::instruction_matcher::ReturnInstMatcher;
use crate::matchers::instruction_matcher::UnreachableInstMatcher;
use crate::matchers::instruction_matcher::UsageInstMatcher;

use super::arithmetic_matchers::register_arithmetic_matchers_function_signatures;
use super::arithmetic_matchers::register_arithmetic_matchers_functions;
Expand All @@ -47,6 +48,7 @@ pub fn register_inst_matchers_functions(map: &mut HashMap<&'static str, Function

map.insert("m_unused", match_unused);
map.insert("m_has_one_use", match_has_one_use);
map.insert("m_has_n_uses", match_has_n_uses);

register_arithmetic_matchers_functions(map);
register_int_comparisons_matchers_functions(map);
Expand Down Expand Up @@ -162,6 +164,14 @@ pub fn register_inst_matchers_function_signatures(map: &mut HashMap<&'static str
},
);

map.insert(
"m_has_n_uses",
Signature {
parameters: vec![Box::new(InstMatcherType), Box::new(IntType)],
return_type: Box::new(InstMatcherType),
},
);

register_arithmetic_matchers_function_signatures(map);
register_int_comparisons_matchers_function_signatures(map);
register_float_comparisons_matchers_function_signatures(map);
Expand Down Expand Up @@ -276,8 +286,9 @@ fn match_unused(values: &[Box<dyn Value>]) -> Box<dyn Value> {
.matcher
.clone();

let usage_matcher = UsageInstMatcher::create_unused_matcher(matcher);
Box::new(InstMatcherValue {
matcher: Box::new(HasOneUseInstMatcher { matcher }),
matcher: usage_matcher,
})
}

Expand All @@ -289,7 +300,23 @@ fn match_has_one_use(values: &[Box<dyn Value>]) -> Box<dyn Value> {
.matcher
.clone();

let usage_matcher = UsageInstMatcher::create_has_one_use_matcher(matcher);
Box::new(InstMatcherValue {
matcher: usage_matcher,
})
}

fn match_has_n_uses(values: &[Box<dyn Value>]) -> Box<dyn Value> {
let matcher = values[0]
.as_any()
.downcast_ref::<InstMatcherValue>()
.unwrap()
.matcher
.clone();

let usage_count = values[1].as_int().unwrap() as usize;
let usage_matcher = UsageInstMatcher::create_has_n_uses_matcher(matcher, usage_count);
Box::new(InstMatcherValue {
matcher: Box::new(HasOneUseInstMatcher { matcher }),
matcher: usage_matcher,
})
}
39 changes: 33 additions & 6 deletions src/matchers/instruction_matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1131,26 +1131,53 @@ impl InstMatcher for UnusedMatcher {
}
}

/// Instruction Matcher to check if the value is used only once or not
#[derive(Clone)]
pub struct HasOneUseInstMatcher {
pub struct UsageInstMatcher {
pub matcher: Box<dyn InstMatcher>,
pub count: usize,
}

impl InstMatcher for HasOneUseInstMatcher {
impl UsageInstMatcher {
pub fn create_unused_matcher(matcher: Box<dyn InstMatcher>) -> Box<dyn InstMatcher> {
Box::new(UsageInstMatcher { matcher, count: 0 })
}

pub fn create_has_one_use_matcher(matcher: Box<dyn InstMatcher>) -> Box<dyn InstMatcher> {
Box::new(UsageInstMatcher { matcher, count: 1 })
}

pub fn create_has_n_uses_matcher(
matcher: Box<dyn InstMatcher>,
n: usize,
) -> Box<dyn InstMatcher> {
Box::new(UsageInstMatcher { matcher, count: n })
}
}

impl InstMatcher for UsageInstMatcher {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn is_match(&self, instruction: LLVMValueRef) -> bool {
unsafe {
// The instruction itself is not matches
if !self.matcher.is_match(instruction) {
return false;
}

let first_use = LLVMGetFirstUse(instruction);

// It's not used
if first_use.is_null() {
return false;
return self.count == 0;
}
let next_use = LLVMGetNextUse(first_use);
next_use.is_null()

let mut number_of_usage = 1;
let mut next_use = LLVMGetNextUse(first_use);
while !next_use.is_null() {
number_of_usage += 1;
next_use = LLVMGetNextUse(next_use);
}

self.count == number_of_usage
}
}
}

0 comments on commit 6fbfb89

Please sign in to comment.