collatz_problem solved (GAS) x8664 (64)

This commit is contained in:
Bedir Tuğra Karaabalı 2025-08-27 18:47:47 +03:00
parent 0a1d4fbb2e
commit 15e539be18
2 changed files with 107 additions and 11 deletions

100
collatz.S
View File

@ -3,9 +3,42 @@
# collatz problem
.text
# void collatz_len_and_peek(uint64_t x, uint64_t *steps, uint64_t *peek)
.global collatz_len_and_peek
collatz_len_and_peek:
# void collatz_len_and_peak(uint64_t x, uint64_t *steps, uint64_t *peak)
.global collatz_len_and_peak
.global scan_upto
# bu makrolar yukardaki belirlediğim stack'e çok bağlı yani %rbp relative
# bu demek oluyor ki stack değişirse bu makrolar da değişmek zorunda
# daha esnek bir tasarım offset eklemek olurdu
.macro save_registers base
movq %rax, -96(%\base)
movq %rcx, -88(%\base)
movq %rdx, -80(%\base)
movq %rsi, -72(%\base)
movq %rdi, -64(%\base)
movq %r8, -56(%\base)
movq %r9, -48(%\base)
movq %r10, -40(%\base)
movq %r11, -32(%\base)
.endm
.macro restore_registers base
movq -96(%\base), %rax
movq -88(%\base), %rcx
movq -80(%\base), %rdx
movq -72(%\base), %rsi
movq -64(%\base), %rdi
movq -56(%\base), %r8
movq -48(%\base), %r9
movq -40(%\base), %r10
movq -32(%\base), %r11
.endm
collatz_len_and_peak:
# Collatz problem implementation
# x -> rdi, steps -> rsi, peak -> rdx
@ -19,17 +52,70 @@ collatz_len_and_peek:
testq $1, %r8 # 1 and n
jz .even
# odd case
leaq (%r8, %r8, 2), %r8 # n *= 3 -> lea base + index * scale
addq $1,%r8 # n += 1
leaq 1(%r8, %r8, 2), %r8 # n *= 3 -> lea ( base + index * scale )
jmp .next_step
.even:
shrq $1, %r8 # n /= 2
.next_step:
cmpq (%rdx), %r8 # if (n > *peek) n - *peek
cmpq (%rdx), %r8 # if (n > *peak) n - *peak
jle .next
movq %r8, (%rdx) # *peek = n
movq %r8, (%rdx) # *peak = n
.next:
addq $1, (%rsi) # (*steps)++
jmp .loop
.done:
ret
# void scan_upto(uint64_t N, uint64_t *best_n, uint64_t *best_steps, uint64_t *best_peak, uint64_t *xor_steps)
scan_upto:
pushq %rbp
movq %rsp, %rbp
subq $104, %rsp # burda stack de local değişkenler tutulcak makro için 80 byte + 16 byte local değişkenler ama
# hizalamak da gerekiyor
# başlatma initialize
# rdi rsi rdx rcx r8
movq $1, (%rsi) # *best_n = 1
movq $0, (%rdx) # *best_steps = 0
movq $1, (%rcx) # *best_peak = 1
movq $0, (%r8) # *xor_steps = 0
movq $1, %r9 # n = 1
.loop_scan:
cmpq %rdi, %r9 # if (n <= N)
jg .done_scan
# local değişkenler
movq $0, -8(%rbp) # steps = 0
movq $0, -16(%rbp) # peak = 0
# şimdi fonksiyon çağırcam ama register sırasını korumam lazım bunlar
# caller-saved olduğu için diper fonksiyonda korunmazlar ve değişiler bu yüzden
# hali hazırda kullandığım registerları stack e vermem lazım
# ama bunu makro olarak yazmak istiyorum bir daha kullanmıycak olsamda
save_registers rbp
movq %r9, %rdi # n
leaq -8(%rbp), %rsi # steps
leaq -16(%rbp), %rdx # peak
call collatz_len_and_peak
restore_registers rbp
movq (%r8), %r11 # r11 = *xor_steps
xorq -8(%rbp), %r11 # *xor_steps ^= steps
movq %r11, (%r8) # *xor_steps = r11
movq (%rdx), %r11 # r11 = *best_steps
movq -8(%rbp), %r10 # r10 = steps
cmpq %r11, %r10 # if (steps > *best_steps)
jle .incr
movq %r9,(%rsi) # *best_n = n
movq %r10, (%rdx) # *best_steps = r10
movq -16(%rbp), %r11 # r11 = peak
movq %r11, (%rcx) # *best_peak = r11
.incr:
incq %r9
jmp .loop_scan
.done_scan:
leave
ret

18
main.c
View File

@ -1,11 +1,21 @@
#include <stdint.h>
#include <stdio.h>
void collatz_len_and_peek(uint64_t x, uint64_t *steps, uint64_t *peek);
void collatz_len_and_peak(uint64_t x, uint64_t *steps, uint64_t *peak);
void scan_upto(uint64_t N, uint64_t *best_n, uint64_t *best_steps, uint64_t *best_peak, uint64_t *xor_steps);
int main() {
uint64_t steps, peak;
collatz_len_and_peek(13, &steps, &peak);
printf("steps=%lu, peak=%lu\n", steps, peak);
printf("hello world!\n");
uint64_t N = 1000000;
uint64_t best_n, best_steps, best_peak, xor_steps;
scan_upto(N, &best_n, &best_steps, &best_peak, &xor_steps);
printf("collatz_longest(1..%lu)\n", N);
printf("n*=%lu\n", best_n);
printf("steps=%lu\n", best_steps);
printf("peak=%lu\n", best_peak);
printf("xor_steps=%lu\n", xor_steps);
return 0;
}