Привет всем! Прежде чем мы погрузимся в глубокий анализ архитектуры компилятора ZGEN, я хочу приоткрыть завесу тайны и рассказать о том, что прямо сейчас кипит в нашей «лаборатории». Это те фичи и улучшения, которые проходят активное тестирование и, возможно, скоро станут частью следующего релиза. Ваше мнение по этим вопросам поможет нам двигаться в правильном направлении.
Warnings, Errors: На пути к умной диагностике
Хороший компилятор — это не тот, который просто работает, а тот, который помогает вам писать код лучше. Мы уделяем огромное внимание качеству диагностики. Сейчас компилятор уже выдает осмысленные предупреждения и ошибки, указывая на конкретное место в коде:
[zcc::driver<impl AssemblyDriver>]: Compilation of user-defined module is not supported 2 | 3 | @include std::fs::read_to_string; 4 | ^-------------------------------- [zcc::driver<impl AssemblyDriver>]: Compilation of user-defined module is not supported 4 | 5 | @include ownlib("./mylibs/ownlib.asmx"); 6 | ^------------------------------------ [zcc::driver<impl AssemblyDriver>]: Compilation of user-defined fn functions is not supported 16 | 17 | @fn pub assume {} 18 | ^-------- [zcc::driver<impl AssemblyDriver>]: Compilation of user-defined fn functions is not supported 18 | 19 | @fn pub consume_message_broker(str message, uint64 len) { 20 | ^------------------------------------------------
Но этого мало. Сейчас мы тестируем две новые возможности:
-
Счетчик предупреждений и ошибок. По завершении компиляции вы будете видеть четкую сводку, которая сразу даст понять масштаб проблем:
i 4 Warnings, 0 Errors.Это стандарт для серьезных инструментов, и мы его внедряем.
-
Флаг
-Wдля подавления предупреждений. Иногда предупреждения могут мешать, особенно если вы уверены в своем коде. Мы тестируем флаг-W, который полностью отключит вывод всехwarnings, оставляя только критические ошибки.
И здесь нам нужен ваш совет. Мы рассматриваем введение более гранулярных флагов, по аналогии с GCC/Clang. Напишите в комментариях, хотели бы вы видеть, например, флаг -Wno-unused-variable, который бы отключал предупреждения только о неиспользуемых переменных?
T-API: Улучшение интерфейса
T-API — это наш парсер аргументов командной строки. Он должен быть гибким и интуитивно понятным. Мы обнаружили недоработку в текущей версии: флаги вроде --llvm@version работают корректно, но более привычный формат --llvm-version интерпретируется как два отдельных флага: --llvm и --version. Это контринтуитивно. Сейчас в лаборатории находится патч, который научит tapi правильно обрабатывать «длинные» флаги с дефисами, чтобы вы могли использовать тот стиль, который вам удобнее.
Call: Связь с внешним миром
Это, пожалуй, самое горячее направление наших исследований. Мы работаем над полноценной интеграцией с системными библиотеками, такими как libc.
В идеале, к которому мы стремимся, код для вывода строки будет выглядеть так:
@include libc; @section rodata { message: str("Hello World") } @fn main { @call libc::printf("sent %s", $message); }
Это интуитивно, чисто и эффективно. Но чтобы достичь этой простоты, под капотом должна работать невероятно сложная система. На данный момент наша тестовая реализация выглядит более «низкоуровневой»:
@include libc; @section rodata { format: str("sent %s") message: str("Hello World") } @fn main { ;; программист сам кладет аргументы в регистры по ABI @call printf; }
Почему существует эта разница и что нужно для перехода?
-
Разбор сложных выражений:
zcc_parserдолжен научиться понимать конструкциюlibc::printf, распознавать ее как вызов функции из внешнего модуля и передавать эту информацию вhwc. -
Генерация PLT/GOT: Когда
hwcвидит вызов внешней функции (printf), он не знает ее точный адрес. Поэтому он генерирует специальный «трамплин» в секцииPLT(Procedure Linkage Table). Первый вызовprintfперенаправляется на динамический загрузчик системы, который находит реальный адрес функции вlibc.soи записывает его в таблицуGOT(Global Offset Table). Все последующие вызовыprintfуже будут идти напрямую по адресу из GOT, что практически не сказывается на производительности.hwcполностью управляет созданием этих таблиц. -
Сборка вызовов по ABI: Компонент
assemblyдолжен быть обучен правиламABI(Application Binary Interface) дляx86_64. Он должен знать, что первые шесть целочисленных аргументов функции передаются через регистры%rdi,%rsi,%rdx,%rcx,%r8,%r9. Именноassemblyдолжен будет генерироватьmovинструкции для загрузки аргументов в правильные регистры перед инструкциейcall.
Этот функционал находится в активной разработке. Ваше мнение здесь критически важно: стоит ли нам выпустить текущую «ручную» реализацию или подождать полностью автоматизированной? Напишите в комментариях, это поможет нам определить приоритеты.
Section: Работа с данными
На данный момент в ZGEN стабильно работает секция .rodata для констант. Но для полноценных программ необходима возможность работать с изменяемыми глобальными данными. Прямо сейчас мы проводим тестирование и отладку секции .data:
@section data { message: str("This is a data section") }
Это позволит создавать глобальные переменные, которые можно будет изменять в ходе выполнения программы. Пока что, как и в rodata, мы поддерживаем только строковый тип (str), но с расширением системы типов появятся и другие.
И раз уж мы заговорили о типах…
Голосуйте в комментариях!
Хочу сразу отметить: типы для чисел с плавающей точкой (float, double) появятся не скоро. Их реализация требует значительных доработок в FPU/SSE-части компилятора и отдельного масштабного тестирования. Мы доберемся до них, но постепенно. Двигаемся итерационно.
Спасибо, что заглянули в нашу лабораторию! Ваша обратная связь помогает нам строить лучший инструмент. В следующей статье мы подробно разберем, как все эти компоненты работают вместе в уже релизной версии компилятора.
ссылка на оригинал статьи https://habr.com/ru/articles/929264/
Добавить комментарий