
shecc dibuat dari awal, menargetkan arsitektur Arm 32-bit dan RISC-V, sebagai kompiler kompilasi mandiri untuk subset bahasa C. Meskipun sifatnya sederhana, ia mampu melakukan strategi pengoptimalan dasar sebagai kompiler pengoptimalan yang berdiri sendiri.
shecc mampu mengkompilasi file sumber C yang ditulis dalam sintaks berikut:
+= , -= , *=int i = [expr]#define , #ifdef , #elif , #endif , #undef , dan #error__VA_ARGS__Backend menargetkan armv7hf dengan Linux ABI, diverifikasi pada Raspberry Pi 3, dan juga mendukung arsitektur RISC-V 32-bit, diverifikasi dengan QEMU.
Langkah-langkah untuk memvalidasi shecc bootstrapping:
stage0 : kode sumber shecc awalnya dikompilasi menggunakan kompiler biasa yang menghasilkan executable asli. Kompiler yang dihasilkan dapat digunakan sebagai kompiler silang.stage1 : Biner yang dibangun membaca kode sumbernya sendiri sebagai input dan menghasilkan biner ARMv7-A/RV32IM.stage2 : Biner ARMv7-A/RV32IM yang dihasilkan dipanggil (melalui QEMU atau dijalankan pada perangkat Arm dan RISC-V) dengan kode sumbernya sendiri sebagai input dan menghasilkan biner ARMv7-A/RV32IM lainnya.bootstrap : Bangun kompiler stage1 dan stage2 , dan verifikasi bahwa keduanya identik dalam byte. Jika demikian, shecc dapat mengkompilasi kode sumbernya sendiri dan menghasilkan versi baru dari program yang sama. Pembuat kode di shecc tidak bergantung pada utilitas eksternal. Anda hanya memerlukan kompiler C biasa seperti gcc dan clang . Namun, shecc akan melakukan bootstrap sendiri, dan emulasi ISA Arm/RISC-V diperlukan. Instal QEMU untuk emulasi pengguna Arm/RISC-V di GNU/Linux:
$ sudo apt-get install qemu-user shecc masih dapat dibuat di macOS atau Microsoft Windows. Namun, bootstrap tahap kedua akan gagal karena tidak adanya qemu-arm .
Untuk menjalankan tes snapshot, instal paket di bawah ini:
$ sudo apt-get install graphviz jq Konfigurasikan backend mana yang Anda inginkan, shecc mendukung backend ARMv7-A dan RV32IM:
$ make config ARCH=arm
# Target machine code switch to Arm
$ make config ARCH=riscv
# Target machine code switch to RISC-V
Jalankan make dan Anda akan melihat ini:
CC+LD out/inliner
GEN out/libc.inc
CC out/src/main.o
LD out/shecc
SHECC out/shecc-stage1.elf
SHECC out/shecc-stage2.elf
File out/shecc adalah kompiler tahap pertama. Penggunaannya:
$ shecc [-o output] [+m] [--no-libc] [--dump-ir] < infile.c >Opsi kompiler:
-o : Tentukan nama file keluaran (default: out.elf )+m : Gunakan instruksi perkalian/pembagian perangkat keras (default: dinonaktifkan)--no-libc : Kecualikan pustaka C yang tertanam (default: tertanam)--dump-ir : Membuang representasi perantara (IR)Contoh:
$ out/shecc -o fib tests/fib.c
$ chmod +x fib
$ qemu-arm fib Verifikasi bahwa IR yang dipancarkan identik dengan snapshot dengan menentukan target check-snapshots saat memanggil make :
$ make check-snapshots shecc hadir dengan unit test. Untuk menjalankan pengujian, berikan check sebagai argumen:
$ make checkKeluaran referensi:
...
int main(int argc, int argv) { exit(sizeof(char)); } => 1
int main(int argc, int argv) { int a; a = 0; switch (3) { case 0: return 2; case 3: a = 10; break; case 1: return 0; } exit(a); } => 10
int main(int argc, int argv) { int a; a = 0; switch (3) { case 0: return 2; default: a = 10; break; } exit(a); } => 10
OK
Untuk membersihkan file kompiler yang dihasilkan, jalankan perintah make clean . Untuk mengatur ulang konfigurasi arsitektur, gunakan perintah make distclean .
Setelah opsi --dump-ir diteruskan ke shecc , representasi perantara (IR) akan dihasilkan. Ambil file tests/fib.c misalnya. Ini terdiri dari fungsi deret Fibonacci rekursif.
int fib ( int n )
{
if ( n == 0 )
return 0 ;
else if ( n == 1 )
return 1 ;
return fib ( n - 1 ) + fib ( n - 2 );
}Jalankan yang berikut ini untuk menghasilkan IR:
$ out/shecc --dump-ir -o fib tests/fib.cPenjelasan baris demi baris antara sumber C dan IR:
C Source IR Explanation
-- -- -- -- -- -- -- -- -- + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
int fib ( int n ) def int @ fib ( int % n ) Indicate a function definition
{ {
if ( n == 0 ) const %. t1001 , $0 Load constant 0 into a temporary variable ".t1001"
%. t1002 = eq % n , %. t1001 Test "n" equals ".t1001" or not , and write the result in temporary variable ".t1002"
br %. t1002 , . label . 1177 , . label . 1178 If ".t1002" equals zero , goto false label ".label.1178" , otherwise ,
goto true label ".label.1177"
. label . 1177
return 0 ; const %. t1003 , $0 Load constant 0 into a temporary variable ".t1003"
ret %. t1003 Return ".t1003"
j . label . 1184 Jump to endif label ".label.1184"
. label . 1178
else if ( n == 1 ) const %. t1004 , $1 Load constant 1 into a temporary variable ".t1004"
%. t1005 = eq % n , %. t1004 Test "n" equals ".t1004" or not , and write the result in temporary variable ".t1005"
br %. t1005 , . label . 1183 , . label . 1184 If ".t1005" equals zero , goto false label ".label.1184" . Otherwise ,
goto true label ".label.1183"
. label . 1183
return 1 ; const %. t1006 , $1 Load constant 1 into a temporary variable ".t1006"
ret %. t1006 Return ".t1006"
. label . 1184
return
fib ( n - 1 ) const %. t1007 , $1 Load constant 1 into a temporary variable ".t1007"
%. t1008 = sub % n , %. t1007 Subtract ".t1007" from "n" , and store the result in temporary variable ".t1008"
push %. t1008 Prepare parameter for function call
call @ fib , 1 Call function " fib " with one parameter
+ retval %. t1009 Store return value in temporary variable ". t1009 "
fib ( n - 2 ); const %. t1010 , $2 Load constant 2 into a temporary variable ".t1010"
%. t1011 = sub % n , %. t1010 Subtract ".t1010" from "n" , and store the result in temporary variable ".t1011"
push %. t1011 Prepare parameter for function call
call @ fib , 1 Call function " fib " with one parameter
retval %. t1012 Store return value in temporary variable ". t1012 "
%. t1013 = add %. t1009 , %. t1012 Add ". t1009 " and ". t1012 ", and store the result in temporary variable " . t1013 "
ret %. t1013 Return ".t1013"
} }<stdarg.h> yang dapat digunakan. Alternatifnya, periksa implementasi printf di source lib/cc untuk var_arg . shecc dapat didistribusikan ulang secara bebas di bawah lisensi klausa BSD 2. Penggunaan kode sumber ini diatur oleh lisensi bergaya BSD yang dapat ditemukan di file LICENSE .