Доп задание №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. Инициализация регистров:

    • mov x0, %[n]: значение n загружается в регистр x0, используя mov.
    • sub x0, x0, #1: уменьшаем x0 на 1, используя sub, так как массив нумеруется с нуля.
  2. Метка 1: Начало внешнего цикла

    • 1:
  3. Установка начальных значений для флагов и индексов:

    • mov x1, #0: сбрасываем флаг обмена.
    • mov x2, #0: сбрасываем индекс для внутреннего цикла.
  4. Метка 2: Начало внутреннего цикла

    • 2:
  5. Загрузка элементов массива для сравнения:

    • 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.
  6. Сравнение и обмен элементов:

    • 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: устанавливаем флаг обмена.
  7. Метка 3: Продолжение внутреннего цикла

    • 3:
    • add x2, x2, #1: увеличиваем индекс x2.
    • cmp x2, x0: проверяем, достиг ли x2 конца массива.
    • blt 2b: если x2 меньше x0, повторяем внутренний цикл, сравниваем используя blt.
  8. Переход к следующему проходу внешнего цикла или завершение:

    • 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" // Разрешение изменения регистров
    );
}

Пояснения

  1. Инициализация регистров:

    • mov x0, %[arr]: перемещаем указатель на массив arr в регистр x0.
    • mov x1, %[rez]: перемещаем указатель на массив rez в регистр x1.
    • mov x2, #0: инициализируем индекс x2 в 0.
  2. Метка 1: Начало цикла

    • 1:
  3. Проверка условия завершения цикла:

    • cmp x2, %[n]: сравниваем индекс x2 с длиной массива n.
    • bge 2f: если x2 >= n, переходим к метке 2 (завершение цикла).
  4. Загрузка элемента массива и обновление счетчика:

    • 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]].
  1. Инкремент индекса и повтор цикла:

    • add x2, x2, #1: увеличиваем индекс x2.
    • b 1b: возвращаемся к метке 1 для следующего итерации.
  2. Метка 2: Завершение цикла

    • 2: