






#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
endmodulefunc อธิบายลายเซ็นต์ของฟังก์ชัน (รับอาร์กิวเมนต์จำนวนเต็มแบบลงนาม 32 บิตและส่งกลับค่าจำนวนเต็มแบบเซ็นชื่อ 32 บิต) และอาร์กิวเมนต์ฟังก์ชัน N ซึ่งจะเป็นตัวแปรโลคัลของประเภทจำนวนเต็มแบบเซ็นชื่อ 64 บิต;string อธิบายข้อมูลในรูปแบบของสตริง Cexport อธิบายฟังก์ชั่นโมดูลหรือข้อมูลที่มองเห็นได้ภายนอกโมดูลปัจจุบันimport อธิบายฟังก์ชันของโมดูลหรือข้อมูลที่ควรกำหนดในโมดูล MIR อื่นproto อธิบายฟังก์ชันต้นแบบ ไวยากรณ์ของมันเหมือนกับไวยากรณ์ funccall เป็นคำสั่ง MIR เพื่อเรียกใช้ฟังก์ชัน MIR_load_externalm1 และ 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-<target>.c มีโค้ดธรรมดาที่ขึ้นอยู่กับเครื่อง ซึ่งใช้ร่วมกันสำหรับล่ามและคอมไพเลอร์ JITmir-<target>.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 เดือน