Открыть сервис

Трёхадресная команда

Трёхадресная команда (трёхадресный код, трёхоперандная команда) — это форма записи машинных инструкций или промежуточного кода, в которой команда содержит три адресных поля, указывающих на операнды (обычно два источника и один приёмник результата). Является распространённой архитектурой набора команд (ISA), особенно в RISC-процессорах, а также в промежуточных представлениях компиляторов и виртуальных машинах.

История

Развитие трёхадресных команд тесно связано с эволюцией вычислительной техники и архитектур процессоров. Ранние компьютеры, такие как IAS-машина (1945) и EDSAC (1949), использовали одноадресные команды, где результат операции сохранялся в аккумуляторе. С ростом сложности вычислений и требований к производительности возникла необходимость в более гибкой адресации.

В 1950-х годах появились машины с двух- и трёхадресными командами. Например, IBM 7090 (1958) использовал трёхадресные инструкции для некоторых операций. Однако широкое распространение трёхадресная архитектура получила с развитием RISC-процессоров в 1980-х годах. Проекты, такие как MIPS (1981) и SPARC (1987), заложили основы современных трёхадресных наборов команд, где каждая арифметическая или логическая операция явно указывает три регистра.

В области компиляции трёхадресный код (TAC) стал стандартным промежуточным представлением, используемым в таких компиляторах, как GCC и LLVM, начиная с 1990-х годов. Это позволило унифицировать процесс оптимизации и генерации кода для различных целевых архитектур.

Структура трёхадресной команды

Трёхадресная команда в общем виде имеет формат:

OP DEST, SRC1, SRC2

где:

  • OP — код операции (например, ADD, SUB, MUL, LOAD, STORE);
  • DEST — адрес (или регистр) для записи результата;
  • SRC1 — адрес (или регистр) первого операнда;
  • SRC2 — адрес (или регистр) второго операнда.

Примеры:

  • ADD R1, R2, R3 — сложить содержимое регистров R2 и R3, результат записать в R1.
  • SUB R4, R5, #10 — вычесть из содержимого R5 константу 10, результат в R4.
  • MUL R6, R7, R8 — умножить R7 на R8, результат в R6.

В некоторых архитектурах (например, ARM) трёхадресные команды могут быть модифицированы для использования констант или флагов состояния.

Классификация

По типу операндов

  1. Регистровые трёхадресные команды — все операнды находятся в регистрах процессора. Характерны для RISC-архитектур (MIPS, ARM, RISC-V).
  2. Регистрово-памятные трёхадресные команды — один или два операнда могут быть в памяти, а результат также может быть записан в память. Встречаются в некоторых CISC-архитектурах (например, VAX).
  3. Команды с непосредственными операндами — один из операндов является константой, закодированной в самой команде.

По назначению

  1. Арифметические и логические — ADD, SUB, MUL, DIV, AND, OR, XOR.
  2. Пересылки данных — MOV, LOAD, STORE (хотя LOAD и STORE часто двухадресные).
  3. Управления — JMP, BEQ, BNE (условные и безусловные переходы).
  4. Сравнения — CMP, TEST (часто двухадресные, но могут быть трёхадресными в некоторых архитектурах).

Применение

В процессорах

Трёхадресные команды являются основой большинства современных RISC-процессоров. Основные преимущества:

  • Повышение производительности — за счёт явного указания всех операндов сокращается количество обращений к памяти и уменьшается зависимость от аккумулятора.
  • Конвейеризация — трёхадресные команды облегчают распараллеливание выполнения инструкций.
  • Упрощение компиляции — компилятору не нужно генерировать дополнительные команды для перемещения данных между регистрами.

Примеры архитектур, использующих трёхадресные команды:

  • MIPS — классическая RISC-архитектура с 32 регистрами и трёхадресными арифметическими командами.
  • ARM — поддерживает трёхадресные команды в режиме ARM (32-битные инструкции), но в Thumb-режиме (16-битные) часто использует двухадресные.
  • RISC-V — открытая архитектура, где базовые арифметические команды трёхадресные.
  • x86-64 — в основном использует двухадресные команды (CISC-традиция), но с расширениями AVX и SSE появились трёхадресные векторные инструкции.

В компиляторах

