Skip to content

Latest commit

 

History

History
160 lines (113 loc) · 3.82 KB

File metadata and controls

160 lines (113 loc) · 3.82 KB

Dana LLVM IR Generation

This stage takes a valid Dana program (after semantic analysis) and generates LLVM IR code. The IR is written to stdout, so it can be redirected into a .ll file and then compiled with clang together with the Dana runtime library.

Features

  • Emits LLVM IR for all valid Dana programs.
  • Supports function definitions, procedure calls, control flow, and expressions.
  • Declares and links against built-in runtime functions (I/O, strings, conversions).
  • Produces portable LLVM IR targeting x86_64-pc-linux-gnu.
  • Stable exit codes (0 on success, non-zero on error).

Prerequisites

  • The semantic analyzer must be built first (LLVM IR generation depends on its AST).
  • LLVM 14 (tested with the default package on Debian 12. Later LLVM versions introduce header and function name changes that can cause incompatibility).
  • clang (for assembling IR and linking the runtime library).
  • make, flex, bison, and a C++17 compiler.

Build

From this directory:

make            # build LLVM code generator
make clean      # remove generated .cpp/.o files
make distclean  # remove all generated files, including the danac binary

The build produces the binary: ./danac.

Usage

Usage: ./danac [OPTIONS] [FILE]

Generate LLVM IR from FILE, or standard input if FILE is omitted.

Options:
  -h, --help       Show this help and exit

Examples:

./danac program.dana > program.ll   # Compile source to LLVM IR
./danac < input.dana > out.ll     # Read from stdin, write IR to file

Examples

Input

def hello
    writeString: "Hello world!\n"

Command

./danac hello.dana > hello.ll

LLVM IR (minimal, ommiting built-ins)

; ModuleID = 'Dana Program'
source_filename = "Dana Program"
target triple = "x86_64-pc-linux-gnu"

@.str = private constant [14 x i8] c"Hello world!\0A\00", align 1

declare void @writeString(i8*)

define void @hello() {
entry:
  call void @writeString(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i32 0, i32 0))
  ret void
}

define i32 @main() {
entry:
  call void @hello()
  ret i32 0
}

Compiling to Executable

After saving the IR to a file:

./danac hello.dana > hello.ll
clang -o hello hello.ll libdanart.a
./hello

Output:

Hello world!

Using the danac.sh Script

For convenience, a wrapper script automates the process:

Usage: ./danac.sh [-h] [-o output] <input.dana>

Options:
  -h            Show this help message and exit
  -o <output>   Name of the output executable (default: a.out)

Example:

./danac.sh -o hello hello.dana
./hello

Exit Codes

  • 0 — success (LLVM IR generated)
  • non-zero — semantic or code generation error (message printed to stderr)

Testing

Use the repository’s Python test harness:

cd ../testing
python3 test_llvm.py

The script:

  • Runs danac on all programs in testing/programs/.
  • Saves IR into testing/ll/.
  • Uses clang to compile .ll into an executable, linked with libdanart.a.
  • Saves binary into testing/bin.
  • Executes the binary with inputs from testing/input/.
  • Compares program output against reference results in testing/result/.

Tips & Troubleshooting

  • Ensure LLVM 14 and clang are installed and available in $PATH.
  • The runtime library libdanart.a must be present in the same directory or linked with -L and -l options.
  • If the libdanart.a is deleted you can restore it by running
    gcc -c dana_runtime.c -o dana_runtime.o
    ar rcs libdanart.a dana_runtime.o
    
  • If compilation fails with target triple issues, verify that your LLVM and clang versions match your system architecture.
  • IR is printed to stdout (using danac) — don’t forget to redirect (>) to capture it in a file.