Show HN: Compile C to Not Gates
Introduction to c2fj
The innovative compiler, c2fj, showcases the capability of transforming any C program into a series of NOT operations. This compiler follows a unique path: C → RiscV → Flipjump → .fjm, providing a testament to the versatility and power of compilers. For more insights, you can explore the repositories and discussions on platforms like GitHub and Esolangs.
Example Program: Calculating Primes
int main() {
printf("Calculate primes up to: ");
int max_number;
scanf("%d", &max_number);
...
for (int p = 3; p <= max_number; p += 2) {
if (non_prime[p] == false) {
for (int i = p*p; i <= max_number; i += p) {
non_prime[i] = true;
}
printf("%d\n", p);
}
}
return 0;
}
Upon compilation using c2fj, this program can efficiently calculate prime numbers up to the specified limit. For example, for a limit of 20, the output primes are 2, 3, 5, 7, 11, 13, 17, 19.
Installation Guide
To install c2fj, use the following commands:
>>> pip install c2fj
>>> sudo apt install picolibc-riscv64-unknown-elf
Usage Instructions
To compile your C file, execute:
python3 c2fj.py file.c
This command will compile your C file into an elf, then into fj files, and finally into fjm, before running it.
Supported Flags
- –breakpoints: Place a fj-breakpoint at the start of the specified RiscV addresses.
- –single-step: Place fj-breakpoints at the start of all RiscV opcodes.
- –unify_fj: Unify the generated fj files into a single file.
- –finish-after: Stop the compilation at any step (before running, before creating fjm, etc.).
- –build-dir: Save the builds in this directory.
Handling Projects with Multiple C Files
c2fj supports specifying a Makefile path instead of a single C file. Your Makefile should include constants that c2fj will populate:
- C2FJ_GCC_OPTIONS
- C2FJ_LINKER_SCRIPT
- C2FJ_SOURCES
- C2FJ_INCLUDE_DIRS
- ELF_OUT_PATH
Example Makefile
GCC := riscv64-unknown-elf-gcc
GCC_FLAGS := -O3
SOURCES := $(C2FJ_SOURCES) main.c globals.c calculate_int.c
OBJECTS := $(SOURCES:.c=.o)
all: |
$(GCC) $(C2FJ_GCC_OPTIONS) $(GCC_FLAGS) $(SOURCES) -I $(C2FJ_INCLUDE_DIRS) -T $(C2FJ_LINKER_SCRIPT) -o $(ELF_OUT_PATH)
clean:
rm -r build 2>/dev/null || true
.PHONY: clean all
Technical Insights
The process begins with the compilation of C files into a RiscV elf using picolibc, facilitating the next phase of fj-compilation. Each syscall compiled to a special RiscV opcode is further compiled into the fj implementation of the requested syscall, as defined in c2fj_init.c.
The RiscV to FlipJump compilation converts each opcode into the appropriate flipjump macro, optimizing space to handle extensive C code bases efficiently.
Execution and Optimization
Using flipjump macros,