SimpLang is a domain-specific language (DSL) designed to facilitate SIMD hardware optimization, particularly for deep learning applications. It provides high-level abstractions for SIMD operations, coupled with robust debugging and runtime infrastructure.
- LLVM 14 or later
- CMake 3.20+
- C++17 compatible compiler
- Boost libraries
# Ubuntu/Debian
sudo apt update
sudo apt install -y \
llvm-14-dev \
clang-14 \
cmake \
libboost-dev
You have two options for building:
- Using build script (recommended)
./build.sh
- Manual CMake build
# Configure with SIMD debugging enabled
cmake -B build -DSIMD_DEBUG=ON
# Build the compiler
cmake --build build --target simplang
Execute the test suite using:
./run_tests.sh
- Compile a SimpLang Kernel
# Syntax: ./build/src/simplang <input_file.sl>
./build/src/simplang my_kernel.sl
- Run a Compiled Kernel
# Syntax: ./build/tests/test_loop_runner <path_to_compiled_kernel.so>
./build/tests/test_loop_runner ./build/tests/obj/test_loop.so
- Create a SimpLang kernel (
test_loop.sl
):
fn kernel_main() {
var sum = 0.0;
var i = 1.0;
while (i <= 100.0) {
sum = sum + i;
i = i + 1.0;
}
return sum;
}
- Compile the kernel:
./build/src/simplang test_loop.sl
- Run the compiled kernel:
./build/tests/test_loop_runner ./build/tests/obj/test_loop.so
- Enable SIMD debugging for detailed vector operation insights:
cmake -B build -DSIMD_DEBUG=ON
- Use the test runner for quick iteration:
# Compile and run in one step
./run_tests.sh
-
Build Failures
- Ensure LLVM 14 is installed and in PATH
- Check that all dependencies are installed
- Verify CMake version is 3.20 or higher
-
Runtime Issues
- Verify kernel compilation succeeded
- Check shared library paths
- Enable SIMD_DEBUG for detailed error messages
SimpLang employs a Host-Kernel architecture. Your main application (the host, typically written in C++) interacts with specialized, compiled SimpLang code (the kernel) to perform computationally intensive tasks.
Key Benefits:
- Modularity: Kernels can be changed or updated without recompiling the entire host application.
- Specialization: Kernels are optimized for specific SIMD tasks.
- Isolation: Kernel crashes are contained, preventing host application failure.
- Write SimpLang Kernel Code: Define your SIMD-optimized logic within a SimpLang kernel.
- Compile Kernel: The SimpLang compiler transforms your code into a shared library (e.g.,
.so
on Linux). - Integrate with Host Program: Your C++ host application loads and executes the compiled kernel.
SimpLang prioritizes safety and reliability through:
- Robust Error Handling: Provides informative error messages for easier debugging.
- Automatic Resource Management: Ensures proper cleanup of memory and other resources.
- Type Safety: Enforces data type consistency between the host and kernel.
The SimpLang compiler transforms your code through a series of stages:
-
Lexical Analysis (Text to Tokens): The source code is broken down into fundamental units called tokens (keywords, identifiers, operators, etc.).
fn add(var x, var y) { return x + y; }
Tokens Example:
fn
,add
,(
,var
,x
,,
,var
,y
,)
,{
,return
,x
,+
,y
,}
,This stage identifies syntax errors like misspelled keywords.
-
Syntactic Analysis (Understanding Structure): The compiler analyzes the token stream to build an Abstract Syntax Tree (AST), representing the code's structure and relationships between elements.
AST Example (Simplified):
Function: add Parameters: x, y Body: Return Statement: Binary Operation: + Left Operand: x Right Operand: y
This stage detects logical errors, such as incorrect operator usage.
-
Optimization: The compiler applies various optimizations to improve performance:
- Basic Optimizations: Simplifies expressions, removes redundant operations, and reorders calculations.
- SIMD Optimization: Leverages CPU instructions to perform multiple operations in parallel (e.g., using SSE or AVX).
- Memory Optimization: Arranges data for efficient access, including data alignment and minimizing unnecessary memory transfers.
-
Code Generation (Final Output): The optimized code is translated into a shared library (e.g.,
.so
). This library includes:- Executable Code: Machine code ready for execution.
- Debug Information: Facilitates debugging by mapping source code to machine code.
Development Experience:
- Clear Error Messages: Provides specific and helpful error messages to pinpoint issues.
- Warnings: Alerts developers to potential problems that might not be immediate errors.
- Debug Information: Enables source-level debugging.
Performance Focus: The compiler is designed to generate highly efficient code by leveraging modern CPU features, SIMD instructions, and cache-friendly memory layouts.
SimpLang provides a robust debugging infrastructure for inspecting kernel behavior with minimal performance impact when disabled.
Core Architecture:
Host Program <-> Debug Interface <-> Kernel Runtime
| | |
+-> Commands ---+-> Runtime Hooks |
| | |
+-- State <---+-- Event Queue |
| | |
+-- Control <---+-- Breakpoints |
Key Features:
- Hardware and Software Breakpoints: Supports setting breakpoints using hardware registers (minimal overhead) or software interrupts.
- Zero Overhead (Disabled): Breakpoint checks have negligible performance impact when not active.
- Conditional Breakpoints: Break execution based on specific conditions.
- Source-Level Mapping: Relate breakpoints to specific lines of SimpLang code.
- Memory Tracking: Monitors memory allocation and usage to detect leaks and analyze patterns.
- SIMD Alignment Verification: Ensures data is correctly aligned for SIMD operations.
- Vector Operation Tracking: Monitors memory access during vector operations.
- Memory Access Pattern Analysis: Helps identify inefficient memory access.
- Call Stack Inspection: Provides detailed call stack information, including function arguments and local variable states.
- SIMD Register Inspection: Examine the contents of SIMD registers.
- Vector Operation Flow: Track the execution of vector operations.
- Memory Access Analysis: Analyze memory access patterns within the call stack.
- Asynchronous Event Processing: Handles debugging events efficiently without blocking kernel execution.
- Lock-Free Queue: Utilizes lock-free data structures for high-throughput event processing.
- Configurable Buffering: Allows customization of event buffering strategies.
- Real-time Filtering: Filter specific debugging events.
Integration Example (C++ Host):
// Attach debugger with custom configuration
DebugConfig config;
config.enableMemoryTracking()
.setBreakpointMode(HardwareBreakpoints)
.setEventBuffering(1024);
runner.attachDebugger(config);
// Register custom event handlers
runner.debugger().onMemoryLeak([](const LeakInfo& info) {
std::cout << "Leak detected: " << info.size << " bytes\n";
});
Performance Characteristics (Approximate):
- Breakpoints (inactive): Near zero overhead.
- Memory Tracking: 2-5% overhead.
- Call Stack Inspection: 1-3% overhead.
- Event System: <1% overhead with buffering.
SimpLang offers native support for SIMD operations, abstracting the underlying hardware details:
- SSE Support: Provides 128-bit vector operations with aligned memory access and optimized math functions.
- AVX Support: Offers 256-bit vector operations with advanced vector extensions and hardware-specific optimizations.
The SimpLang runtime environment provides essential services for kernel execution:
- Memory Management:
- SIMD-Aligned Allocations: Ensures memory is aligned for optimal SIMD performance.
- Memory Pool Optimization: Improves allocation efficiency for frequently used memory blocks.
- Optional Garbage Collection: Can automatically manage memory, reducing manual memory management.
- Error Handling: Manages exceptions and provides mechanisms for error recovery and debugging information.
- Performance Monitoring: Tracks operation timing, memory usage, and provides hints for potential optimizations.
fn bounded_sum(var n) {
var sum = 0.0;
var i = 1.0;
while (i <= n) {
sum = (sum + i) % 10000.0;
i = i + 1.0;
}
return sum;
}
fn kernel_main() {
var n = 100000.0;
return bounded_sum(n);
}
#include "kernel_runner.hpp"
#include <iostream>
int main() {
try {
KernelRunner runner;
runner.loadLibrary("./kernel.so"); // Assuming kernel.so is the compiled output
// Optional: Enable debugging
// runner.attachDebugger();
// Run kernel and get result
double result = runner.runKernel();
std::cout << "Result: " << result << std::endl;
return 0;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}
- JIT Compilation Overhead: < 1 millisecond.
- SIMD Operation Performance: Approximately 1.3x slower than highly optimized native C++ (trade-off for abstraction and ease of use).
- Memory Overhead: Around 2MB per kernel instance.
- Debug Mode Overhead: Approximately 5% in typical usage scenarios.
- Write SimpLang Kernel Code: Create your SIMD-optimized logic in
.sl
files. - Compile Kernel: Use the SimpLang compiler to generate a shared library (e.g.,
kernel.so
). - Integrate with Host Program: Load and interact with the compiled kernel from your C++ application using the provided
KernelRunner
API. - Debug: Utilize the built-in debugging infrastructure to step through code, inspect variables, and analyze performance.
- Profile and Optimize: Identify performance bottlenecks and refine your SimpLang code or compiler settings.
- Language Extensions:
- Advanced type system for more robust code.
- Template support for generic programming.
- Meta-programming capabilities for compile-time code generation.
- Optimization Improvements:
- Auto-vectorization to automatically generate SIMD code from scalar operations.
- Pattern-based optimizations to recognize and optimize common code patterns.
- Hardware-specific tuning to leverage unique features of different processor architectures.
- Tooling:
- IDE integration with syntax highlighting, code completion, and debugging support.
- Visual debugger for a more intuitive debugging experience.
- Performance analyzer to provide detailed performance insights.
For information on how to contribute to SimpLang development, please refer to the CONTRIBUTING.md
file. This includes guidelines for:
- Code Style: Ensuring consistent and readable code.
- Testing Requirements: Writing thorough unit and integration tests.
- Pull Request Process: Submitting changes effectively.
- Documentation Standards: Maintaining clear and up-to-date documentation.