Skip to content

Commit

Permalink
feat: Implement m_inst_oneof, m_inst_allof Matchers
Browse files Browse the repository at this point in the history
  • Loading branch information
AmrDeveloper committed Dec 19, 2024
1 parent a3b2491 commit 7df70cd
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 22 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
steps:
- run: wget https://apt.llvm.org/llvm.sh
- run: chmod +x llvm.sh
- run: sudo ./llvm.sh 16
- run: sudo ./llvm.sh 18
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo clippy -- -D warnings
19 changes: 16 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ gitql-ast = "0.30.0"
gitql-parser = "0.32.0"
gitql-engine = "0.33.0"
gitql-cli = "0.33.0"
inkwell = { version = "0.5.0", features = ["llvm16-0"] }

inkwell = { version = "0.5.0", features = ["llvm18-0"] }

lineeditor = "0.4.1"
dyn-clone = "1.0.17"

Expand Down
7 changes: 7 additions & 0 deletions docs/InstructionMatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,10 @@ Instructions Matchers are functions that build a instruction matcher to match ag
| :----------: | :--------: | :---------: | :--------------------------------------------------: |
| m_invoke | () | InstMatcher | Build Inst Matcher that match invoke Instruction |
| m_landingpad | () | InstMatcher | Build Inst Matcher that match landingpad Instruction |

### Compound Instructions Matchers functions

| Function | Parameters | Return | Description |
| :----------: | :--------------------: | :---------: | :------------------------------------------------------------------------------: |
| m_inst_oneof | (inst: ...InstMatcher) | InstMatcher | Build Inst Matcher from list of matchers that return true if one of them matches |
| m_inst_allof | (inst: ...InstMatcher) | InstMatcher | Build Inst Matcher from list of matchers that return true if all of them matches |
68 changes: 68 additions & 0 deletions src/functions/matchers/compound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::collections::HashMap;

use gitql_ast::types::varargs::VarargsType;
use gitql_core::signature::Signature;
use gitql_core::signature::StandardFunction;
use gitql_core::values::base::Value;

use crate::ir::types::InstMatcherType;
use crate::ir::values::InstMatcherValue;
use crate::matchers::compound::CompoundInstMatcher;
use crate::matchers::InstMatcher;

#[inline(always)]
pub fn register_compound_matchers_function(map: &mut HashMap<&'static str, StandardFunction>) {
map.insert("m_inst_oneof", match_oneof_compound_inst);
map.insert("m_inst_allof", match_allof_compound_inst);
}

#[inline(always)]
pub fn register_compound_matchers_function_signatures(map: &mut HashMap<&'static str, Signature>) {
map.insert(
"m_inst_oneof",
Signature {
parameters: vec![
Box::new(InstMatcherType),
Box::new(VarargsType {
base: Box::new(InstMatcherType),
}),
],
return_type: Box::new(InstMatcherType),
},
);

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

fn match_oneof_compound_inst(values: &[Box<dyn Value>]) -> Box<dyn Value> {
let mut matchers: Vec<Box<dyn InstMatcher>> = vec![];
for value in values.iter() {
if let Some(inst_matcher) = value.as_any().downcast_ref::<InstMatcherValue>() {
matchers.push(inst_matcher.matcher.to_owned());
}
}
let matcher = Box::new(CompoundInstMatcher::create_one_of(matchers));
Box::new(InstMatcherValue { matcher })
}

fn match_allof_compound_inst(values: &[Box<dyn Value>]) -> Box<dyn Value> {
let mut matchers: Vec<Box<dyn InstMatcher>> = vec![];
for value in values.iter() {
if let Some(inst_matcher) = value.as_any().downcast_ref::<InstMatcherValue>() {
matchers.push(inst_matcher.matcher.to_owned());
}
}
let matcher = Box::new(CompoundInstMatcher::create_all_of(matchers));
Box::new(InstMatcherValue { matcher })
}
1 change: 1 addition & 0 deletions src/functions/matchers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod arithmetic;
pub mod binary;
pub mod compound;
pub mod constants;
pub mod exception;
pub mod fcmp;
Expand Down
2 changes: 1 addition & 1 deletion src/functions/matchers/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ fn match_array(values: &[Box<dyn Value>]) -> Box<dyn Value> {
.matcher;

let length = if values.len() == 2 {
Some(values[1].as_int().unwrap() as u32)
Some(values[1].as_int().unwrap() as u64)
} else {
None
};
Expand Down
4 changes: 4 additions & 0 deletions src/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use matchers::arithmetic::register_arithmetic_matchers_function_signatures;
use matchers::arithmetic::register_arithmetic_matchers_functions;
use matchers::binary::register_binary_inst_matchers_function_signatures;
use matchers::binary::register_binary_inst_matchers_functions;
use matchers::compound::register_compound_matchers_function;
use matchers::compound::register_compound_matchers_function_signatures;
use matchers::constants::register_constants_matchers_function_signatures;
use matchers::constants::register_constants_matchers_functions;
use matchers::exception::register_exception_inst_matchers_function_signatures;
Expand Down Expand Up @@ -50,6 +52,7 @@ pub fn llvm_ir_functions() -> &'static HashMap<&'static str, StandardFunction> {
register_shift_matchers_functions(&mut map);
register_binary_inst_matchers_functions(&mut map);
register_exception_inst_matchers_functions(&mut map);
register_compound_matchers_function(&mut map);
map
})
}
Expand All @@ -66,6 +69,7 @@ pub fn llvm_ir_function_signatures() -> HashMap<&'static str, Signature> {
register_shift_matchers_function_signatures(&mut map);
register_binary_inst_matchers_function_signatures(&mut map);
register_exception_inst_matchers_function_signatures(&mut map);
register_compound_matchers_function_signatures(&mut map);
map
}

