кодДоп задание №1
Условие
Создать программу на языке С, которая считывает из файла целые числа. Необходимо написать ассемблерную вставку, осуществляющую сортировку массива. Метод сортировки определяет разработчик. Вставка должна быть вынесена в отдельную функцию. Использовать глобальные переменные для передачи данных в указанную функию запрещено. Полученный массив записать в файл вывода.
Входные данные
Первая строка входного файла INPUT.TXT содержит одно целое число N (1 ≤ N ≤ 100). В следующих N строках содержатся числа, по модулю не превышающие 10^9.
Содержание отчета по работе
Link to original
- Условие программы;
- Текст программы.
Функция сортировки
Начнем с функции sort
, которая выполняет сортировку массива методом пузырька с использованием ассемблерных вставок.
void sort(long long *arr, long long n) {
__asm__ (
"mov x0, %[n]\n" // Перемещение значения n в регистр x0
"sub x0, x0, #1\n" // Уменьшение x0 на 1 (так как массив с 0 индексацией)
"1:\n" // Метка 1 для начала внешнего цикла
"mov x1, #0\n" // Инициализация флага обмена x1 в 0
"mov x2, #0\n" // Инициализация индекса x2 в 0
"2:\n" // Метка 2 для начала внутреннего цикла
"ldr x3, [%[arr], x2, lsl #3]\n" // Загрузка arr[x2] в регистр x3 (x2 сдвинут на 3 бита, так как элемент long long)
"add x4, x2, #1\n" // Инкремент x4 = x2 + 1
"ldr x5, [%[arr], x4, lsl #3]\n" // Загрузка arr[x4] в регистр x5
"cmp x3, x5\n" // Сравнение arr[x2] и arr[x4]
"ble 3f\n" // Переход к метке 3, если arr[x2] <= arr[x4]
"str x5, [%[arr], x2, lsl #3]\n" // Обмен элементов arr[x2] и arr[x4]
"str x3, [%[arr], x4, lsl #3]\n"
"mov x1, #1\n" // Установка флага обмена в 1
"3:\n" // Метка 3: продолжение внутреннего цикла
"add x2, x2, #1\n" // Инкремент x2
"cmp x2, x0\n" // Проверка конца внутреннего цикла
"blt 2b\n" // Переход к метке 2, если x2 < x0
"sub x0, x0, #1\n" // Уменьшение x0 для следующего прохода внешнего цикла
"cbnz x1, 1b\n" // Переход к метке 1, если был хотя бы один обмен
: // Пустой список выходных операндов
: [arr] "r"(arr), [n] "r"(n) // Входные операнды: arr и n
: "x0", "x1", "x2", "x3", "x4", "x5" // Разрешение изменения регистров
);
}
Пояснения
-
Инициализация регистров:
-
Метка 1: Начало внешнего цикла
1:
-
Установка начальных значений для флагов и индексов:
mov x1, #0
: сбрасываем флаг обмена.mov x2, #0
: сбрасываем индекс для внутреннего цикла.
-
Метка 2: Начало внутреннего цикла
2:
-
Загрузка элементов массива для сравнения:
ldr x3, [%[arr], x2, lsl #3]
: загружаемarr[x2]
в регистрx3
, используя ldr, адресную арифметику и lsl.add x4, x2, #1
: увеличиваемx4
на 1, используя add.ldr x5, [%[arr], x4, lsl #3]
: загружаемarr[x4]
в регистрx5
.
-
Сравнение и обмен элементов:
cmp x3, x5
: сравниваемarr[x2]
иarr[x4]
, используя cmp.ble 3f
: еслиarr[x2] <= arr[x4]
, переходим к метке 3, используя ble.str x5, [%[arr], x2, lsl #3]
: еслиarr[x2] > arr[x4]
, меняем местамиarr[x2]
иarr[x4]
, сравниваем используя str.str x3, [%[arr], x4, lsl #3]
mov x1, #1
: устанавливаем флаг обмена.
-
Метка 3: Продолжение внутреннего цикла
3:
add x2, x2, #1
: увеличиваем индексx2
.cmp x2, x0
: проверяем, достиг лиx2
конца массива.blt 2b
: еслиx2
меньшеx0
, повторяем внутренний цикл, сравниваем используя blt.
-
Переход к следующему проходу внешнего цикла или завершение:
sub x0, x0, #1
: уменьшаемx0
для следующего прохода.cbnz x1, 1b
: если был обмен (cbnz), возвращаемся к метке 1.
Функция подсчета
Теперь рассмотрим функцию count
, которая подсчитывает количество вхождений каждого элемента массива.
void count(long long *arr, long long *rez, long long n) {
__asm__ (
"mov x0, %[arr]\n" // Перемещение указателя на массив arr в регистр x0
"mov x1, %[rez]\n" // Перемещение указателя на массив rez в регистр x1
"mov x2, #0\n" // Инициализация индекса x2 в 0
"1:\n" // Метка 1 для начала цикла
"cmp x2, %[n]\n" // Сравнение x2 с n
"bge 2f\n" // Переход к метке 2, если x2 >= n
"ldr x3, [x0, x2, lsl #3]\n"// Загрузка arr[x2] в регистр x3
"ldr x4, [x1, x3, lsl #3]\n"// Загрузка rez[arr[x2]] в регистр x4
"add x4, x4, #1\n" // Инкремент значения rez[arr[x2]]
"str x4, [x1, x3, lsl #3]\n"// Сохранение обновленного значения в rez[arr[x2]]
"add x2, x2, #1\n" // Инкремент индекса x2
"b 1b\n" // Переход к метке 1
"2:\n" // Метка 2: завершение цикла
: // Пустой список выходных операндов
: [arr] "r"(arr), [rez] "r"(rez), [n] "r"(n) // Входные операнды: arr, rez и n
: "x0", "x1", "x2", "x3", "x4" // Разрешение изменения регистров
);
}
Пояснения
-
Инициализация регистров:
mov x0, %[arr]
: перемещаем указатель на массивarr
в регистрx0
.mov x1, %[rez]
: перемещаем указатель на массивrez
в регистрx1
.mov x2, #0
: инициализируем индексx2
в 0.
-
Метка 1: Начало цикла
1:
-
Проверка условия завершения цикла:
cmp x2, %[n]
: сравниваем индексx2
с длиной массиваn
.bge 2f
: еслиx2
>=n
, переходим к метке 2 (завершение цикла).
-
Загрузка элемента массива и обновление счетчика:
ldr x3, [x0, x2, lsl #3]
:
загружаем arr[x2]
в регистр x3
.
ldr x4, [x1, x3, lsl #3]
: загружаемrez[arr[x2]]
в регистрx4
.add x4, x4, #1
: увеличиваем значениеrez[arr[x2]]
.str x4, [x1, x3, lsl #3]
: сохраняем обновленное значение вrez[arr[x2]]
.
-
Инкремент индекса и повтор цикла:
add x2, x2, #1
: увеличиваем индексx2
.b 1b
: возвращаемся к метке 1 для следующего итерации.
-
Метка 2: Завершение цикла
2: