Как стать автором
Поиск
Написать публикацию
Обновить
8.13

Компиляторы *

Из исходного кода в машинный

Сначала показывать
Порог рейтинга
Уровень сложности

AsmX G3: Архитектура кодировщика ZGEN. Как hwm генерирует машинный код amd64

Уровень сложностиСложный
Время на прочтение20 мин
Количество просмотров1.1K

Большинство компиляторов — это монолитные черные ящики, унаследованные из прошлого. Мы отвергли этот путь. Мы разбираем архитектуру x86_64 до "первых принципов", чтобы понять, как на самом деле работает кремний. В этой статье мы вскрываем капот нашего компилятора ZGEN и его "фабрики машинного кода" — hwm. Никакой магии. Только чистая, детерминированная инженерия, которая превращает ассемблер в исполняемые биты.

Перейти к полному техническому разбору

Новости

Efficient Computer: программируем по кафелю

Уровень сложностиСредний
Время на прочтение3 мин
Количество просмотров3.1K

Экспериментируем с компилятором для новой не Фон-Неймановской архитектуры, обещающей повышение энергоэффективности в 100 раз.

Читать далее

AsmX G3: От высокоуровневого ассемблера к нативному коду. Разбираем компилятор ZGEN

Уровень сложностиСложный
Время на прочтение14 мин
Количество просмотров2.5K

Мы не просто пишем код. Мы строим компиляторы, которые строят код. AsmX G3 — это не обновление, это переосмысление с первых принципов. Приготовьтесь к глубокому техническому погружению в архитектуру нашего нового компилятора ZGEN, где мы вскроем каждый компонент, от ядра до сборщика ELF, и покажем инженерные решения, которые определяют будущее системного программирования.

Читать полный технический разбор

Невидимые загрузки или о пользе свободно стоящих функций

Время на прочтение5 мин
Количество просмотров1.3K

Довольно долго я тягался с по-настоящему глупой проблемой на C++: мне не нравятся функции-члены, но я вынужден их писать, чтобы программисту было хоть немного удобнее работать. Функции-члены обеспечивают две вещи: разграничение областей видимости и обнаружимость. Разграничение областей видимости — менее актуальная из этих задач, поскольку в моём коде на C++ я и так не использую модификаторы private/public. Обнаружимость — большая проблема: я могу написать x.F, а IDE предложит x.Func(). Отлично! «Но правильные программисты пользуются только vim и скромными IDE». Что ж, привет вам, воображаемые мифические обычные программеры. Здесь вам ничего не угрожает, но, пожалуйста, уходя — надевайте сразу два беджика:  «vim отстой» и «Я ненавижу emacs». Отлично помогает завязать разговор с «настоящими» программистами.

Читать далее

Продолжаем делать реализацию LISP на Python. Часть 1: структуры

Время на прочтение4 мин
Количество просмотров2.1K

Да. Спустя наверно 3 дня я решил сделать это. Долго конечно, но что тут поделаешь.

Также если нужно, можете посмотреть на первую статью об этом лиспе.

Читать далее

QapGen: Создаём мощные парсеры на C++

Время на прочтение36 мин
Количество просмотров4K

QapDSLv2 — это язык который транслируется в обычный C++ код. Он позволяет удобно и компактно задавать грамматики/правила разбора кода программ, значительно упрощая разработку компиляторов/анализаторов/трансляторов.

QapGen — это генератор дерева_лексеров/парсеров описанных на QapDSLv2. Сама грамматика QapDSLv2 описана на QapDSLv2 на 100%. Поэтому QapGen как основной читатель этой грамматики сам генерирует часть своего кода(весь парсер QapDSLv2).

Основные фишки QapDSLv2 + QapGen — это:

1) Отсутствие этапа токенизации — дерево лексеров разбивает входной поток на лексемы и сохраняет их в строго типизированных древовидных С++ структурах пропуская этап токенизации.

2) Генерация оптимизированного кода полиморфных лексеров.

3) Полное сохранение всех лексем(даже разделители сохраняются, такие как пробелы/переходы на новую строку и комментарии) в результирующем дереве.

4) Возможность сохранить как оригинальное дерево, так и модифицированное обратно в код/текст без потери разделителей/комментариев.

5) Автоматическая генерация кода посетителей(это такой паттерн проектирования).

А теперь пример самой сочной части(рекурсивно самоописывающийся код):