Expand Down
59 changes: 59 additions & 0 deletions src/matchers/compound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use inkwell::llvm_sys::prelude::LLVMValueRef;

use super::InstMatcher;

#[derive(PartialEq, Clone)]
enum CompoundMatcherKind {
OneOf,
AllOf,
}

#[derive(Clone)]
pub struct CompoundInstMatcher {
matchers: Vec<Box<dyn InstMatcher>>,
matcher_kind: CompoundMatcherKind,
}

impl CompoundInstMatcher {
pub fn create_one_of(matchers: Vec<Box<dyn InstMatcher>>) -> Self {
CompoundInstMatcher {
matchers,
matcher_kind: CompoundMatcherKind::OneOf,
}
}

pub fn create_all_of(matchers: Vec<Box<dyn InstMatcher>>) -> Self {
CompoundInstMatcher {
matchers,
matcher_kind: CompoundMatcherKind::AllOf,
}
}
}

impl InstMatcher for CompoundInstMatcher {
fn is_match(&self, instruction: LLVMValueRef) -> bool {
let mut matches_count = 0;
for matcher in self.matchers.iter() {
let is_matches = matcher.is_match(instruction);

// If kind is `oneOf` and one if matches, return true
if is_matches && self.matcher_kind == CompoundMatcherKind::OneOf {
return true;
}

// If kind is `allOf` and one is not matches, return false
if !is_matches && self.matcher_kind == CompoundMatcherKind::AllOf {
return false;
}

if is_matches {
matches_count += 1;
}
}

match self.matcher_kind {
CompoundMatcherKind::OneOf => matches_count > 1,
CompoundMatcherKind::AllOf => matches_count == self.matchers.len(),
}
}
}
3 changes: 0 additions & 3 deletions src/matchers/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use super::InstMatcher;
pub struct ConstIntMatcher;

