Backend
You don’t need to implement an interpreter for Gazprea. You only need to implement a MLIR code generator that outputs LLVM IR.
Memory Management
It is important that you are able to automatically free and allocate memory for
vectors and matrices when they enter and exit scope. You may use malloc
and
free
for these purposes. This may be done in either your runtime or directly
within MLIR.
Below is an example of how to use malloc
and free
within MLIR using the LLVM dialect:
module {
llvm.func @malloc(i32) -> !llvm.ptr<i8>
llvm.func @free(!llvm.ptr<i8>)
llvm.func @main() -> i32 {
%0 = llvm.mlir.constant(128 : i32) : i32
%1 = llvm.call @malloc(%0) : (i32) -> !llvm.ptr<i8>
llvm.call @free(%1) : (!llvm.ptr<i8>) -> ()
%c0_i32 = llvm.mlir.constant(0 : i32) : i32
llvm.return %c0_i32 : i32
}
}
It is important that the code generated by your compiler has no memory leaks, and that all memory is freed as it leaves scope.
Runtime Libraries
If you make a runtime library, the runtime library must be implemented
in a runtime directory (runtime
). Beware that in C++ there is additional
name mangling that occurs to allow class functions. Thus, we recommend
that all runtime functions should be written in C and not in C++. There
is a Makefile in the runtime
folder designed to turn all *.c
and
*.h
pairs into part of the unified runtime library libruntime.a
.
An example of how to make a runtime function is provided bellow.
functions.c
#include "functions.h"
uint64_t factorial(uint64_t n) {
uint64_t fact = 1;
while (n > 0) {
fact *= n;
n--;
}
return fact;
}
functions.h
#pragma once
#include <stdint.h>
uint64_t factorial(uint64_t n);
If your compiler was compiling the following input
3! + (2 + 7)!
Here is how to call the function in the LLVM dialect of MLIR:
MLIR src
module {
// This makes the function available for calling
llvm.func @factorial(i64) -> i64
llvm.func @main() -> i32 {
// Calls factorial with the constant 3 as an argument
%0 = llvm.mlir.constant(3 : i64) : i64
%1 = llvm.call @factorial(%0) : (i64) -> (i64)
// Adds 2 and 7 together
%2 = llvm.mlir.constant(2 : i64) : i64
%3 = llvm.mlir.constant(7 : i64) : i64
%4 = llvm.add %2, %3 : i64
// Calls factorial with the result of 2+7
%5 = llvm.call @factorial(%4) : (i64) -> (i64)
// Adds the result of 3! with (2+7)!
%6 = llvm.add %1, %5 : i64
// Done, return 0
%c0_i32 = llvm.mlir.constant(0 : i32) : i32
llvm.return %c0_i32 : i32
}
}