aboutsummaryrefslogtreecommitdiff
path: root/ft_list_sort.s
blob: a541bd8d8292ad772090306b44a29357012b7034 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
; **************************************************************************** ;
;                                                                              ;
;                                                         :::      ::::::::    ;
;    ft_list_sort.s                                     :+:      :+:    :+:    ;
;                                                     +:+ +:+         +:+      ;
;    By: cacharle <marvin@42.fr>                    +#+  +:+       +#+         ;
;                                                 +#+#+#+#+#+   +#+            ;
;    Created: 2019/11/22 21:03:52 by cacharle          #+#    #+#              ;
;    Updated: 2019/11/22 21:27:27 by cacharle         ###   ########.fr        ;
;                                                                              ;
; **************************************************************************** ;

global _ft_list_sort

%define NULL 0x0

; void ft_list_sort(t_list **begin_list, int (*cmp)(void*, void*));
_ft_list_sort:
	; t_list *slow   : rax = *begin_list
	; t_list *fast   : rbx = (*begin_list)->next
	; t_list *middle : rsp + 0

	; === base condition ===
	cmp  rdi, NULL
	je   FT_LIST_SORT_END              ; if begin_list == NULL return
	mov  rax, [rdi]
	cmp  rax, NULL
	je   FT_LIST_SORT_END              ; if *begin_list == NULL return
	mov  rbx, [rax + 8]
	cmp  rbx, NULL
	je   FT_LIST_SORT_END              ; if (*begin_list)->next == NULL return

	; === find list middle loop ===
FT_LIST_SORT_MIDDLE_LOOP:              ; do {
	mov  rbx, [rbx + 8]                ;     fast = fast->next
	cmp  rbx, NULL
	je   FT_LIST_SORT_MIDDLE_LOOP_END  ;     if fast == NULL break
	mov  rbx, [rbx + 8]                ;     fast = fast->next
	mov  rax, [rax + 8]                ;     slow = slow->next
	cmp  rbx, NULL
	jne  FT_LIST_SORT_MIDDLE_LOOP      ; } while (fast != NULL)
FT_LIST_SORT_MIDDLE_LOOP_END:

	; create a stack frame for local variable to store middle address
	push rbp
	mov  rbp, rsp
	sub  rsp, 8

	; store middle in [rbp - 8]
	mov  rcx, [rax + 8]
	mov  [rbp - 8], rcx
	mov  qword [rax + 8], NULL         ; slow->next = NULL

	; === sorting both child list ===
	push rdi
	push rsi
	call _ft_list_sort                 ; ft_list_sort(begin_list, cmp)
	lea  rdi, [rbp - 8]
	call _ft_list_sort                 ; ft_list_sort(&middle, cmp)
	pop  rsi
	pop  rdi

	; === merging sorted child ===
	push rdi
	push rsi
	mov  rdi, [rdi]                    ; arg_1 = *begin_list
	mov  rdx, rsi                      ; arg_3 = cmp
	mov  rsi, [rbp - 8]                ; arg_2 = middle
	call _st_merge_sorted_list
	pop  rsi
	pop  rdi
	mov  [rdi], rax                    ; *begin_list = st_merge_sorted_list(...);

	; restoring stack frame
	mov  rsp, rbp
	pop  rbp
FT_LIST_SORT_END:
	ret


; t_list *st_merge_sorted_list(t_list* l1, t_list* l2, int (*cmp)(void*, void*))
_st_merge_sorted_list:
	cmp  rdi, NULL
	je   MERGE_SORTED_LIST_RETURN_L2   ; if l1 == NULL return l2
	cmp  rsi, NULL
	je   MERGE_SORTED_LIST_RETURN_L1   ; if l2 == NULL return l1

	push rdi
	push rsi
	push rdx
	mov  rdi, [rdi + 0]                ; l1->data
	mov  rsi, [rsi + 0]                ; l2->data
	xor  rax, rax
	call rdx                           ; cmp
	pop  rdx
	pop  rsi
	pop  rdi

	cmp  eax, 0
	jl   MERGE_SORTED_LIST_L1_LT_L2

	; if l1 >= l2
	push rsi                           ; save l2
	mov  rsi, [rsi + 8]                ; l2 = l2->next
	call _st_merge_sorted_list         ; merge_sorted_list(l1, l2->next, cmp)
	pop  rsi                           ; restore rsi
	mov  [rsi + 8], rax
	mov  rax, rsi
	jmp  MERGE_SORTED_LIST_END
	; else
MERGE_SORTED_LIST_L1_LT_L2:
	push rdi
	mov  rdi, [rdi + 8]
	call _st_merge_sorted_list         ; merge_sort_list(l1->next, l2, cmp)
	pop  rdi
	mov  [rdi + 8], rax
	mov  rax, rdi
	jmp  MERGE_SORTED_LIST_END

MERGE_SORTED_LIST_RETURN_L1:
	mov  rax, rdi
	ret
MERGE_SORTED_LIST_RETURN_L2:
	mov  rax, rsi
MERGE_SORTED_LIST_END:
	ret