-
Notifications
You must be signed in to change notification settings - Fork 0
/
max_short.asm
174 lines (137 loc) · 3.42 KB
/
max_short.asm
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
section .text
global _max_short
; функция выбирает максимум из 4 переданных ей чисел
; все числа типа short
_max_from_4:
mov ax, [esp + 4]
cmp ax, [esp + 6]
jge check_3
mov ax, [esp + 6]
check_3:
cmp ax, [esp + 8]
jge check_4
mov ax, [esp + 8]
check_4:
cmp ax, [esp + 10]
jge finish_check
mov ax, [esp + 10]
finish_check:
ret
; функция обрабатывает "хвост" массива (от 0 до 3 элементов)
; сигнатура:
; process_tail(short cur_res, short* ptr_to_tail, int tail_size)
_process_tail
push ebx
; на стеке лежит ebx, ко всем адресам на стеке прибавляется 4
; в ax храним максимум
mov ax, [esp + 8]
xor ecx, ecx
mov edx, [esp + 10]
; edx - указатель на начало хвоста
loop_tail:
cmp ecx, [esp + 14]
jge ret_tail
mov bx, [edx + ecx * 2]
; bx - текущее число
; каждое из чисел - short, так что ходим по памяти с шагом 2
cmp ax, bx
jge finish_cur_tail_update
mov ax, bx
finish_cur_tail_update:
inc ecx
jmp loop_tail
ret_tail:
pop ebx
ret
; функция выбирает максимум из массива чисел типа short
; len > 0
_max_short:
mov eax, [esp + 4]
mov [ARRAY], eax
mov eax, [esp + 8]
mov [LEN], eax
cmp dword [LEN], 4
jge not_only_tail
; обработать от 1 до 3 элементов
push dword [LEN]
push dword [ARRAY]
mov edx, [ARRAY]
push word [edx]
; положить на стек первый элемент
call _process_tail
add esp, 10
; снять со стека аргументы функции
ret
; в ax ответ
not_only_tail
; инициализируем количество блоков и размер хвоста
xor edx, edx
mov eax, [LEN]
mov ecx, 4
div ecx
mov [BLOCKS], eax
mov [REM], edx
; eax - указатель на начало массива
; mm0 - текущие 4 максимальные элемента (основной набор)
; ecx - сколько блоков уже пройдено
mov eax, [ARRAY]
movq mm0, [eax]
mov ecx, 1
; цикл обработки текущего блока
process_block:
cmp ecx, [BLOCKS]
jge blocks_processed
; ходим по 8, так как 4 числа * 2 байта
; mm1 - текущие 4 элемента (текущий набор)
movq mm1, [eax + ecx * 8]
movq mm2, mm0
pcmpgtw mm2, mm1
; теперь mm2[i] = 0xFFFF, если mm0[i] > mm1[i],
; mm2[i] = 0x0000, если mm0[i] <= mm1[i]
pand mm0, mm2
; сохраняем большие элементы и зануляем меньшие (в основном наборе)
pandn mm2, mm1
; аналогично для текущего набора, теперь в mm2 хранятся нужные элементы
; из текущего набора
por mm0, mm2
; объединяем наборы
inc ecx
jmp process_block
blocks_processed:
; обработаны все блоки по 4 элемента
; выберем максимум из 4 чисел основного набора
; освободить на стеке место для 4 short'ов (4 * 2)
sub esp, 16
; записать на стек 4 числа из основного набора
; они запишутся с [esp] по [esp + 16] так,
; что [esp ... esp + 2) - первое число
; [esp + 2 ... esp + 4) - второе и тд
movq [esp], mm0
call _max_from_4
add esp, 16
; выбран максимум из 4 кандидатов (он в ax)
; теперь рассмотрим хвост
; edx - указатель на начало массива,
; прибавим к нему число обработанных байт
mov edx, [ARRAY]
; edx - указатель на начало хвоста
lea edx, [edx + ecx * 8]
push dword [REM]
push edx
push ax
call _process_tail
add esp, 10
; посчитали максимум с хвоста, ответ хранится в ax
; это и есть ответ для всего массива
; пометить все mm-регистры как свободные (для соблюдения конвенции вызова)
emms
ret
section .data
; указатель на начало массива short
ARRAY : dd 0
; длина массива
LEN : dd 0
; количество "блоков" по 4 числа
BLOCKS : dd 0
; остаток - размер "хвоста"
REM : dd 0