IRx is a Python library that lowers ARXLang ASTx nodes to LLVM IR using llvmlite. It provides a visitor-based codegen pipeline and a small builder API that can translate ASTs to LLVM IR text or produce runnable executables via clang.
Status: early but functional. Arithmetic, variables, functions, returns, basic control flow, and a few system-level expressions (e.g.
PrintExpr) are supported.
-
ASTx → LLVM IR via multiple-dispatch visitors (
plum). -
Back end: IR construction and object emission with llvmlite.
-
Native build: links with
clangto produce an executable. -
Optional runtime features: native capabilities are feature-gated per compilation unit instead of being linked into every binary.
-
PIE-friendly objects: emits PIC-compatible objects by default to work with modern PIE-default linkers.
-
Supported nodes (subset; exact ASTx class names):
- Literals:
LiteralInt16,LiteralInt32,LiteralString - Variables:
Variable,VariableDeclaration,InlineVariableDeclaration - Ops:
UnaryOp(++,--),BinaryOp(+ - * / < >) with simple type promotion - Flow:
IfStmt,ForCountLoopStmt,ForRangeLoopStmt - Functions:
FunctionPrototype,Function,FunctionReturn,FunctionCall - System:
system.PrintExpr(string printing)
- Literals:
-
Built-ins:
putchar,putchard(emitted as IR);putsdeclaration when needed. -
Optional native runtimes:
libcexterns are routed through the runtime feature layer, and Arrow is now available as an optional native runtime feature.
- Python 3.10 – 3.13.
- A recent LLVM/Clang toolchain available on
PATH. - A working C standard library (e.g., system libc) for linking calls like
puts. - Python deps:
llvmlite,pytest, etc. (seepyproject.toml/requirements.txt).- Note: llvmlite has specific Python/LLVM compatibility windows; see its docs.
git clone https://github.com/arxlang/irx.git cd irx conda env create --file conda/dev.yaml conda activate irx poetry installYou can also install it from PyPI: pip install pyirx.
More details: https://irx.arxlang.org/installation/
import astx from irx.builders.llvmliteir import LLVMLiteIR builder = LLVMLiteIR() module = builder.module() # int main() { return 0; } proto = astx.FunctionPrototype("main", astx.Arguments(), astx.Int32()) body = astx.Block() body.append(astx.FunctionReturn(astx.LiteralInt32(0))) module.block.append(astx.Function(prototype=proto, body=body)) ir_text = builder.translate(module) print(ir_text) # LLVM IR text (str)translate returns a str with LLVM IR. It does not produce an object file or binary; use it for inspection, tests, or feeding another tool.
import astx from irx.builders.llvmliteir import LLVMLiteIR from irx.system import PrintExpr builder = LLVMLiteIR() module = builder.module() # int main() { print("Hello, IRx!"); return 0; } main_proto = astx.FunctionPrototype("main", astx.Arguments(), astx.Int32()) body = astx.Block() body.append(PrintExpr(astx.LiteralString("Hello, IRx!"))) body.append(astx.FunctionReturn(astx.LiteralInt32(0))) module.block.append(astx.Function(prototype=main_proto, body=body)) builder.build(module, "hello") # emits object + links with clang builder.run() # executes ./hello (or hello.exe on Windows)-
LLVMLiteIR(public API)translate(ast) -> str— generate LLVM IR text.build(ast, output_path)— emit object via llvmlite and link withclang.run()— execute the produced binary.
-
LLVMLiteIRVisitor(codegen)- Uses
@dispatchto visit each ASTx node type. - Maintains a value stack (
result_stack) and symbol table (named_values). - Emits LLVM IR with
llvmlite.ir.IRBuilder.
- Uses
PrintExpr is an astx.Expr holding a LiteralString. Its lowering:
- Create a global constant for the string (with
\0). - GEP to an
i8*pointer. - Declare (or reuse)
i32 @puts(i8*). - Call
puts.
IRx now has a generic runtime-feature system for native integrations that do not belong as handwritten LLVM container logic.
- Features are registered by name, such as
libcandarrow. - Features can declare external symbols, native C sources, objects, or static libraries.
- The linker only compiles and links artifacts for features that are active in the current compilation unit.
- This is intentionally separate from any future Arx import/module layer.
Arrow uses this path as its first substantial consumer:
- native runtime implemented in C under
src/irx/runtime/arrow/ - opaque
irx_arrow_*handles only - Arrow C Data import/export boundary
- Python
nanoarrowinstalled by default for interop and tests arx-nanoarrow-sourcesinstalled by default for native runtime builds
The current MVP is intentionally narrow: primitive int32 arrays, lifecycle operations, inspection, and C Data roundtrip support. No full Arrow container semantics are encoded directly in LLVM IR.
pytest -vvExample style (simplified):
def test_binary_op_basic(): builder = LLVMLiteIR() module = builder.module() decl_a = astx.VariableDeclaration("a", astx.Int32(), astx.LiteralInt32(1)) decl_b = astx.VariableDeclaration("b", astx.Int32(), astx.LiteralInt32(2)) a, b = astx.Variable("a"), astx.Variable("b") expr = astx.LiteralInt32(1) + b - a * b / a proto = astx.FunctionPrototype("main", astx.Arguments(), astx.Int32()) block = astx.Block() block.append(decl_a); block.append(decl_b) block.append(astx.FunctionReturn(expr)) module.block.append(astx.Function(proto, block)) ir_text = builder.translate(module) assert "add" in ir_text-
Ensure Xcode Command Line Tools are installed:
xcode-select --install. -
Verify
clang --versionworks. -
If needed:
export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
-
CI note: macOS jobs currently run on Python 3.12 only.
- Define
mainto returnInt32and emitreturn 0. Falling off the end or returningvoidcan yield an arbitrary exit code.
- A visitor is missing
@dispatchor is typed against a different class than the one instantiated. Ensure signatures match the exact runtime class (e.g.,visit(self, node: PrintExpr)).
- Install a recent LLVM/Clang. On Linux, use distro packages.
- On macOS, install Xcode CLT.
- On Windows, ensure LLVM’s
bindirectory is onPATH.
-
This usually means your linker is enforcing PIE while the object was compiled with non-PIE relocations.
-
Current IRx defaults to PIC-compatible object emission, which should work with PIE-default linkers.
-
If you are using an older ARX/IRX stack, update first.
-
If you must link externally as a workaround, use:
clang -no-pie file.o -o program
- Linux & macOS: supported and used in CI.
- Windows: expected to work with a proper LLVM/Clang setup; consider it experimental.
builder.run()will executehello.exe.
- More ASTx coverage (booleans, arrays, structs, varargs/options).
- Richer stdlib bindings (I/O, math).
- Optimization toggles/passes.
- Alternative backends and/or JIT runner.
- Better diagnostics and source locations in IR.
- Expand optional Apache Arrow runtime support: nullable arrays, more primitive types, streams, and higher-level handles.
Please see the contributing guide. Add tests for new features and keep visitors isolated (avoid special-casing derived nodes inside generic visitors).
- LLVM and llvmlite for the IR infrastructure.
- ASTx / ARXLang for the front-end AST.
- Contributors and users experimenting with IRx.
License: BSD-3-Clause. See LICENSE.