Files
libvct-spec/spec/001-architecture.md

4.8 KiB

001 — Architecture

  • Status: Draft
  • Normative language: MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as described in RFC 2119.

1. Overview

libVCT is decomposed into modules with explicit responsibilities and boundaries. This file defines the module map, the data flow between stages, the three public interfaces, and the boundaries that carry the design's weight.

2. Modules

Module Responsibility Allocation Visibility
vct.ir.hir HIR AST node types, the trait attachment point, builder/emitter API arena public
vct.ir.vir VIR SSA/CFG types, VIR type system, instruction set arena internal
vct.traits Attribute / Request / Relationship definitions and queries arena public
vct.comptime Comptime evaluator / constant-folding engine arena internal
vct.hir.opt HIR pass framework and passes, parallel cascade arena internal
vct.lower HIR → VIR lowering and SSA construction arena internal
vct.vir.opt VIR pass framework and heavy passes arena internal
vct.backend.c VIR → C17 emitter (out-of-SSA, compiler-friendly C) arena + GC public entry
vct.backend.llvm VIR → textual LLVM IR emitter arena + GC public entry
vct.driver C compiler invocation, flag assembly, .o emission, LTO, cosmopolitan GC public
vct.cli Thin command-line wrapper GC public
vct.diag Diagnostics, source maps, error reporting GC public
vct.context Context and arena ownership, Config GC + arena public
vct.test.hirbuild Fluent HIR test-builder harness arena public

3. Data flow

The default pipeline is:

frontend --build--> HIR
    --hir.opt (parallel, cascading)--> annotated HIR
    --lower--> VIR (SSA/CFG)
    --vir.opt--> optimized VIR
    --backend.c--> C17 source --driver--> .o          (default path)

optimized VIR --backend.llvm--> textual LLVM IR       (caller links LLVM)

Each stage consumes the previous stage's output and is specified independently: 003 — HIR, 004 — HIR Optimizer, 005 — Lowering, 006 — VIR, 007 — VIR Optimizer, 008 — C Backend, and 009 — LLVM Backend.

4. Public interfaces

libVCT exposes exactly three interfaces to embedders:

  1. HIR builder (frontend-facing). Construct nodes, set types and values, attach frontend-supplied traits (such as is_static and optimization hints), and finish a module. See 003 — HIR.
  2. Trait query (VIR-facing). Read attributes and walk relationships. This is the only channel through which VIR obtains facts. See 002 — Traits.
  3. Backend (driver-facing). Consume optimized VIR and emit C or textual LLVM IR. See 008 — C Backend and 009 — LLVM Backend.

The native D API is the full-feature surface. A thin extern(C) C API (opaque handles for Context/Module/Builder/Config) is the primary v1 public surface and is a shim over the D API; no logic lives in the shim. See 013 — Build & Packaging.

5. Load-bearing boundaries

  • vct.traits is the contract. Both HIR and VIR depend on it. VIR depends on nothing else from HIR except node identity. A change to the trait vocabulary is a cross-cutting change and is versioned accordingly (see 013 — Build & Packaging).
  • vct.lower is the SSA construction site. Phi-nodes, dominance, and the memory model all land there; it is the most algorithmically dense module. Its correctness invariants are specified in 005 — Lowering and 006 — VIR.

6. Memory and ownership model

  • A Context owns one or more arenas. An arena is the unit of reclamation; the default is one arena per Module, freed wholesale.
  • All IR and optimizer objects are arena-owned and non-GC. Passes mutate in place under epoch guards (see 002 — Traits).
  • GC is permitted only on cold paths: the driver, diagnostics, and CLI.
  • The arena interface is exposed so embedders can supply their own backing memory; a default bump allocator ships in-tree.

Full lifecycle, ownership, and threading rules are specified in 013 — Build & Packaging.

7. Threading

libVCT is thread-safe when each compilation unit has its own Context and arenas. There is no shared mutable global state. Intra-module parallelism is internal and bounded by the -j setting. The determinism guarantee in 000 — Overview applies regardless of thread count.