Примеры кода QBE IL — различия между версиями
Admin (обсуждение | вклад) (Новая страница: «== Операции и операнды == Рассмотрим некоторые операции и операнды в QBE. Подробнее можно…») |
(нет различий)
|
Версия 20:25, 19 марта 2018
Операции и операнды
Рассмотрим некоторые операции и операнды в QBE.
Подробнее можно прочитать в разделе Арифметические и битовые операции. Обычная арифметика - сложение (add), вычитание (sub), деление (div), умножение (mul). Каждая из этих операций требует два аргумента/операнда (очевидно).
Примеры.
add 0, 1
К нулю (первое слагаемое/первый аргумент/операнд) прибавляется единица (второе слагаемое/второй аргумент/операнд). Результатом сложения (сумма) будет число 1.
sub 2, 1
Из двойки (уменьшаемое/первый аргумент/операнд) вычитается единица (вычитаемое/второй аргумент/операнд). Результатом вычитания (разностью) будет число 1.
div 4, 2
Четыре (делимое/первый аргумент/операнд) делится на два (делитель/второй аргумент/операнд). Результатом деления (частным) будет число 2.
mul 2, 2
Два (первый множитель/первый аргумент/операнд) умножается на два (второй множитель/второй аргумент/операнд). Результатом умножения (произведением) будет число 4.
Аналогично для логических операций. Для операций сдвига справедливо требование наличие двух аргументов/операндов. В этом случае первый аргумент/операнд будет являться тем, что требуется "сдвинуть", а второй – числом (целым), на которое требуется осуществить сдвиг.
Операции над памятью.
Основные операции для работы с памятью, которые могут понадобиться Вам для взаимодействия с массивами данных – store
и load
. Особенности применения описаны в соответствующей статье, как на данном ресурсе, так и в оригинальной документации. Приведем пример использования этих команд.
storeb 0, %array
Разместит в первый байт массива array
(то есть %array
выступает аналогом array[0]
) число 0. Суффикс b
на конце инструкции store
свидетельствует о типе используемых операндов.
loadub %array
Результатом выполнения инструкции будет усеченное до unsigned (беззнаковое) значение первого байта массива array
. Суффиксы u
и b
означают unsigned (беззнаковое) и byte (байт) соответственно. То есть суффиксы инструкции load
накладывают ограничение на возвращаемый результат.
Подробнее о работе с массивами будет рассказано ниже.
Присваивания
Пример кода на Си.
int a = 1; int b = 2; int c; c = a + b;
Аналогичный код на QBE IL.
%a = w add 0, 1 %b = w add 0, 2 %c = w add %a, %b
Блоки
@start %b = w add 0, 5 @initA %a = w add 0, 1 @initB %b = w add 0, 2 @result %c = w add %a, %b @end ret 0
Результатом выполнения будет c = 3
, а без наличия переходов между блоками каждая инструкция будет выполняться последовательно. То есть в блоке @start
в переменную b
будет помещено число 5. Затем мы попадем в блок @initA
, где объявим переменную a
и положим в нее число 1. Далее, в блоке @initB
уже размещенное в переменной b
будет заменено на число 2. В блоке @result
объявляется переменная c
и инициализируется суммой переменных a
и b
, эта сумма будет равна 3 (1+2). Блок @end
осуществит выход из функции.
Сравнения
Вы можете найти более подробную информацию в разделе Сравнения. Все сравнения, реализованные в промежуточном языке практически идентичны сравнениям в языке ассемблера. Главным образом, сравнения применяются для осуществления управления условными переходами (представлено ниже). В промежуточном языке представлено несколько видов сравнения для разных типов данных: сравнение на равенство аргументов/операндов, сравнение на неравенство аргументов/операндов, сравнение на "больше или равно", сравнение на "меньше или равно", сравнение на "меньше", сравнение на "больше".
%condition = w cslew %a, %b
Данный пример сравнивает две переменных размерности w (word) (о чем свидетельствует окончание инструкции - w
) на "меньше или равно" (суффикс le
означает "lower or equal") и возвращает 0 размерности w (word) в случае, если %b
больше %a
, либо 1 размерности w (word) в случае положительного выполнения условий суффикса.
Переходы
Рассмотрим код из предыдущего примера с "Блоками", но внесем одно изменение – установим безусловный переход jmp
на другой блок в блоке @initA
.
@start %b = w add 0, 5 @initA %a = w add 0, 1 jmp @result @initB %b = w add 0, 2 @result %c = w add %a, %b @end ret 0
При выполнении, с помощью jmp @result
после объявления переменной a
выполнение продолжится не последовательно (в блоке @initB
), а с блока @result
. То есть c = 1 + 5
(не произойдет переприсваивания b = 2
), тем самым, результатом в c
будет являться число 6.
Заменим безусловный переход jmp @result
из примера выше на переход по условию %condition
, которое добавим перед переходом.
@start %b = w add 0, 5 @initA %a = w add 0, 1 %condition = w cslew %a, 2 jnz %condition, @result, @initB @initB %b = w add 0, 2 @result %c = w add %a, %b @end ret 0
В данном случае, условие %condition = w cslew %a, 2
всегда будет выполняться, а переход jnz %condition, @result, @initB
всегда будет переходить на ветвь @result
. Но если сравнение, например, в @initA
в переменную %a
положить не 1, а 3, то условие будет всегда ложным, тогда переход будет всегда выполняться на ветвь @initB
, и результатом выполнения программы будет %c = 3 (т.к. a = 3) + 2 (т.к. в b будет лежать 2) = 5
Массивы
Предположим, у нас имеется массив байтов array
неопределенного размера и некоторое целое беззнаковое число N. Для работы с N-ным элементом массива придется завести дополнительную переменную (дабы не утратить указатель на первые N элементов), в которой будет размещена сумма адреса первого элемента массива и сдвига на N байт.
%arrayN = l add %array, %N
Теперь с помощью arrayN
и инструкций load
и store
можно получить и записать (соответственно) в N-ный элемент массива array
.