Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

197 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

d2qbe: D language to QBE language compiler

usage

how to compile executables step-by-step.

make all
./d2qbe "main { return 0; }" > a.ssa
./qbe/qbe < a.ssa > a.s
cc a.s -o a.out
./a.out

roadmap

  • tiny self hosted compiler of betterC D language
    • int arith
    • int variables
    • control statements (if-else, for, while)
    • external call of functions precompiled with ldc2
    • multi-int to single int function def and call
    • pointer
    • sizeof
    • array (pointer arithmetic and indexing)
    • global variables
    • string
    • structs, member functions, constructors & destructors (RAII)
    • switch statements & ternary operator
    • multidimensional arrays & slices
    • type aliases (alias) & type properties (.init, .alignof)
    • conditional compilation (version and debug blocks)
    • type inference (auto declarations)
    • generics & templates (template Name(T) { ... }, eponymous Name!Arg)
    • modular compilation (native module and recursive import compilation)
    • floating point support (float, double arithmetic, conversions & registers)
    • compound self-assignments (+=, -=, etc.)
    • byte-sized function parameters safety (char/bool parameter stack stores)
    • frontend SSA optimization (direct emission of QBE SSA phi instructions for ternary operations)
    • foreach and foreach_reverse loops
    • scope(exit) statements
  • full set of betterC D language https://dlang.org/spec/betterc.html#consequences (Self-hosted compiler is 100% complete for the supported subset, but some standard betterC features are missing.)

Unsupported / Missing betterC Features

While d2qbe compiles a very large and self-hosting subset of D betterC, the following standard D features are currently unsupported:

  1. scope(success) & scope(failure): These are disallowed under -betterC by standard compilers (like LDC) due to disabled exception handling/unwinding; our compiler errors out on them to guide standard compliance.
  2. Reference Parameters & Variables (ref): Passing parameters to functions by reference and loop variables referencing the underlying array elements are not supported.
  3. Uniform Function Call Syntax (UFCS): True UFCS for free-standing functions is not supported.
  4. Range-Based foreach Loops: Iterating over custom structs defining standard range primitives (front, empty, popFront).
  5. Compile-Time Function Execution (CTFE): There is no interpreter to evaluate custom functions at compile-time.
  6. Advanced Templates: Multiple parameters, variadic parameters, constraints, and specializations are not supported (only eponymous templates with a single type parameter).
  7. C++ Classes & Interfaces: extern(C++) class (which is standard betterC compatible as it does not use GC) is unsupported.
  8. Delegates & Lambda Functions: Anonymous lambda literals, closure delegates, and scope variable storage classes/lifetime annotations are not implemented.
  9. opApply Delegate-Based Loops: Custom struct iteration using delegates.

benchmarks

We compared our custom D-to-assembly compiler toolchain against standard production toolchains using a floating-point heavy Mandelbrot set rendering loop (test/mandel.d) on linux/x86_64.

Mandelbrot End-to-End Performance

  • Target Program: test/mandel.d (Renders the Mandelbrot set 50 times in a loop).
  • Binaries Compared:
    • Ours: Our custom D compiler toolchain (d2qbe + dqbe + cc assembler/linker).
    • Hybrid: A hybrid toolchain using our custom frontend (d2qbe) combined with the upstream optimizing QBE compiler (qbe/qbe) and cc.
    • LDC2: The standard production D compiler (ldc2 -O3 -betterC).
Metric Ours (d2qbe + dqbe) Hybrid (d2qbe + QBE) LDC2 -O3 (Production)
Compile Time 0.04 s 0.06 s 0.07 s
Compile Memory (Max RSS) 10.0 MB 9.8 MB 97.7 MB
Binary Size (Stripped) 14,536 bytes 14,536 bytes 14,480 bytes
Execution Time (50x runs) 1.36 s 0.25 s 0.23 s
Execution Memory (Max RSS) 1.6 MB 1.6 MB 1.6 MB

Multi-Benchmark Execution Suite

To verify compilation correctness and register pressure under different workloads, we compared execution runtimes (in seconds) across four diverse benchmark types:

Benchmark Ours (d2qbe + dqbe) Hybrid (d2qbe + QBE) LDC2 -O3 (Production)
Mandelbrot (Floating-point) 1.36 s 0.25 s 0.23 s
Collatz (Control-flow) 0.53 s 0.28 s 0.07 s
Primes (Modulo math) 0.06 s 0.02 s 0.02 s
N-Queens (Recursion & Arrays) 4.00 s 0.74 s 0.21 s

Key Insights:

  1. Lightweight & Fast Compilation: By utilizing __gshared memory for compiler global tables under -betterC, our toolchain compiles 2x faster than LDC2 (0.04s vs 0.07s) and uses 9.7x less memory (10.0MB vs 97.7MB).
  2. Optimal Frontend Generation: When coupled with upstream QBE's backend optimizer, our custom frontend code generator matches the production-optimized LLVM code generation of LDC2 within 0.02 seconds (0.25s vs 0.23s) and recurses extremely efficiently in N-Queens.
  3. Global Register Allocation: We implemented a complete Linear Scan Register Allocator (allocating 5 GPRs %rbx, %r12..%r15 and 6 FPRs %xmm8..%xmm13 globally) alongside SSA Deconstruction (lowering phi instructions using parallel copies to prevent swap cycles). Together, this delivers massive execution speedups on complex loop-heavy and recursive programs (e.g. Mandelbrot execution time dropped from 1.70s to 1.36s, a 20% further speedup!).

references

About

Tiny betterC D language compiler with QBE clone

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages