
shecc wurde von Grund auf neu entwickelt und zielt sowohl auf 32-Bit-Arm- als auch auf RISC-V-Architekturen als selbstkompilierender Compiler für eine Teilmenge der C-Sprache ab. Trotz seiner einfachen Natur ist es in der Lage, grundlegende Optimierungsstrategien als eigenständiger Optimierungscompiler durchzuführen.
shecc ist in der Lage, C-Quelldateien zu kompilieren, die in der folgenden Syntax geschrieben sind:
+= , -= , *=int i = [expr]#define , #ifdef , #elif , #endif , #undef und #error__VA_ARGS__Das Backend zielt auf armv7hf mit Linux ABI ab, verifiziert auf Raspberry Pi 3, und unterstützt auch die RISC-V 32-Bit-Architektur, verifiziert mit QEMU.
Die Schritte zur Validierung shecc Bootstrappings:
stage0 : shecc Quellcode wird zunächst mit einem gewöhnlichen Compiler kompiliert, der eine native ausführbare Datei generiert. Der generierte Compiler kann als Cross-Compiler verwendet werden.stage1 : Die erstellte Binärdatei liest ihren eigenen Quellcode als Eingabe und generiert eine ARMv7-A/RV32IM-Binärdatei.stage2 : Die generierte ARMv7-A/RV32IM-Binärdatei wird aufgerufen (über QEMU oder läuft auf ARM- und RISC-V-Geräten) mit ihrem eigenen Quellcode als Eingabe und generiert eine weitere ARMv7-A/RV32IM-Binärdatei.bootstrap : Erstellen Sie die Compiler stage1 und stage2 und stellen Sie sicher, dass sie byteweise identisch sind. Wenn ja, kann shecc seinen eigenen Quellcode kompilieren und neue Versionen desselben Programms erstellen. Der Codegenerator in shecc ist nicht auf externe Dienstprogramme angewiesen. Sie benötigen lediglich gewöhnliche C-Compiler wie gcc und clang . Allerdings würde sich shecc selbst booten und eine ARM/RISC-V-ISA-Emulation ist erforderlich. Installieren Sie QEMU für die Arm/RISC-V-Benutzeremulation unter GNU/Linux:
$ sudo apt-get install qemu-user Es ist weiterhin möglich, shecc auf macOS oder Microsoft Windows zu erstellen. Das Bootstrapping der zweiten Stufe würde jedoch aufgrund des Fehlens qemu-arm fehlschlagen.
Um den Snapshot-Test auszuführen, installieren Sie die folgenden Pakete:
$ sudo apt-get install graphviz jq Konfigurieren Sie das gewünschte Backend. shecc unterstützt ARMv7-A- und RV32IM-Backend:
$ make config ARCH=arm
# Target machine code switch to Arm
$ make config ARCH=riscv
# Target machine code switch to RISC-V
Führen Sie make aus und Sie sollten Folgendes sehen:
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 ist der Compiler der ersten Stufe. Seine Verwendung:
$ shecc [-o output] [+m] [--no-libc] [--dump-ir] < infile.c >Compiler-Optionen:
-o : Geben Sie den Namen der Ausgabedatei an (Standard: out.elf ).+m : Hardware-Multiplikations-/Divisionsanweisungen verwenden (Standard: deaktiviert)--no-libc : Eingebettete C-Bibliothek ausschließen (Standard: eingebettet)--dump-ir : Zwischendarstellung (IR) ausgebenBeispiel:
$ out/shecc -o fib tests/fib.c
$ chmod +x fib
$ qemu-arm fib Stellen Sie sicher, dass die ausgegebenen IRs mit den Snapshots identisch sind, indem Sie beim Aufruf make das Ziel check-snapshots angeben:
$ make check-snapshots shecc kommt mit Unit-Tests. Um die Tests auszuführen, geben Sie check als Argument an:
$ make checkReferenzausgabe:
...
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
Um die generierten Compilerdateien zu bereinigen, führen Sie den Befehl make clean aus. Verwenden Sie zum Zurücksetzen von Architekturkonfigurationen den Befehl make distclean .
Sobald die Option --dump-ir an shecc übergeben wird, wird die Zwischendarstellung (IR) generiert. Nehmen Sie zum Beispiel die Datei tests/fib.c . Es besteht aus einer rekursiven Fibonacci-Folgenfunktion.
int fib ( int n )
{
if ( n == 0 )
return 0 ;
else if ( n == 1 )
return 1 ;
return fib ( n - 1 ) + fib ( n - 2 );
}Führen Sie Folgendes aus, um IR zu generieren:
$ out/shecc --dump-ir -o fib tests/fib.cZeilenweise Erklärung zwischen C-Quelle und 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> verwendet werden. Alternativ können Sie die Implementierung printf in der lib/cc auf var_arg prüfen. shecc ist unter der BSD-2-Klausel-Lizenz frei weiterverbreitbar. Die Nutzung dieses Quellcodes unterliegt einer BSD-ähnlichen Lizenz, die in der LICENSE Datei zu finden ist.