impl InstMatcher for ConstIntMatcher {
#[allow(deprecated)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn is_match(&self, instruction: LLVMValueRef) -> bool {
unsafe {
Expand All @@ -24,7 +23,6 @@ impl InstMatcher for ConstIntMatcher {
pub struct ConstFloatMatcher;

impl InstMatcher for ConstFloatMatcher {
#[allow(deprecated)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn is_match(&self, instruction: LLVMValueRef) -> bool {
unsafe {
Expand All @@ -39,7 +37,6 @@ impl InstMatcher for ConstFloatMatcher {
pub struct ConstPointerNullMatcher;

impl InstMatcher for ConstPointerNullMatcher {
#[allow(deprecated)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn is_match(&self, instruction: LLVMValueRef) -> bool {
unsafe {
Expand Down
1 change: 1 addition & 0 deletions src/matchers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ impl InstMatcher for AnyInstMatcher {

pub mod arithmetic;
pub mod binary;
pub mod compound;
pub mod constants;
pub mod exception;
pub mod fcmp;
Expand Down
12 changes: 7 additions & 5 deletions src/matchers/other.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::ffi::CStr;

use inkwell::llvm_sys;
use inkwell::llvm_sys::core::LLVMGetInstructionOpcode;
use inkwell::llvm_sys::core::LLVMGetOperand;
use inkwell::llvm_sys::core::LLVMGetValueKind;
use inkwell::llvm_sys::core::LLVMGetValueName2;
use inkwell::llvm_sys::core::LLVMTypeOf;
use inkwell::llvm_sys::prelude::LLVMValueRef;
use inkwell::llvm_sys::LLVMOpcode;
Expand Down Expand Up @@ -48,14 +48,15 @@ pub struct ArgumentMatcher {
}

impl InstMatcher for ArgumentMatcher {
#[allow(deprecated)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn is_match(&self, instruction: LLVMValueRef) -> bool {
unsafe {
let value_kind = LLVMGetValueKind(instruction);
if value_kind == LLVMValueKind::LLVMArgumentValueKind {
if let Some(name) = &self.name {
let label_value_name = llvm_sys::core::LLVMGetValueName(instruction);
let mut name_len: usize = 0;
let label_value_name =
LLVMGetValueName2(instruction, &mut name_len as *mut usize);
let name_str = CStr::from_ptr(label_value_name).to_str().unwrap();
let is_name_matches = name.eq(name_str);
if is_name_matches {
Expand All @@ -80,14 +81,15 @@ pub struct LabelInstMatcher {
}

impl InstMatcher for LabelInstMatcher {
#[allow(deprecated)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn is_match(&self, instruction: LLVMValueRef) -> bool {
unsafe {
let value_kind = LLVMGetValueKind(instruction);
if value_kind == LLVMValueKind::LLVMBasicBlockValueKind {
if let Some(name) = &self.name {
let label_value_name = llvm_sys::core::LLVMGetValueName(instruction);
let mut name_len: usize = 0;
let label_value_name =
LLVMGetValueName2(instruction, &mut name_len as *mut usize);
let name_str = CStr::from_ptr(label_value_name).to_str().unwrap();
return name.eq(name_str);
}
Expand Down
16 changes: 8 additions & 8 deletions src/matchers/types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use inkwell::llvm_sys;
use llvm_sys::core::LLVMGetArrayLength;
use inkwell::llvm_sys::core::LLVMGetArrayLength2;
use llvm_sys::core::LLVMGetElementType;
use llvm_sys::core::LLVMGetIntTypeWidth;
use llvm_sys::core::LLVMGetTypeKind;
Expand Down Expand Up @@ -115,7 +115,7 @@ impl TypeMatcher for PointerTypeMatcher {
#[derive(Clone)]
pub struct ArrayTypeMatcher {
pub base_matcher: Box<dyn TypeMatcher>,
pub length: Option<u32>,
pub length: Option<u64>,
}

impl TypeMatcher for ArrayTypeMatcher {
Expand All @@ -133,7 +133,7 @@ impl TypeMatcher for ArrayTypeMatcher {
}

if let Some(target_length) = self.length {
let length = LLVMGetArrayLength(llvm_type);
let length = LLVMGetArrayLength2(llvm_type);
return target_length == length;
}

Expand Down Expand Up @@ -195,7 +195,7 @@ mod tests {
use crate::matchers::AnyTypeMatcher;

use super::*;
use llvm_sys::core::LLVMArrayType;
use llvm_sys::core::LLVMArrayType2;
use llvm_sys::core::LLVMContextCreate;
use llvm_sys::core::LLVMDoubleTypeInContext;
use llvm_sys::core::LLVMFloatTypeInContext;
Expand Down Expand Up @@ -363,12 +363,12 @@ mod tests {
let context = unsafe { LLVMContextCreate() };

let i32t = unsafe { LLVMInt32TypeInContext(context) };
let i32t_array_10_n = unsafe { LLVMArrayType(i32t, 10) };
let i32t_array_20_n = unsafe { LLVMArrayType(i32t, 20) };
let i32t_array_10_n = unsafe { LLVMArrayType2(i32t, 10) };
let i32t_array_20_n = unsafe { LLVMArrayType2(i32t, 20) };

let i64t = unsafe { LLVMInt64TypeInContext(context) };
let i64t_array_10_n = unsafe { LLVMArrayType(i64t, 10) };
let i64t_array_20_n = unsafe { LLVMArrayType(i64t, 20) };
let i64t_array_10_n = unsafe { LLVMArrayType2(i64t, 10) };
let i64t_array_20_n = unsafe { LLVMArrayType2(i64t, 20) };

let i32_matcher = Box::new(IntTypeMatcher {
size: IntTypeSize::Size32,
Expand Down

0 comments on commit 7df70cd

Please sign in to comment.