structt_target_struct:i_target_item{
structt_keyword{
stringkw=any_str_from_vec(split("struct,class",","));
" "? // optional separator
};
structt_body_semicolon:i_struct_impl{";"};
structt_body_impl:i_struct_impl{
"{" // жрём скобочку
vector<TAutoPtr<i_target_item>>nested?; //рекурсия!
" "?
vector<TAutoPtr<i_struct_field>>arr?; // парсим поля
" "?
TAutoPtr<t_cpp_code>c?; // остальной С++ код
" "?
"}"
};
structt_parent{
stringa_or_c=any_str_from_vec(split("=>,:",","));
" "?
t_namename;
};
//точка входа в парсер:
TAutoPtr<t_keyword>kw?; //парсимstruct/class
t_namename; //парсим имя
" "?
TAutoPtr<t_parent>parent?;
" "?
TAutoPtr<i_struct_impl>body;
};

Читать далее

Создаём свою легкую реализацию LISP'а на Python

Время на прочтение5 мин
Количество просмотров2K

Всем привет! Сегодня мы с вами сделаем реализацию LISP'а. Конечно же не полного.

Возможно, когда то я доведу этот лисп до ума и напишу новую статью... Но не обещаю.

Читать далее

Что не пишут в документации Kotlin Contracts: тёмные закоулки и пасхалки

Уровень сложностиСложный
Время на прочтение9 мин
Количество просмотров2.1K

Контракты в Kotlin — это «тёмная лошадка» языка — они загадочные и чуть-чуть магические. И под капотом у них спрятано гораздо больше, чем можно найти в официальной документации.

Привет! Меня зовут Виталий. Я работаю Android‑разработчиком в Альфа‑Банке. В этой статье я делюсь пасхалками и неожиданными фичами Kotlin компилятора, связанными с Kotlin Contracts: как парсится список эффектов, как работает новый Contracts API изнутри, и почему, чёрт возьми, на уровне компилятора можно использовать контракты не только на уровне функций.

Всё просто, лампово и с примерами из исходников. Даже если вы никогда не ковырялись в кишках компилятора, гарантирую: после прочтения контракты станут чуть ближе, а компилятор — чуть менее пугающим.

Читать далее

Встреча ISO C++ в Софии: С++26 и рефлексия

Время на прочтение9 мин
Количество просмотров12K


Привет! На связи Антон Полухин из Техплатформы Городских сервисов Яндекса, и сейчас я расскажу о софийской встрече Международного комитета по стандартизации языка программирования C++, в которой принимал активное участие. Это была последняя встреча, на которой новые фичи языка, с предодобренным на прошлых встречах дизайном, ещё могли попасть в C++26.

И результат превзошёл все ожидания:
  • compile-time-рефлексия
  • рефлексия параметров функций
  • аннотации
  • std::optional<T&‍>
  • параллельные алгоритмы


Об этих и других новинках расскажу в посте

CLL в ISPA: Семантические действия просто и мощно

Уровень сложностиСредний
Время на прочтение3 мин
Количество просмотров518

CLL в ISPA — переносимый язык семантических действий для генераторов парсеров. Объявление переменных, условий и циклов, генерация AST и кода на C++ без привязки к языку парсера. Пример, разбор и сравнение с ANTLR, Bison.

Читать далее

ISPA Parser Generator

Уровень сложностиСредний
Время на прочтение5 мин
Количество просмотров715

Разработка парсер генератора ISPA: что реализовано и какие планы на будущее.Гибкий парсер нового поколения с теми функциями, которых давно не хватает существующим решениям.

Читать далее

Rust 1.88.0: Цепочки let, naked-функции, булевы литералы в cfg и очистка кеша cargo

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров1.6K

Команда Rust рада сообщить о новой версии языка — 1.88.0. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.


Если у вас есть предыдущая версия Rust, установленная через rustup, то для обновления до версии 1.88.0 вам достаточно выполнить команду:


$ rustup update stable

Если у вас ещё не установлен rustup, вы можете установить его с соответствующей страницы нашего веб-сайта, а также посмотреть подробные примечания к выпуску на GitHub.


Если вы хотите помочь нам протестировать будущие выпуски, вы можете использовать канал beta (rustup default beta) или nightly (rustup default nightly). Пожалуйста, сообщайте обо всех встреченных вами ошибках.

Читать дальше →

Уничтожение EXE: 640 Байт для программы на C

Уровень сложностиСредний
Время на прочтение5 мин
Количество просмотров15K

