#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비트 부호 있는 정수 값을 반환함)과 64비트 부호 있는 정수 유형의 지역 변수가 될 함수 인수 N
을 설명합니다.;
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 바이너리에 대한 전체 경로가 포함된 추가 인수를 전달합니다.
속도와 경량화를 위한 매우 짧은 최적화 파이프라인
가장 가치 있는 최적화 용도만:
컴파일 속도와 생성된 코드 성능을 조정하기 위한 다양한 최적화 수준
SSA 형식의 MIR은 레지스터 할당 전에 사용됩니다.
극도로 생성된 코드 성능에 대한 최적화 구현의 단순성
전체 JIT 컴파일러 파이프라인 에 대한 자세한 내용:
단순화 : MIR 낮추기
인라인 : MIR 호출 인라인
CFG 구축 : 제어 흐름 그래프 구축(기본 블록 및 CFG 에지)
SSA 구축 : 피연산자에 phi 노드 및 SSA 에지를 추가하여 단일 정적 할당 양식 구축
주소 변환 : MIR ADDR 명령어 제거 또는 변경
Global Value Numbering : GVN을 통해 중복된 기능을 제거합니다. 여기에는 지속적인 전파 및 중복 로드 제거가 포함됩니다.
Copy Propagation : SSA 복사 전파 및 중복 확장 지침 제거
데드스토어 제거(Dead Store Removal ) : 중복스토어 제거
데드 코드 제거(Dead Code Elimination ): 사용하지 않는 출력이 있는 insns 제거
압력 완화 : 레지스터 압력을 감소시키기 위한 이동 기능
SSA 결합 : 주소 결합, 비교 및 분기 명령어 쌍
SSA 외부 : phi 노드 및 SSA 에지 제거
Jump opts : 다양한 점프 최적화
Machinize : 호출 ABI, 2-op insns 등을 위해 MIR을 변환하는 기계 종속 코드를 실행합니다.
루프 찾기 : 자연스러운 루프 찾기 및 루프 트리 구축
Build Live Info : 기본 블록에 대한 라이브 인 및 라이브 아웃 계산
Build Register Con conflicts : 이동과 관련된 레지스터에 대한 충돌 매트릭스를 구축합니다. 레지스터 병합에 사용됩니다.
Coalesce : 공격적인 레지스터 병합
RA(Register Allocator) : 실시간 범위 분할 기능을 갖춘 우선순위 기반 선형 스캔 RA
Build Live Ranges : 레지스터의 프로그램 포인트 범위 계산
할당 : -O0
의 경우 빠른 RA 또는 -O1
이상의 경우 우선순위 기반 선형 스캔 RA
재작성 : 예약된 하드 규정을 사용하여 할당에 따라 MIR을 변환합니다.
결합 (코드 선택): 데이터에 의존하는 기능을 하나로 병합
데드 코드 제거(Dead Code Elimination ): 사용하지 않는 출력이 있는 insns 제거
기계 기능 생성 : 기계 기능을 생성하는 기계 종속 코드 실행
c2m
에 작은 C11(일부 GCC 확장이 포함된 2011 ANSI C 표준)을 구현했습니다. README.md를 참조하세요.mir.h
및 mir.c
파일에는 MIR 바이너리 및 MIR 텍스트 표현의 입력/출력을 포함한 주요 API 코드가 포함되어 있습니다.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
and make test
통해 일부 벤치마크와 테스트를 실행할 수 있습니다. GCC-12.3.1을 갖춘 FC37에서 64GB 메모리를 갖춘 Intel i5-13600K
MIR 발생기 | MIR 해석기 | gcc -O2 | gcc -O0 | |
---|---|---|---|---|
편집 [1] | 1.0 (249us) | 0.09 (22us) | 109 (27.1ms) | 105(26.1ms) |
처형 [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) |
위치 [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 파일만을 기반으로 한 추정입니다.
GCC-12.3.1을 갖춘 FC37에서 64GB 메모리를 갖춘 Intel i5-13600K
c2m -O2 -eg (발전기) | c2m -ei(통역사) | gcc -O2 | gcc -O0 | |
---|---|---|---|---|
편집 [1] | 1.0 (336us) | 1.0 (337us) | 80 (27.1ms) | 77(26.1ms) |
처형 [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) |
위치 [4] | 1.0 (54.8K) | 1.0 (54.8K) | 44 (2420K) | 44(2420K) |
[1]은 C 시브 코드 컴파일의 실제 시간을 기준으로 합니다(포함 파일 없음 및 GCC용 메모리 파일 시스템 사용).
[2]는 사용된 MIR 생성기 최적화 레벨 2를 사용한 10회 실행의 최고 벽 시간을 기반으로 합니다.
[3]은 GCC 및 C2MIR용 cc1, MIR 코어, 인터프리터 및 MIR용 생성기의 제거된 크기를 기반으로 합니다.
[4]는 테스트를 제외한 모든 소스 파일을 기반으로 합니다.
다음은 동일한 머신의 15개 소규모 C 벤치마크( c-benchmarks
디렉토리)에서 다양한 C 컴파일러에 대해 GCC -O2와 관련하여 생성된 코드 성능입니다.
평균 | 기하평균 | |
---|---|---|
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 |
lacc -O3 | 0.47 | 0.39 |
PCC -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 |
wasi -O2/wasmtime | 0.92 | 0.87 |
c2m
포함)을 다른 대상으로 포팅할 수 있습니다.