From 7df70cd2153c7e038de8ebe12feac3c46069901e Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Thu, 19 Dec 2024 19:36:32 +0100 Subject: [PATCH] feat: Implement `m_inst_oneof`, `m_inst_allof` Matchers --- .github/workflows/ci.yaml | 2 +- Cargo.lock | 19 +++++++-- Cargo.toml | 4 +- docs/InstructionMatcher.md | 7 +++ src/functions/matchers/compound.rs | 68 ++++++++++++++++++++++++++++++ src/functions/matchers/mod.rs | 1 + src/functions/matchers/types.rs | 2 +- src/functions/mod.rs | 4 ++ src/matchers/compound.rs | 59 ++++++++++++++++++++++++++ src/matchers/constants.rs | 3 -- src/matchers/mod.rs | 1 + src/matchers/other.rs | 12 +++--- src/matchers/types.rs | 16 +++---- 13 files changed, 176 insertions(+), 22 deletions(-) create mode 100644 src/functions/matchers/compound.rs create mode 100644 src/matchers/compound.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index caeb560..d9714a4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -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 diff --git a/Cargo.lock b/Cargo.lock index d601caf..a2d8bd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" + [[package]] name = "autocfg" version = "1.4.0" @@ -389,14 +395,15 @@ dependencies = [ [[package]] name = "llvm-sys" -version = "160.2.1" +version = "180.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e73861901245d32e1c3d8b35b639cf100859b4cd0c9da56fe0273040acbb3ea4" +checksum = "778fa5fa02e32728e718f11eec147e6f134137399ab02fd2c13d32476337affa" dependencies = [ + "anyhow", "cc", "lazy_static", "libc", - "regex", + "regex-lite", "semver", ] @@ -562,6 +569,12 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" version = "0.8.5" diff --git a/Cargo.toml b/Cargo.toml index 977f416..652f4ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/docs/InstructionMatcher.md b/docs/InstructionMatcher.md index 74b9f6f..cdd1b16 100644 --- a/docs/InstructionMatcher.md +++ b/docs/InstructionMatcher.md @@ -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 | \ No newline at end of file diff --git a/src/functions/matchers/compound.rs b/src/functions/matchers/compound.rs new file mode 100644 index 0000000..452ca13 --- /dev/null +++ b/src/functions/matchers/compound.rs @@ -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]) -> Box { + let mut matchers: Vec> = vec![]; + for value in values.iter() { + if let Some(inst_matcher) = value.as_any().downcast_ref::() { + 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]) -> Box { + let mut matchers: Vec> = vec![]; + for value in values.iter() { + if let Some(inst_matcher) = value.as_any().downcast_ref::() { + matchers.push(inst_matcher.matcher.to_owned()); + } + } + let matcher = Box::new(CompoundInstMatcher::create_all_of(matchers)); + Box::new(InstMatcherValue { matcher }) +} diff --git a/src/functions/matchers/mod.rs b/src/functions/matchers/mod.rs index 4341913..4928178 100644 --- a/src/functions/matchers/mod.rs +++ b/src/functions/matchers/mod.rs @@ -1,5 +1,6 @@ pub mod arithmetic; pub mod binary; +pub mod compound; pub mod constants; pub mod exception; pub mod fcmp; diff --git a/src/functions/matchers/types.rs b/src/functions/matchers/types.rs index de6cc23..e561eec 100644 --- a/src/functions/matchers/types.rs +++ b/src/functions/matchers/types.rs @@ -251,7 +251,7 @@ fn match_array(values: &[Box]) -> Box { .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 }; diff --git a/src/functions/mod.rs b/src/functions/mod.rs index 8601d4d..a943b33 100644 --- a/src/functions/mod.rs +++ b/src/functions/mod.rs @@ -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; @@ -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 }) } @@ -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 } diff --git a/src/matchers/compound.rs b/src/matchers/compound.rs new file mode 100644 index 0000000..464a339 --- /dev/null +++ b/src/matchers/compound.rs @@ -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>, + matcher_kind: CompoundMatcherKind, +} + +impl CompoundInstMatcher { + pub fn create_one_of(matchers: Vec>) -> Self { + CompoundInstMatcher { + matchers, + matcher_kind: CompoundMatcherKind::OneOf, + } + } + + pub fn create_all_of(matchers: Vec>) -> 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(), + } + } +} diff --git a/src/matchers/constants.rs b/src/matchers/constants.rs index bae714a..1b629bf 100644 --- a/src/matchers/constants.rs +++ b/src/matchers/constants.rs @@ -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 { @@ -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 { @@ -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 { diff --git a/src/matchers/mod.rs b/src/matchers/mod.rs index 6ee4bda..b22c422 100644 --- a/src/matchers/mod.rs +++ b/src/matchers/mod.rs @@ -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; diff --git a/src/matchers/other.rs b/src/matchers/other.rs index 2663961..45c7ed0 100644 --- a/src/matchers/other.rs +++ b/src/matchers/other.rs @@ -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; @@ -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 { @@ -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); } diff --git a/src/matchers/types.rs b/src/matchers/types.rs index f3cf7b7..9ded47d 100644 --- a/src/matchers/types.rs +++ b/src/matchers/types.rs @@ -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; @@ -115,7 +115,7 @@ impl TypeMatcher for PointerTypeMatcher { #[derive(Clone)] pub struct ArrayTypeMatcher { pub base_matcher: Box, - pub length: Option, + pub length: Option, } impl TypeMatcher for ArrayTypeMatcher { @@ -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; } @@ -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; @@ -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,