В наше время разработчики уже не так беспокоятся о размере приложений. Некоторые простейшие приложения требуют под 200-300 МБ, а игра вообще может весить более 100 ГБ. Я уже не говорю про "Hello World", который иногда занимет под 180-260 КБ!

К счастью, есть возможность сократить размер приложения. О мусоре в exe'шнике и о способах его удаления написано в этой статье.

Читать далее

Ближайшие события

Почему C++ считает мой класс копируемым, если его нельзя скопировать?

Уровень сложностиСредний
Время на прочтение3 мин
Количество просмотров6.3K

Рассмотрим следующий сценарий:

template<typename T>
struct Base
{
// Есть конструктор по умолчанию
Base() = default;

// Некопируемый
Base(Base const &) = delete;
};

template<typename T>
struct Derived : Base<T>
{
Derived() = default;
Derived(Derived const& d) : Base<T>(d) {}
};
// Это assertion выполняется?
static_assert(
std::is_copy_constructible_v<Derived<int>>);

Почему выполняется это assertion? Очевидно, что скопировать Derived<int> нельзя, ведь при этом мы попытаемся скопировать некопируемый Base<int>. И в самом деле, если попробовать скопировать его, то мы получим ошибку.

Читать далее

Языково-ориентированное… моделирование?

Уровень сложностиСредний
Время на прочтение13 мин
Количество просмотров1.9K

Историю можно начать с 1994 года, в котором Мартин Уорд (Martin Ward) на основании исследования больших проектов предложил парадигму языково-ориентированного программирования, когда процесс разработки программного обеспечения разбивается на стадии создания предметно-ориентированных языков и описания решения задачи с их использованием. Цель языково-ориентированного программирования — разделить сложности разработки: машиноориентированная часть кода (низкоуровневая функциональность) и человеко-ориентированная (решение прикладной задачи) разрабатываются независимо друг от друга.

Далее в 2003 году Эрик Эванс (Eric Evans) ввел понятие предметно-ориентированного проектирования (Domain-Driven Design, DDD) для набора программных и организационных практик, позволяющих разрабатывать сложные масштабируемые системы. Этот подход до сих пор активно используется, например, в микросервисной архитектуре и в информационной безопасности (см. Secure by Design). В этом подходе вводятся понятия: «модель», «проектирование по модели» (Model-Driven Design), «изоляция предметной области» и «изолированный контекст» (Bounded Context). Особенно интересно, что Эванс упоминает о предметно-ориентированных языках, как идеальном средстве описания модели конкретной предметной области, которая должна быть изолирована в своём контексте.

Но как обстоят дела с имитационным математическим моделированием? До сих пор мы применяем инструменты, разработанные по большей части на базе концепций из середины прошлого века. В то время, как за последнюю пару десятилетий теория и технологии развивались достаточно динамично. Возможно, в этом нет ничего страшного (об этом позже). Но вот что интересно: можно ли объединить понятия разработки математических моделей и программного обеспечения на базе представленных выше концепций?

Вот мы и добрались до моделирования в широком смысле. Далее речь пойдёт о подходе, который может быть применён, как для имитационного математического моделирования, так и для разработки сложного программного обеспечения. Начнём с имитационного моделирования, поскольку в этой области есть наиболее интересные результаты, но перспективы нового подхода в разработке сложных программных систем постараюсь тоже затронуть.

Читать далее

Почему Rust так мало волнует производительность компилятора

Уровень сложностиПростой
Время на прочтение15 мин
Количество просмотров8.1K

Наверно, чаще всего на Rust жалуются из-за его медленного цикла обратной связи и долгого времени компиляции. Я слышу и читаю об этом постоянно; в подкастах по Rust, в постах блоговопросах, докладах с конференций и офлайн-обсуждениях. Я и сам, как пользователь Rust, регулярно жалуюсь на это!

Кроме того, наряду с обычными жалобами на время компиляции, я начал замечать от раздражённых разработчиков на Rust и подобные заявления: «Почему Rust Project не занимается активнее этой важной и очевидной проблемой? Почему с этим что-нибудь не сделают?». Я участник рабочей группы по производительности компилятора Rust, поэтому воспринимаю такие вопросы очень серьёзно. И, разумеется, у меня есть мнение по этому поводу. В этом посте я приведу свои размышления, способные служить ответами на эти (и похожие) вопросы.

