#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
以C字符串的形式描述数据export
描述当前模块外部可见的模块功能或数据import
描述了应该在其他 MIR 模块中定义的模块函数或数据proto
描述了函数原型。其语法与func
语法相同call
是调用函数的 MIR 指令MIR_load_external
加载外部 C 函数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
在 Linux 上运行二进制 MIR 文件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
可能有点奇怪。 binfmt_misc 上的P
标志传递一个额外的参数,其中包含 MIR 二进制文件的完整路径。
优化流程非常短,速度快且重量轻
仅最有价值的优化用途:
不同的优化级别可调整编译速度与生成的代码性能
MIR 的SSA形式用于寄存器分配之前
针对极端生成代码性能的优化实施的简单性
有关完整 JIT 编译器管道的更多详细信息:
简化:降低 MIR
Inline :内联 MIR 调用
Build CFG :构建控制流图(基本块和CFG边)
构建 SSA :通过向操作数添加 phi 节点和 SSA 边来构建单一静态赋值形式
地址转换:删除或更改 MIR ADDR 指令
全球价值编号:通过 GVN 删除冗余 insn。这包括恒定传播和冗余负载消除
复制传播:SSA复制传播并删除冗余扩展指令
死店消除:删除多余的店
死代码消除:删除具有未使用输出的insn
压力释放:移动insns以降低套准压力
SSA组合:组合地址以及比较和分支指令对
SSA 之外:删除 phi 节点和 SSA 边
Jump opts :不同的跳跃优化
Machinize :运行机器相关代码转换 MIR 以调用 ABI、2-op insns 等
Find Loops :寻找自然循环并构建循环树
构建活信息:计算基本块的活入和活出
构建寄存器冲突:为涉及移动的寄存器构建冲突矩阵。它用于寄存器合并
Coalesce :积极的寄存器合并
寄存器分配器 (RA) :基于优先级的线性扫描 RA,具有生命范围分割
构建生命范围:计算寄存器的程序点范围
分配:用于-O0
的快速RA或用于-O1
及以上的基于优先级的线性扫描RA
重写:使用保留的硬寄存器根据分配转换 MIR
组合(代码选择):将数据依赖的insn合并为一个
死代码消除:删除具有未使用输出的insn
生成机器 Insns :运行与机器相关的代码创建机器 Insns
c2m
实现了一个小型 C11(2011 ANSI C 标准,带有一些 GCC 扩展)。请参阅 README.mdmir.h
和mir.c
包含主要 API 代码,包括 MIR 二进制和 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
包含 MIR JIT 编译器的代码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
中的文件相应包含用于 C 到 MIR 编译器的 x86_64、aarch64、ppc64le、s390x 和 riscv 机器相关代码mir-bin-run.c
包含上述mir-bin-run
的代码b2ctab
实用程序的文件mir-bin-driver.c
可用于从 MIR 二进制文件生成二进制文件的便携式方式mir-utils
包含使用 MIR 的不同实用程序,例如将二进制 MIR 转换为文本 MIR,反之亦然adt-tests
、 mir-tests
、 c-tests
和c-benchmarks
包含用于测试和基准测试 MIR 和c2m
的代码make bench
和make test
运行一些基准测试和测试Intel i5-13600K,FC37 下 64GB 内存,GCC-12.3.1
MIR 发生器 | MIR 解释器 | 海合会-O2 | 海湾合作委员会-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 (557KB) | 0.43 (240KB) | 58 (32.2MB) | 58 (32.2MB) |
LOC [4] | 1.0 (23.4K) | 0.48(11.3K) | 103 (2420K) | 103 (2402K) |
[1] 基于 C 筛代码的编译时间(没有任何包含文件,并且使用 GCC 的内存文件系统)以及由优化级别 2 的 MIR 解释器和 MIR 生成器生成的相应 MIR 筛代码
[2] 基于使用 MIR 生成器优化级别 2 的 10 次运行的最佳运行时间
[3] 基于 GCC 和 MIR 核心的 cc1 的剥离大小以及 MIR 的解释器或生成器
[4] 我的估计仅基于 x86-64 GNU C 编译器所需的文件和用于创建和运行 MIR 代码的最小程序的 MIR 文件
Intel i5-13600K,FC37 下 64GB 内存,GCC-12.3.1
c2m -O2 -eg(发电机) | c2m-ei(解释器) | 海合会-O2 | 海湾合作委员会-O0 | |
---|---|---|---|---|
编译[1] | 1.0 (336us) | 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 (961KB) | 1.0 (961KB) | 34 (32.2MB) | 34 (32.2MB) |
LOC [4] | 1.0 (54.8K) | 1.0 (54.8K) | 44 (2420K) | 44 (2420K) |
[1] 基于 C sieve 代码的编译时间(没有任何包含文件并使用 GCC 内存文件系统)
[2] 基于使用 MIR 生成器优化级别 2 的 10 次运行的最佳运行时间
[3] 基于 GCC 和 C2MIR、MIR 核心、解释器和 MIR 生成器的 cc1 的剥离大小
[4] 基于除测试之外的所有源文件
下面是在同一台机器上针对不同 C 编译器在 15 个小型 C 基准测试(来自目录c-benchmarks
)上生成的与 GCC -O2 相关的代码性能,其中
平均的 | 几何平均法 | |
---|---|---|
海合会-O2 | 1.00 | 1.00 |
海湾合作委员会-O0 | 0.63 | 0.57 |
c2m-eg | 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 |
进程 | 0.68 | 0.65 |
紫胶-O3 | 0.47 | 0.39 |
聚碳酸酯-O | 0.80 | 0.78 |
TCC | 0.54 | 0.50 |
emcc-O2/wasmer | 0.60 | 0.55 |
wasi -O2/wasmer 起重机 | 0.60 | 0.54 |
wasi-O2/wasmer LLVM | 0.78 | 0.72 |
wasi-O2/wasmer 单通道 | 0.45 | 0.36 |
瓦西-O2/wasmtime | 0.92 | 0.87 |
c2m
)移植到另一个目标 1-2 个月