From 1a4055a69a7ab9d2d8530e56d207be5b60680aae Mon Sep 17 00:00:00 2001 From: janis Date: Wed, 29 Oct 2025 00:39:23 +0100 Subject: [PATCH] memmove, vec_insert, vec_binary_search_by working and tested --- lang/src/lib.asm | 37 ++++++++++++++++++++++ lang/src/vec.asm | 80 +++++++++++++++++++++++++++++++---------------- lang/tests/vec.rs | 44 ++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 27 deletions(-) diff --git a/lang/src/lib.asm b/lang/src/lib.asm index 77dd8f3..4a83219 100644 --- a/lang/src/lib.asm +++ b/lang/src/lib.asm @@ -16,6 +16,7 @@ global strcmp global strchr global streq global memcpy +global memmove global memswap global eprint_str global exit @@ -162,6 +163,7 @@ strcmp: mov rax, 1 ret +;; a and b may be overlapping ;; Copy bytes from one memory location to another ;; rdi: destination pointer ;; rsi: source pointer @@ -182,7 +184,42 @@ memcpy: .done: ret +;; rdi: destination pointer +;; rsi: source pointer +;; rdx: number of bytes to move +memmove: + ; if dest < src { + cmp rdi, rsi + jb .forward + ; reverse + ; for i in (0..n).rev() { + mov r8, rdx +.rev_loop: + cmp r8, 0 + je .done + dec r8 + ; dest[i] = src[i]; + mov al, [rsi + r8] + mov [rdi + r8], al + jmp .rev_loop + ; } +.forward: + ; for i in 0..n { + xor r8, r8 +.fwd_loop: + cmp r8, rdx + jge .done + ; dest[i] = src[i]; + mov al, [rsi + r8] + mov [rdi + r8], al + inc r8 + jmp .fwd_loop + ; } +.done: + mov rax, rdi + ret +;; a and b must not be overlapping ;; Swap bytes between two memory locations ;; rdi: pointer to first memory location ;; rsi: pointer to second memory location diff --git a/lang/src/vec.asm b/lang/src/vec.asm index e1781ce..e30adf0 100644 --- a/lang/src/vec.asm +++ b/lang/src/vec.asm @@ -3,6 +3,7 @@ section .rdata section .text extern memcpy +extern memmove extern memswap extern oom extern panic @@ -127,21 +128,17 @@ vec_get: ;; rdi: pointer to Vec struct ;; rsi: pointer to data to push -;; rdx: size of data to push ;; fn vec_push(vec: *mut Vec, data: &[u8]) vec_push: push rbp mov rbp, rsp - ; if data.len() != vec.item_size panic(); - mov rax, [rdi + 24] - cmp rdx, rax - jne .panic ; let vec, ptr, size; sub rsp, 24 mov [rsp], rdi ; save vec mov [rsp + 8], rsi ; save data ptr - mov [rsp + 16], rdx ; save data size ; vec_try_grow(vec, size); + mov rsi, [rdi + 8] + inc rsi call vec_try_grow ; memcpy(&vec.data[vec.len], data, size); mov rax, [rsp] ; vec @@ -152,7 +149,8 @@ vec_push: add rax, rcx ; data + len * item_size mov rdi, rax ; dest ptr mov rsi, [rsp + 8] ; data ptr - mov rdx, [rsp + 16] ; data size + mov rax, [rsp] ; vec + mov rdx, [rax + 24] ; item_size call memcpy ; vec.len += 1; mov rax, [rsp] ; vec @@ -160,10 +158,6 @@ vec_push: add rsp, 24 pop rbp ret -.panic: - call panic - pop rbp - ret ;; rdi: pointer to Vec struct @@ -239,11 +233,14 @@ vec_swap: jge .panic ; a = a * item_size; - mov rax, [rdi + 24] ; item_size + mov rbx, [rdi + 24] ; item_size + mov rax, rdx + xor rdx, rdx mul rbx ; b * item_size mov [rsp + 16], rax ; b = b * item_size; mov rax, rsi + xor rdx, rdx mul rbx ; a * item_size mov [rsp + 8], rax @@ -308,16 +305,18 @@ vec_remove: .panic: call panic +;; essentially a reserve() function ;; rdi: pointer to Vec struct -;; fn vec_try_grow(vec: *mut Vec, push_size: usize) -> bool +;; rsi: desired size +;; fn vec_try_grow(vec: *mut Vec, new_size: usize) -> bool vec_try_grow: push rbp mov rbp, rsp push rbx mov rax, [rdi + 16] ; capacity mov rbx, [rdi + 8] ; len - cmp rbx, rax - jg .grow + cmp rsi, rax + jge .grow ; grow if new_size >= capacity pop rbx xor rax, rax pop rbp @@ -459,20 +458,47 @@ vec_find: vec_insert: push rbp mov rbp, rsp - sub rsp, 32 + push r12 + push rbx + sub rsp, 0x20 mov [rsp], rdi ; save vec mov [rsp + 8], rsi ; save index - mov [rsp + 16], rdx ; save data ptr + mov [rsp + 0x10], rdx ; save data ptr - mov rsi, rdx - mov rdx, rcx - call vec_push - mov rdi, [rsp] mov rsi, [rdi + 8] - sub rsi, 1 - mov rdx, [rsp + 8] - call vec_swap + inc rsi + call vec_try_grow + + mov rbx, [rsp] ; vec + mov rdi, [rbx] ; vec.data + mov rcx, [rbx + 24] ; item_size + mov rdx, [rbx + 8] ; len + sub rdx, [rsp + 8] ; len - index + mov rax, rdx + mul rcx ; (len - index) * item_size + mov r12, rax ; number of bytes to move + mov rsi, [rbx] ; vec.data + mov rax, [rsp + 8] ; index + mov rcx, [rbx + 24] ; item_size + mul rcx ; index * item_size + add rsi, rax ; src ptr + mov rdi, rsi + add rdi, rcx ; dst ptr + mov rdx, r12 ; number of bytes to move + call memmove + + mov rdi, rsi + mov rsi, [rsp + 0x10] + mov rdx, [rbx + 24] ; item_size + call memcpy + + mov rax, [rbx + 8] ; len + inc rax + mov [rbx + 8], rax + add rsp, 32 + pop rbx + pop r12 pop rbp ret @@ -502,7 +528,7 @@ vec_binary_search_by: mov rax, [rsp + 0x20] ; low mov rcx, [rsp + 0x30] ; high cmp rax, rcx - jge .not_found + jg .not_found ; mid = (low + high) / 2 sub rcx, rax shr rcx, 1 @@ -515,8 +541,8 @@ vec_binary_search_by: mul rdx ; mid * item_size add rax, rcx ; vec.data + mid * item_size mov rdi, [rsp + 0x18] ; compare ctx - mov rsi, rax - mov rdx, [rsp + 0x8] ; key + mov rsi, [rsp + 0x8] ; key + mov rdx, rax mov rax, [rsp + 0x10] ; compare fn call rax cmp eax, 0 diff --git a/lang/tests/vec.rs b/lang/tests/vec.rs index b1c36b9..44aa9bf 100644 --- a/lang/tests/vec.rs +++ b/lang/tests/vec.rs @@ -155,6 +155,36 @@ impl VecT { } } } + + fn binary_search_by(&self, elem: &T, mut cmp: F) -> Result + where + F: FnMut(&T, &T) -> i32, + { + extern "C" fn cmp_trampoline i32>( + f: *const (), + a: *const u8, + b: *const u8, + ) -> i32 { + let f = unsafe { &mut *(f as *mut F) }; + let a = unsafe { &*(a as *const T) }; + let b = unsafe { &*(b as *const T) }; + f(a, b) + } + + unsafe { + let index = vec_binary_search_by( + &raw const self.vec as *mut _, + elem as *const T as *const u8, + cmp_trampoline::, + &raw mut cmp as *mut F as *mut (), + ); + if (index as isize) < 0 { + Err(!index) + } else { + Ok(index) + } + } + } } #[unsafe(no_mangle)] @@ -282,4 +312,18 @@ fn main() { }), Some(1) ); + + assert_eq!(vec.as_slice(), &[20, 40, 50]); + vec.insert(30, 1); + assert_eq!(vec.as_slice(), &[20, 30, 40, 50]); + + let cmp = |a: &u32, b: &u32| match a.cmp(b) { + core::cmp::Ordering::Less => -1, + core::cmp::Ordering::Equal => 0, + core::cmp::Ordering::Greater => 1, + }; + assert_eq!(vec.binary_search_by(&25, cmp), Err(1)); + assert_eq!(vec.binary_search_by(&30, cmp), Ok(1)); + assert_eq!(vec.binary_search_by(&5, cmp), Err(0)); + assert_eq!(vec.binary_search_by(&55, cmp), Err(5)); }