MLIR-based programming language, optimized for DSP and ML workloads.
Ive is a domain-specific language built on top of MLIR (Multi-Level Intermediate Representation) that provides high-level abstracts for tensor operations, automatic differentiation, and optimization for digital signal processing and machine learning applications.
- Tensor Operations: Built-in support for multi-dimensional arrays and operations
- Type Inference: Automatic shape and type deduction
- MLIR Backend: Leverages MLIR's optimization infrastructure
- Multiple Compilation Targets: AST, MLIR, LLVM IR, and JIT execution
- Struct Types: User-defined composite data types
- Generic Functions: Functions that operate on unknown-shaped arguments
- CMake 3.20+
- LLVM/MLIR (compatible version)
- C++17 compatible compiler
- Ninja (optional)
Using Make:
mkdir build
cd build
cmake ..
makeUsing Ninja (recommended):
cmake -B build -G Ninja
cmake --build build./build/ive [options] <input-file>ive(default): Load input file as ive source codemlir: Load input file as MLIR IR
ast: Print the Abstract Syntax Treemlir: Print MLIR representationmlir-affine: Print MLIR after affine loweringmlir-llvm: Print MLIR after LLVM loweringllvm: Print LLVM IRjit: JIT compile and execute (callsmain()function)
--opt: Enable optimization passes
Execute a program:
./build/ive -emit=jit examples/multiply_transpose.iveView AST:
./build/ive -emit=ast examples/multiply_transpose.iveView MLIR:
./build/ive -emit=mlir examples/multiply_transpose.iveView LLVM IR with optimizations:
./build/ive -emit=llvm --opt examples/multiply_transpose.iveLoad and process MLIR file:
./build/ive -x mlir -emit=mlir-llvm examples/multiply_transpose.mlirvar a = [[1, 2, 3], [4, 5, 6]]; # Inferred shape: <2x3>
var b<2, 3> = [1, 2, 3, 4, 5, 6]; # Explicit shape annotation
def multiply_transpose(a, b) {
return transpose(a) * transpose(b);
}
The condition of an if expression must be a 0-dimensional tensor (tensor<f64>).
This means the condition is a scalar tensor value (a 0-dimensional tensor),
not a 1-D vector tensor like tensor<1xf64> or a ranked tensor like
tensor<2x2xf64>.
def main() {
var a = 1;
var b = 2;
if a {
print(a);
}
else {
print(b);
}
if (b) {
print(b);
}
}
Ive supports a 3-operand for loop form:
for i = <init>, <condition>, <step> {
...
}
Rules:
- First operand (
i = <init>) must be an iterator assignment. - Second operand must be a comparison expression (for example
i < 10,i lt n,i le n, etc.) producing Ive truth semantics. - Third operand is the step expression used as
i += stepeach iteration.
Example:
def main() {
var a = 1;
for i=0, i < 10, 1 {
print(a);
a = a + 1;
}
}
Run it with JIT:
./build/ive examples/for.ive -emit=jitCurrent behavior note:
- Constant-bound loops (for example
for i=0, i < 10, 1) execute with loop-carried assignment behavior in codegen, so updates likea = a + 1affect later iterations. - Dynamic-bound loops (for example
for i=0, i < n, 1) are emitted asive.forand lowered through control-flow passes. At the moment, full loop-carried variable update semantics for arbitrary reassigned variables are still evolving.
struct Struct {
var a;
var b;
}
# User defined generic function may operate on struct types as well.
def multiply_transpose(Struct value) {
# We can access the elements of a struct via the '.' operator.
return transpose(value.a) * transpose(value.b);
}
def main() {
# We initialize struct values using a composite initializer.
Struct value = {[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]};
# We pass these arguments to functions like we do with variables.
var c = multiply_transpose(value);
print(c);
}
- Arithmetic:
+,-,*,/ - Comparison:
lt,le,gt,ge,eq,ne - Tensor operations:
transpose(),reshape() - Shape inference: Automatic deduction of result shapes
Ive supports keyword-based comparison operators:
lt(less-than)le(less-than-or-equal)gt(greater-than)ge(greater-than-or-equal)eq(equal)ne(not-equal)
Example:
def main() {
var a = 1;
var b = 2;
var c1 = a lt b;
var c2 = a eq a;
# Comparisons of scalar operands produce scalar truth values,
# represented as a 0-dimensional tensor in Ive.
if c1 {
print(c2);
}
}
llvm-lit -v tests/Automatically generate FileCheck assertions using the provided script:
Setup:
export LLVM_SRC=~/workspace/llvm-projectGenerate checks:
bash gen_checks.sh tests/example.iveThe script will:
- Compile the test file and capture MLIR output
- Auto-generate CHECK assertions based on the output
- Insert the assertions directly into your test file
ive/
├── build/ # Build directory
├── examples/ # Example programs
│ ├── multiply_transpose.ive
│ └── struct.ive
├── include/ive/ # Header files
│ ├── AST.hpp
│ ├── Lexer.hpp
│ ├── Parser.hpp
│ └── Dialect.hpp
├── parser/ # Lexer and Parser implementation
├── mlir/ # MLIR dialect implementation
├── tests/ # LIT tests
│ ├── example.ive
│ └── lit.site.cfg.py
├── utils/ # Utility scripts
│ └── gen_checks.sh
└── main.cpp # Compiler driver
- Create a
.ivefile intests/ - Add RUN directive:
# RUN: %ive %s -emit=mlir 2>&1 | FileCheck %s - Generate checks:
./gen_checks.sh tests/yourtest.ive - Run tests:
llvm-lit -v tests/yourtest.ive
Print AST for debugging parsing issues:
./build/ive -emit=ast examples/yourfile.ivePrint MLIR for type/shape issues:
./build/ive -emit=mlir examples/yourfile.iveContributions are welcome! Please ensure:
- Code follows existing style
- Tests pass:
llvm-lit -v tests/ - New features include test coverage
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. See LICENSE.txt for details.
Built on top of MLIR, part of the LLVM project.