Предупреждение: все выраженные в этом посте мнения исключительно мои и необязательно отражают точку зрения Rust Project (группы контрибьюторов и мейнтейнеров тулчейна Rust).

Читать далее

Что будет, если заинлайнить всё

Время на прочтение25 мин
Количество просмотров13K

Усаживайтесь поудобнее, ребята! Сегодня мы с вами разберём следующий увлекательный вопрос: что будет, если заинлайнить вообще всё?

Если вы пока не знакомы с техникой встраивания (inlining) то примите к сведению, что в сообществе специалистов по разработке компиляторов многие, в том числе очень авторитетные фигуры (например, Чендлер Каррут) считают этот приём наиважнейшим при оптимизации компиляторов. Подробнее о том, как устроено встраивание, рассказано здесь — мы беззастенчиво хвалимся той презентацией, с которой выступили перед участниками конференции LLVM Developers' Meeting по межпроцедурной оптимизации. Я рассказывал о встраивании и очень рекомендую вам посмотреть хотя бы первые 6 минут. В этом видео я рассказываю, почему встраивание — очень простое преобразование, а вот тут вашему вниманию предлагается реализация встраивания, предложенная великим Крисом Латтнером уже около 20 лет назад — в ней всего около 200 строк кода. К сожалению, сегодня даже само преобразование пропорционально выросло: в качестве примера взгляните хотя бы на InlineFunction.cpp.

В вышеупомянутом видео я рассказываю, что у встраивания есть свои недостатки. Иными словами, встраивание позиционируется как супер-пупер инструмент в арсенале компиляторщика, но пользоваться этой штукой следует с осторожностью. И следует ли вообще?

Читать далее

QapDSL — декларативное описание AST и парсеров для C++

Уровень сложностиСредний
Время на прочтение4 мин
Количество просмотров1.6K



QapDSL — декларативное описание AST и парсеров для C++


QapDSL — это специализированный язык (DSL), который позволяет описывать абстрактные синтаксические деревья (AST) и правила их разбора для языков программирования, прежде всего C++. Такая формализация помогает автоматизировать построение парсеров, генерацию кода, анализ исходников и даже рефакторинг.



Зачем нужен QapDSL?


  • Компактно и наглядно описывать структуру и грамматику языка.
  • Автоматически генерировать C++-структуры, парсеры, сериализаторы и визиторы.
  • Ускорять эксперименты с языками, создавая прототипы компиляторов и анализаторов.
  • Упрощать анализ и рефакторинг сложных языков, в т.ч. C++.


Пример QapDSL-описания


Рассмотрим, как описывается объявление класса C++ на QapDSL:


t_class{
  string keyword;
  t_sep sep0;
  string name;
  t_sep sep1;
  TAutoPtr<t_parents> parents;
  t_sep sep2;
  TAutoPtr<t_class_body> body;
  t_sep sep3;
  {
    M+=go_any_str_from_vec(keyword,split("struct,class,union",","));
    O+=go_auto(sep0);
    M+=go_str<t_name>(name);
    O+=go_auto(sep1);
    O+=go_auto(parents);
    O+=go_auto(sep2);
    O+=go_auto(body);
    O+=go_auto(sep3);
    M+=go_const(";");
  }
}

Читать дальше →

Оптимизируем C++ шаблоны: от инлайнинга до модулей

Уровень сложностиСредний
Время на прочтение18 мин
Количество просмотров4.1K

Мы рассмотрим, чем опасны шаблоны для проекта на C++ и как минимизировать эти риски. В оптимизации нам помогут инлайн-файлы, явные инстанциации и даже модули из C++20.

Читать далее

Возможное расширение языка C++ операцией скалярного произведения

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров4.7K

У меня возникла идея, как можно расширить синтаксис C++ операцией скалярного произведения. Если кратко, то произведение двух матриц в новых обозначениях будет выглядеть так:

C[>i][>j] = A[i][>k] * B[>k][j];

Насколько мне известно, сочетания операторов [> и [< вроде бы нигде не используются. Их можно применить для декларации индексов, которые существуют только в пределах данного выражения. Сочетание [> используется для декларации индекса, который пробегает от начала до конца массива в прямом направлении, а сочетание [< для декларации индекса, который пробегает в обратном направлении. Для повторяющихся индексов в произведении подразумевается суммирование - они аналогичны немым индексам в тензорных обозначениях.

Разберём на примерах, как это будет работать.

Читать далее
1
23 ...

Вклад авторов