diff --git a/lang/src/int_to_str.asm b/lang/src/int_to_str.asm index a28fe73..fa0543a 100644 --- a/lang/src/int_to_str.asm +++ b/lang/src/int_to_str.asm @@ -1,6 +1,73 @@ section .text global int_to_str global int_to_str2 +global str_to_int + +;; rdi: pointer to input string +;; rsi: length of input string +;; dl: radix +;; fn str_to_int(s: *const u8, len: usize, radix: u8) -> i64 +str_to_int: + push rbp + mov rbp, rsp + push r12 + push r13 + sub rsp, 0x10 + mov qword [rsp], 0 ; result = 0 + mov [rsp + 8], dl ; multiplier = radix + + xor r12, r12 ; r12 = index +.loop: + cmp r12, rsi + jge .epilogue + mov rax, [rsp] + movzx rcx, byte [rsp + 8] + xor rdx, rdx + imul rcx + jo .overflow ; overflow + mov [rsp], rax + + mov al, byte [rdi + r12] + cmp al, '_' + je .skip_underscore + cmp al, '9' + ja .check_alpha + cmp al, '0' + jb .not_a_digit + sub al, '0' + jmp .digit_parsed +.check_alpha: + cmp al, 'a' + jb .not_a_digit + cmp al, 'f' + ja .not_a_digit + sub al, 'a' - 10 + jmp .digit_parsed +.digit_parsed: + cmp al, byte [rsp + 8] + ja .not_a_digit + movzx rax, al + add [rsp], rax + +.skip_underscore: + inc r12 + jmp .loop + +.not_a_digit: + mov qword [rsp], 0 + jmp .epilogue +.overflow: + mov rax, -1 + shr rax, 1 + mov qword [rsp], rax + +.epilogue: + mov rax, [rsp] + add rsp, 0x10 + pop r13 + pop r12 + pop rbp + ret ;; rdi: input integer ;; rsi: pointer to output buffer (at least 21 bytes) diff --git a/lang/tests/int_to_str.rs b/lang/tests/int_to_str.rs index 0f3b73d..87db35f 100644 --- a/lang/tests/int_to_str.rs +++ b/lang/tests/int_to_str.rs @@ -20,6 +20,7 @@ impl FFISlice { unsafe extern "C" { unsafe fn int_to_str2(value: isize, buffer: *mut u8, buffer_len: usize, radix: u8) -> FFISlice; + unsafe fn str_to_int(s: *const u8, len: usize, radix: u8) -> isize; } fn main() { @@ -51,5 +52,29 @@ fn main() { let s = slice.as_str(); println!("Integer: {:b}, String: {}", value, s); assert_eq!(s, format!("{value:b}")); + + let s = "1234567890"; + let parsed = str_to_int(s.as_ptr(), s.len(), 10); + println!("String: {}, Integer: {}", s, parsed); + assert_eq!(parsed, 1234567890isize); + + let s = "499602d2"; + let parsed = str_to_int(s.as_ptr(), s.len(), 16); + println!("String: {}, Integer: {}", s, parsed); + assert_eq!(parsed, 1234567890isize); + + let s = "11145401322"; + let parsed = str_to_int(s.as_ptr(), s.len(), 8); + println!("String: {}, Integer: {}", s, parsed); + assert_eq!(parsed, 1234567890isize); + let s = "11101011"; + let parsed = str_to_int(s.as_ptr(), s.len(), 2); + println!("String: {}, Integer: {}", s, parsed); + assert_eq!(parsed, 235isize); + + let s = "9999999999999999999999999999999999999999"; + let parsed = str_to_int(s.as_ptr(), s.len(), 10); + println!("String: {}, Integer: {}", s, parsed); + assert_eq!(parsed, isize::MAX); } }