#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
คือ function 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
อินไลน์ : อินไลน์การโทร MIR
สร้าง CFG : การสร้างกราฟควบคุมการไหล (บล็อกพื้นฐานและขอบ CFG)
สร้าง SSA : การสร้างแบบฟอร์มการกำหนดสแตติกเดี่ยวโดยการเพิ่มโหนด phi และขอบ SSA ให้กับตัวถูกดำเนินการ
การแปลงที่อยู่ : ลบหรือเปลี่ยนคำสั่ง MIR ADDR
การกำหนดหมายเลขมูลค่าสากล : การลบ insns ที่ซ้ำซ้อนผ่าน GVN ซึ่งรวมถึงการแพร่กระจายอย่างต่อเนื่องและการกำจัดโหลดซ้ำซ้อน
การเผยแพร่สำเนา : การเผยแพร่สำเนา SSA และการลบคำแนะนำส่วนขยายที่ซ้ำซ้อน
การกำจัดร้านค้าที่ตายแล้ว : การลบร้านค้าที่ซ้ำซ้อน
การกำจัดรหัสที่ตายแล้ว : ลบ insns ด้วยเอาต์พุตที่ไม่ได้ใช้
การลดแรงกดทับ : การย้ายโรงพักเพื่อลดแรงกดดันในการลงทะเบียน
SSA รวม : รวมที่อยู่และเปรียบเทียบและคู่คำสั่งแยกสาขา
ออกจาก SSA : การลบโหนด phi และขอบ SSA
Jump opts : การเพิ่มประสิทธิภาพการกระโดดที่แตกต่างกัน
Machinize : รันโค้ดที่ขึ้นอยู่กับเครื่องซึ่งแปลง MIR สำหรับการโทร ABI, 2-op insns ฯลฯ
Find Loops : ค้นหาลูปธรรมชาติและสร้างแผนผังลูป
สร้างข้อมูลสด : คำนวณข้อมูลสดเข้าและออกสำหรับบล็อกพื้นฐาน
สร้างข้อขัดแย้งของการลงทะเบียน : การสร้างเมทริกซ์ข้อขัดแย้งสำหรับการลงทะเบียนที่เกี่ยวข้องกับการย้าย ใช้สำหรับการลงทะเบียนการรวมตัว
Coalesce : การรวมตัวกันของการลงทะเบียนเชิงรุก
Register Allocator (RA) : RA สแกนเชิงเส้นตามลำดับความสำคัญพร้อมการแยกช่วงสัญญาณสด
Build Live Ranges : คำนวณช่วงคะแนนโปรแกรมสำหรับรีจิสเตอร์
กำหนด : fast RA สำหรับ -O0
หรือการสแกนเชิงเส้นตามลำดับความสำคัญ RA สำหรับ -O1
ขึ้นไป
เขียนใหม่ : แปลง MIR ตามการกำหนดโดยใช้ฮาร์ดเร็กที่สงวนไว้
รวม (การเลือกรหัส): รวมอินส์ที่ขึ้นกับข้อมูลเป็นหนึ่งเดียว
การกำจัดรหัสที่ตายแล้ว : ลบ insns ด้วยเอาต์พุตที่ไม่ได้ใช้
Generate Machine Insns : รันโค้ดที่ขึ้นกับเครื่องเพื่อสร้าง machine insns
c2m
ดู README.mdmir.h
และ mir.c
มีโค้ด API ที่สำคัญ รวมถึงอินพุต/เอาต์พุตของไบนารี MIR และการแสดงข้อความ MIRmir-dlist.h
, mir-mp.h
, mir-varr.h
, mir-bitmap.h
, mir-hash.h
, mir-htab.h
, mir-reduce.h
มีโค้ดทั่วไปตามลำดับสำหรับ double-linked รายการ พูลหน่วยความจำ อาร์เรย์ความยาวผันแปร บิตแมป การคำนวณแฮช ตารางแฮช และการบีบอัด/ขยายข้อมูล ไฟล์ 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 JITmir-gen-x86_64.c
, mir-gen-aarch64.c
, mir-gen-ppc64.c
, mir-gen-s390x.c
และ mir-gen-riscv64.c
เป็นโค้ดที่ขึ้นอยู่กับเครื่องของคอมไพเลอร์ JITmir-.c
มีโค้ดธรรมดาที่ขึ้นอยู่กับเครื่อง ซึ่งใช้ร่วมกันสำหรับล่ามและคอมไพเลอร์ JITmir-.h
มีการประกาศทั่วไปสำหรับล่ามและคอมไพเลอร์ JITmir2c/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
สามารถใช้เป็นแบบพกพาเพื่อสร้างไบนารีจากไฟล์ไบนารี MIRmir-utils
มียูทิลิตี้ที่แตกต่างกันเพื่อทำงานกับ MIR เช่น การแปลง MIR ไบนารีเป็น MIR ต้นฉบับและข้อรองadt-tests
, mir-tests
, c-tests
และ c-benchmarks
มีโค้ดสำหรับการทดสอบและการเปรียบเทียบ MIR และ c2m
make bench
และ make test
Intel i5-13600K พร้อมหน่วยความจำ 64GB ภายใต้ FC37 พร้อม GCC-12.3.1
เครื่องกำเนิดไฟฟ้า MIR | MIR-ล่าม | จีซีซี -O2 | จีซีซี -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 sieve (โดยไม่มีไฟล์รวมอยู่ด้วยและด้วยการใช้ระบบไฟล์หน่วยความจำสำหรับ GCC) และโค้ด MIR sieve ที่สอดคล้องกันโดยตัวแปล MIR และเครื่องกำเนิด MIR พร้อมการปรับให้เหมาะสมระดับ 2
[2] อิงตามเวลาผนังที่ดีที่สุด 10 รอบโดยใช้การเพิ่มประสิทธิภาพ MIR-generator ระดับ 2
[3] ขึ้นอยู่กับขนาดที่แยกออกของ cc1 สำหรับแกน GCC และ MIR และล่ามหรือตัวสร้างสำหรับ MIR
[4] การประมาณค่าของฉันขึ้นอยู่กับไฟล์ที่จำเป็นสำหรับคอมไพเลอร์ x86-64 GNU C และไฟล์ MIR สำหรับโปรแกรมขั้นต่ำเพื่อสร้างและรันโค้ด MIR
Intel i5-13600K พร้อมหน่วยความจำ 64GB ภายใต้ FC37 พร้อม GCC-12.3.1
c2m -O2 -เช่น (เครื่องกำเนิดไฟฟ้า) | c2m -ei (ล่าม) | จีซีซี -O2 | จีซีซี -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 sieve (ไม่มีไฟล์รวมและด้วยการใช้ระบบไฟล์หน่วยความจำสำหรับ GCC)
[2] อิงตามเวลาผนังที่ดีที่สุด 10 รอบโดยใช้การเพิ่มประสิทธิภาพ MIR-generator ระดับ 2
[3] ขึ้นอยู่กับขนาดที่แยกออกของ cc1 สำหรับ GCC และ C2MIR, MIR core, ล่าม และตัวสร้างสำหรับ MIR
[4] ขึ้นอยู่กับไฟล์ต้นฉบับทั้งหมด ไม่รวมการทดสอบ
นี่คือประสิทธิภาพของโค้ดที่สร้างขึ้นที่เกี่ยวข้องกับ GCC -O2 สำหรับคอมไพเลอร์ C ที่แตกต่างกันในการวัดประสิทธิภาพ C ขนาดเล็ก 15 รายการ (จากไดเร็กทอรี c-benchmarks
) บนเครื่องเดียวกันกับที่
เฉลี่ย | เรขาคณิต | |
---|---|---|
จีซีซี -O2 | 1.00 น | 1.00 น |
จีซีซี -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 |
พาร์เซอร์ -O3 | 1.02 | 0.98 |
ซีรอค | 0.68 | 0.65 |
แล็คซี -O3 | 0.47 | 0.39 |
พีซีซี -O | 0.80 | 0.78 |
ทีซีซี | 0.54 | 0.50 |
emcc -O2/วอสเมอร์ | 0.60 | 0.55 |
wasi -O2/wasmer เครนลิฟต์ | 0.60 | 0.54 |
wasi -O2/วอสเมอร์ LLVM | 0.78 | 0.72 |
wasi -O2/wasmer singlepass | 0.45 | 0.36 |
วาซิ -O2/วอสม์ไทม์ | 0.92 | 0.87 |
c2m
) ไปยังเป้าหมายอื่นเป็นเวลา 1-2 เดือน