Трёхадресный код (TAC) — это промежуточное представление программы, используемое в компиляторах для оптимизации и генерации машинного кода. Каждая инструкция TAC имеет вид:

  • x = y op z — арифметическая операция;
  • x = y — копирование;
  • goto L — безусловный переход;
  • if x relop y goto L — условный переход;
  • x = y[i] — доступ к массиву;
  • x[i] = yзапись в массив.

TAC широко применяется в компиляторах GCC, LLVM, а также в виртуальных машинах (например, Dalvik в Android — до версии 5.0).

В виртуальных машинах

Некоторые виртуальные машины используют трёхадресные инструкции для обеспечения переносимости и эффективности:

  • Java Virtual Machine (JVM)байт-код JVM в основном двухадресный (стековый), но некоторые инструкции (например, iadd) оперируют с вершиной стека.
  • Common Language Runtime (CLR) — платформа .NET использует стековую архитектуру, но с трёхадресными элементами в IL-коде.
  • WebAssembly — использует стековую архитектуру, но с возможностью локальных переменных.

Сравнение с другими архитектурами

ХарактеристикаТрёхадреснаяДвухадреснаяОдноадреснаяСтековая
Число операндов3210 (неявные)
Типичные архитектурыRISC (MIPS, ARM, RISC-V)CISC (x86, 68000)Аккумуляторные (PDP-8)JVM, CLR, Forth
Длина командыФиксированная (32 бит)Переменная (1-15 байт)Фиксированная (16-32 бит)1 байт (часто)
ПроизводительностьВысокая (конвейер)СредняяНизкаяСредняя
Сложность компиляцииНизкаяСредняяВысокаяСредняя

Преимущества и недостатки

Преимущества

  1. Явная адресация — отсутствие скрытых зависимостей от аккумулятора или стека упрощает анализ и оптимизацию кода.
  2. Конвейеризация — трёхадресные команды легче распараллеливаются, что важно для суперскалярных процессоров.
  3. Уменьшение числа команд — для выполнения операции a = b + c требуется одна команда, а не две (как в двухадресной архитектуре: MOV a, b; ADD a, c).
  4. Гибкостькомпилятор может свободно распределять регистры, не заботясь о сохранении аккумулятора.

Недостатки

  1. Увеличение длины команды — трёхадресные команды обычно занимают 32 бита, что увеличивает объём кода по сравнению с 16-битными двухадресными командами.
  2. Сложность декодирования — большее число полей требует более сложного декодера.
  3. Ограниченность регистров — в архитектурах с малым числом регистров (например, x86-16) трёхадресные команды могут быть неэффективны.

Примеры

Пример 1: MIPS

Вычисление c = a + b на MIPS: `` lw $t0, a # загрузка a в $t0 lw $t1, b # загрузка b в $t1 add $t2, $t0, $t1 # $t2 = $t0 + $t1 sw $t2, c # сохранение результата в c ` Здесь add` — трёхадресная команда.

Пример 2: RISC-V

Вычисление d = (a + b) c: `` add t0, a, b # t0 = a + b mul d, t0, c # d = t0 c ``

Пример 3: Трёхадресный код компилятора

Исходный код на C: ``c int x = 5; int y = x + 3; int z = y 2; ` TAC: ` t1 = 5 x = t1 t2 = x + 3 y = t2 t3 = y 2 z = t3 ``

Интересные факты

  • В архитектуре x86 до появления AVX-512 трёхадресные команды были редкостью. В AVX-512 появились инструкции с тремя и даже четырьмя операндами (например, vfmadd132ps).
  • RISC-V — одна из немногих современных архитектур, где трёхадресные команды являются базовым стандартом, а не опцией.
  • В компиляторах LLVM трёхадресный код используется в промежуточном представлении (IR), которое затем оптимизируется и транслируется в машинный код.

Источники

  • Patterson, D. A., & Hennessy, J. L. (2017). Computer Organization and Design: The Hardware/Software Interface. Morgan Kaufmann.
  • Tanenbaum, A. S. (2016). Structured Computer Organization. Pearson.
  • Aho, A. V., Lam, M. S., Sethi, R., & Ullman, J. D. (2006). Compilers: Principles, Techniques, and Tools. Addison-Wesley.
  • Документация архитектур MIPS, ARM, RISC-V.
  • Статья «Three-address code» в английской Википедии.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →