#define Size 819000
int sieve ( int N ) {
int64_t i , k , prime , count , n ; char flags [ Size ];
for ( n = 0 ; n < N ; n ++ ) {
count = 0 ;
for ( i = 0 ; i < Size ; i ++ )
flags [ i ] = 1 ;
for ( i = 0 ; i < Size ; i ++ )
if ( flags [ i ]) {
prime = i + i + 3 ;
for ( k = i + prime ; k < Size ; k += prime )
flags [ k ] = 0 ;
count ++ ;
}
}
return count ;
}
void ex100 ( void ) {
printf ("sieve (100) = %d", sieve (100));
}
m_sieve : module
export sieve
sieve : func i32, i32:N
local i64:iter, i64:count, i64:i, i64:k, i64:prime, i64:temp, i64:flags
alloca flags, 819000
mov iter, 0
loop : bge fin, iter, N
mov count, 0; mov i, 0
loop2 : bge fin2, i, 819000
mov u8:(flags, i), 1; add i, i, 1
jmp loop2
fin2 : mov i, 0
loop3 : bge fin3, i, 819000
beq cont3, u8:(flags,i), 0
add temp, i, i; add prime, temp, 3; add k, i, prime
loop4 : bge fin4, k, 819000
mov u8:(flags, k), 0; add k, k, prime
jmp loop4
fin4 : add count, count, 1
cont3 : add i, i, 1
jmp loop3
fin3 : add iter, iter, 1
jmp loop
fin : ret count
endfunc
endmodule
m_ex100 : module
format : string "sieve (10) = %dn"
p_printf : proto p:fmt, i32:result
p_sieve : proto i32, i32:iter
export ex100
import sieve, printf
ex100 : func v, 0
local i64:r
call p_sieve, sieve, r, 100
call p_printf, printf, format, r
endfunc
endmodule
func
описывает сигнатуру функции (принимает 32-битный целочисленный аргумент со знаком и возвращает 32-битное целое число со знаком) и аргумент функции N
, который будет локальной переменной 64-битного целого числа со знаком.;
string
описывает данные в форме строки Cexport
описывает функции или данные модуля, которые видны за пределами текущего модуля.import
описывает функции или данные модуля, которые должны быть определены в других модулях MIR.proto
описывает прототипы функций. Его синтаксис такой же, как синтаксис func
.call
— это инструкция MIR для вызова функций MIR_load_external
m1
и m2
— модули m_sieve
и m_e100
, func
— функция ex100
, sieve
— функция sieve
): /* ctx is a context created by MIR_init / MIR_init2 */
MIR_load_module ( ctx , m1 ); MIR_load_module ( ctx , m2 );
MIR_load_external ( ctx , "printf" , printf );
MIR_link ( ctx , MIR_set_interp_interface , import_resolver );
/* or use MIR_set_gen_interface to generate and use the machine code */
/* or use MIR_set_lazy_gen_interface to generate function code on its 1st call */
/* use MIR_gen (ctx, func) to explicitly generate the function machine code */
MIR_interp ( ctx , func , & result , 0 ); /* zero here is arguments number */
/* or ((void (*) (void)) func->addr) (); to call interpr. or gen. code through the interface */
binfmt_misc
Бинарный файл mir-bin-run
подготовлен к использованию из binfmt_misc
с помощью следующей строки (пример):
line=:mir:M::MIR::/usr/local/bin/mir-bin-run:P
echo $line > /proc/sys/fs/binfmt_misc/register
Адаптируйте двоичный путь mir-bin-run к вашей системе, он используется по умолчанию.
И бежать с
c2m your-file.c -o your-file
chmod +x your-file
./your-file your args
Исполняемый файл «настраивается» с помощью переменных среды:
MIR_TYPE
устанавливает интерфейс выполнения кода: interp
(для интерпретации), jit
(для генерации) и lazy
(для отложенной генерации, по умолчанию);MIR_LIBS
(список, разделенный двоеточиями) определяет список дополнительных библиотек для загрузки;MIR_LIB_DIRS
или LD_LIBRARY_PATH
(список, разделенный двоеточиями) определяет дополнительный список каталогов для поиска библиотек.Из-за связанной природы
mir-bin-run
сbinfmt_misc
может быть немного странно вызыватьmir-bin-run
напрямую. ФлагP
в binfmt_misc передает дополнительный аргумент с полным путем к двоичному файлу MIR.
Очень короткий конвейер оптимизации для скорости и легкости.
Только самое ценное использование оптимизации:
Различные уровни оптимизации для настройки скорости компиляции в зависимости от производительности сгенерированного кода.
Форма SSA MIR используется перед распределением регистров.
Простота реализации оптимизаций по сравнению с экстремальной производительностью сгенерированного кода.
Более подробная информация о полном конвейере JIT-компилятора :
Упрощение : снижение MIR
Inline : встраивание вызовов MIR
Build CFG : построение графа потока управления (базовые блоки и ребра CFG)
Создание SSA : создание единой формы статического назначения путем добавления фи-узлов и ребер SSA к операндам.
Преобразование адреса : удалить или изменить инструкции MIR ADDR
Глобальная нумерация значений : удаление избыточных insns через GVN. Это включает в себя постоянное распространение и устранение избыточной нагрузки.
Распространение копирования : распространение копирования SSA и удаление избыточных инструкций расширения.
Устранение мертвых магазинов : удаление избыточных магазинов
Устранение мертвого кода : удаление insns с неиспользуемыми выходами
Сброс давления : перемещение insns для уменьшения давления регистра.
Объединение SSA : объединение адресов и пар инструкций сравнения и ветвления.
Вне SSA : удаление фи-узлов и ребер SSA.
Параметры прыжка : различные оптимизации прыжков.
Machinize : запуск машинно-зависимого кода, преобразующего MIR для вызовов ABI, 2-op insns и т. д.
Find Loops : поиск естественных циклов и построение дерева циклов.
Build Live Info : расчет времени жизни и жизни для основных блоков.
Build Register Conflicts : построение матрицы конфликтов для регистров, участвующих в перемещениях. Используется для объединения регистров.
Coalesce : агрессивное объединение регистров.
Распределитель регистров (RA) : линейное сканирование RA на основе приоритета с разделением диапазона в реальном времени.
Build Live Ranges : расчет программных диапазонов точек для регистров
Назначьте : быстрое RA для -O0
или линейное сканирование RA на основе приоритета для -O1
и выше.
Перезаписать : преобразовать MIR в соответствии с назначением, используя зарезервированные жесткие правила.
Объединение (выбор кода): объединение insns, зависящих от данных, в один
Устранение мертвого кода : удаление insns с неиспользуемыми выходами
Generate Machine Insns : запуск машинно-зависимого кода, создающего машинные имена.
c2m
. См. README.md.mir.h
и mir.c
содержат основной код API, включая ввод/вывод двоичного и текстового представления MIR.mir-dlist.h
, mir-mp.h
, mir-varr.h
, mir-bitmap.h
, mir-hash.h
, mir-htab.h
, mir-reduce.h
содержат общий код соответственно для двусвязных списки, пулы памяти, массивы переменной длины, растровые изображения, хэш-вычисления, хеш-таблицы и сжатие/распаковка данных. Файл mir-hash.h
— это общая, простая и высококачественная хеш-функция, используемая в хеш-таблицах.mir-interp.c
содержит код для интерпретации кода MIR. Он включен в mir.c
и никогда не компилируется отдельно.mir-gen.h
, mir-gen.c
, mir-gen-x86_64.c
, mir-gen-aarch64.c
, mir-gen-ppc64.c
, mir-gen-s390x.c
и mir-gen-riscv64.c
содержит код для JIT-компилятора MIR.mir-gen-x86_64.c
, mir-gen-aarch64.c
, mir-gen-ppc64.c
, mir-gen-s390x.c
и mir-gen-riscv64.c
представляют собой машинно-зависимый код JIT-компилятора.mir-.c
содержат простой машинно-зависимый код, общий для интерпретатора и JIT-компилятора.mir-.h
содержат объявления, общие для интерпретатора и JIT-компилятора.mir2c/mir2c.h
и mir2c/mir2c.c
содержат код для компилятора MIR в C. Сгенерированный код может быть непереносимым.c2mir/c2mir.h
, c2mir/c2mir.c
, c2mir/c2mir-driver.c
и c2mir/mirc.h
содержат код для компилятора C в MIR. Файлы в каталогах c2mir/x86_64
и c2mir/aarch64
, c2mir/ppc64
, c2mir/s390x
и c2mir/riscv64
содержат соответственно машинно-зависимый код x86_64, aarch64, ppc64le, s390x и riscv для компилятора C в MIR.mir-bin-run.c
содержит код для mir-bin-run
, описанный выше.mir-bin-driver.c
с утилитой b2ctab
можно использовать для портативного способа создания двоичных файлов из двоичных файлов MIR.mir-utils
содержит различные утилиты для работы с MIR, например, преобразование двоичного MIR в текстовый и наоборот.adt-tests
, mir-tests
, c-tests
и c-benchmarks
содержит код для тестирования и бенчмаркинга MIR и c2m
make bench
и make test
Intel i5-13600K с памятью 64 ГБ под FC37 с GCC-12.3.1
МИР-генератор | МИР-переводчик | gcc -O2 | gcc -O0 | |
---|---|---|---|---|
компиляция [1] | 1,0 (249 мкс) | 0,09 (22 мкс) | 109 (27,1 мс) | 105 (26,1 мс) |
исполнение [2] | 1,0 (1,74 с) | 13,7 (23,8 с) | 0,92 (1,6 с) | 2,28 (3,97 с) |
размер кода [3] | 1.0 (557 КБ) | 0,43 (240 КБ) | 58 (32,2 МБ) | 58 (32,2 МБ) |
ЛОК [4] | 1,0 (23,4К) | 0,48 (11,3К) | 103 (2420К) | 103 (2402К) |
[1] основано на времени компиляции сито-кода C (без подключаемого файла и с использованием файловой системы памяти для GCC) и соответствующего сито-кода MIR с помощью MIR-интерпретатора и MIR-генератора с уровнем оптимизации 2.
[2] основано на лучшем времени стены из 10 прогонов с использованием используемого MIR-генератора уровня оптимизации 2.
[3] основано на урезанных размерах cc1 для ядра GCC и MIR и интерпретатора или генератора для MIR.
[4] моя оценка основана только на файлах, необходимых для компилятора GNU C x86-64, и файлов MIR для минимальной программы для создания и запуска кода MIR.
Intel i5-13600K с памятью 64 ГБ под FC37 с GCC-12.3.1
c2m -O2 -eg (генератор) | c2m -ei (переводчик) | gcc -O2 | gcc -O0 | |
---|---|---|---|---|
компиляция [1] | 1,0 (336 мкс) | 1,0 (337 мкс) | 80 (27,1 мс) | 77 (26,1 мс) |
исполнение [2] | 1,0 (1,74 с) | 13,7 (23,8 с) | 0,92 (1,6 с) | 2,28 (3,97 с) |
размер кода [3] | 1.0 (961 КБ) | 1.0 (961 КБ) | 34 (32,2 МБ) | 34 (32,2 МБ) |
ЛОК [4] | 1,0 (54,8К) | 1,0 (54,8К) | 44 (2420К) | 44 (2420К) |
[1] основано на времени компиляции кода C sieve (без подключаемого файла и с использованием файловой системы памяти для GCC)
[2] основано на лучшем времени стены из 10 прогонов с использованием используемого MIR-генератора уровня оптимизации 2.
[3] основано на урезанных размерах cc1 для GCC и C2MIR, ядра MIR, интерпретатора и генератора для MIR.
[4] основано на всех исходных файлах, за исключением тестов.
Здесь сгенерирована производительность кода, связанная с GCC -O2, для разных компиляторов C в 15 небольших тестах C (из каталога c-benchmarks
) на той же машине, где
Средний | Геомеанское | |
---|---|---|
gcc -O2 | 1.00 | 1.00 |
gcc -O0 | 0,63 | 0,57 |
c2m -например | 0,96 | 0,91 |
c2m -eb | 0,92 | 0,85 |
Чибикк | 0,38 | 0,30 |
лязг -O2 | 1.12 | 1.09 |
cparser -O3 | 1.02 | 0,98 |
cproc | 0,68 | 0,65 |
лакк -O3 | 0,47 | 0,39 |
пкк -О | 0,80 | 0,78 |
ТСС | 0,54 | 0,50 |
emcc -O2/васмер | 0,60 | 0,55 |
Васи -O2/васмер крановый подъемник | 0,60 | 0,54 |
васи -O2/васмер LLVM | 0,78 | 0,72 |
Васи -O2/васмер однопроходный | 0,45 | 0,36 |
васи -O2/wasmtime | 0,92 | 0,87 |
c2m
) на другую таргет за 1-2 месяца.