Теория языков программирования

Генерация кода

Один и тот же алгоритм, написанный одинаково, может работать в 10x быстрее или медленнее - в зависимости от того, насколько умён backend компилятора. Register allocation, instruction selection, scheduling - это то, что превращает абстрактный IR в быстрый нативный код.

  • **Rust release builds**: LLVM -O3 с LTO даёт код, конкурентный с оптимизированным C. Без этого Rust debug builds в 10-50x медленнее release
  • **Wasmtime**: Cranelift компилирует WebAssembly за ~100ms. Это делает serverless cold start приемлемым. LLVM потребовал бы 1-2s
  • **Apple M1 SoC**: ARM backend LLVM оптимизирован Apple для M1. Результат: Clang на M1 компилирует LLVM быстрее, чем Intel Xeon в 2x дороже

Распределение регистров

Распределение регистров - NP-полная задача раскраски графа. Узлы - виртуальные регистры (переменные SSA), рёбра - конфликты (обе переменные живы одновременно). Цель: раскрасить граф в k цветов (физических регистров) с минимальным числом spill'ов в память.

Linear scan register allocation - более быстрый алгоритм O(n log n) vs Chaitin-Briggs O(n^2). JIT компиляторы (JVM, V8) используют linear scan - скорость компиляции важна. AOT (LLVM) может использовать более медленный но качественный Chaitin-Briggs.

Что происходит когда переменных больше, чем физических регистров?

Выбор инструкций

Instruction selection - сопоставление IR узлов с инструкциями целевой архитектуры. Одна IR инструкция может отображаться на разные машинные инструкции с разной стоимостью. Tree pattern matching через dynamic programming даёт оптимальное покрытие.

Почему instruction selection - важная оптимизация?

LLVM backend

LLVM (Low Level Virtual Machine) - модульный компилятор infrastructure. Frontend генерирует LLVM IR, LLVM оптимизирует и генерирует нативный код для 30+ архитектур. Rust, Swift, C++ (Clang), Julia, Kotlin Native - всё на LLVM.

LLVM IR типизирован и в SSA форме. nsw/nuw флаги на арифметике - undefined behavior разрешения, которые открывают дополнительные оптимизации. Rust использует это: signed integer overflow = UB (как в C), поэтому LLVM может оптимизировать агрессивнее.

В чём главное преимущество архитектуры LLVM для создания новых языков?

Cranelift

Cranelift - новый code generator, написанный на Rust для Wasmtime и rustc backend. Разработан как альтернатива LLVM с фокусом на скорость компиляции (для JIT) и корректность (для WebAssembly runtime). Использует проверяемо корректный register allocator (regalloc2).

Сравнение LLVM vs Cranelift: LLVM - 60+ оптимизационных проходов, лучший output code, медленная компиляция. Cranelift - минимальные оптимизации, ~10x быстрее компиляция, хуже output code. Выбор: AOT -> LLVM, JIT/debug -> Cranelift.

Генерация кода - это просто перевод операций один-в-один в инструкции процессора

Codegen включает register allocation (NP-complete), instruction selection (tree pattern matching), instruction scheduling (latency hiding) - каждый этап существенно влияет на производительность

Наивная трансляция LLVM IR -> x86 без register allocation потребует memory для каждой переменной. Хороший register allocator экономит 3-5x по скорости на числодробилках

Почему Cranelift лучше LLVM для JIT компиляции?

Итоги

  • **Register allocation**: NP-полная раскраска графа конфликтов. Spill в память если регистров не хватает. Linear scan для JIT, Chaitin-Briggs для AOT
  • **Instruction selection**: одна IR операция -> оптимальные machine instructions. LEA вместо imul+add. Peephole оптимизации
  • **LLVM**: модульная infrastructure. Frontend -> LLVM IR -> 30+ таргетов + 60 оптимизаций. Основа Rust, Swift, Clang, Julia
  • **Cranelift**: 10x быстрее LLVM, меньше оптимизаций. Идеален для JIT (Wasmtime) и debug сборок

Связанные темы

Codegen - финальный этап компилятора:

  • IR и оптимизации — Оптимизированный IR поступает на вход codegen
  • JIT компиляция — JIT - codegen в runtime, баланс скорости компиляции и качества кода

Вопросы для размышления

  • Register allocation - NP-полная задача, но компиляторы решают её за секунды. Какие эвристики и упрощения делают это возможным на практике?
  • LLVM IR содержит флаги nsw/nuw (no signed/unsigned wrap), которые разрешают undefined behavior оптимизации. Как баланс между оптимизируемостью и корректностью влияет на дизайн языка?
  • Apple использует LLVM для всего Apple Silicon кода. Насколько глубоко компания может кастомизировать backend под свою микроархитектуру?

Связанные уроки

  • fl-18-turing-machine
Генерация кода

0

1

Войти