Making a Function Call in Fern
The easiest program to write in Fern is one that makes a single function call:
#include "helpers.h"
int main() {
// Our first, simple program.
auto a = mk_array("a");
auto b = mk_array("b");
// Gern object that represents a function.
gern::annot::add_1 add_1;
Composable program = {
// the () operator calls the function, and
// generates a "call site".
add_1(a, b),
};
// The program can now be compiled.
compile_program(program);
}
Let's look at the different pieces of the add_1
object carefully:
class add_1 : public gern::AbstractFunction {
public:
add_1()
: input(new const ArrayCPU("input")),
output(new const ArrayCPU("output")) {
}
/* getAnnotation() returns the data production
* and consumption pattern of the function.
* See Tiling Programs in the tutorial for more
* details if you'd like to skip ahead!
*/
Annotation getAnnotation() override {
Variable x("x");
return annotate(
Tileable(x = Expr(0), output["size"], step,
Produces::Subset(output, {x, step}),
Consumes::Subset(input, {x, step})));
}
/* getFunction() returns the "C++" signature of the
* Function that we ultimately use to generate code.
*/
virtual FunctionSignature getFunction() override {
FunctionSignature f;
f.name = "library::impl::add_1"; // <-- Name of the Function
f.args = {Parameter(input), Parameter(output)}; // <-- Parameters of the function
// Also contains template arguments which has been left empty.
return f;
}
/** The file that the function declration lives in, this is included
* in the generated file.
*/
std::vector<std::string> getHeader() override {
return {
"cpu-array.h",
};
}
protected:
AbstractDataTypePtr input;
AbstractDataTypePtr output;
Variable end{"end"};
Variable step{"step"};
};
Given our Fern program and the function definition, when we compile the program, we simply get a function that makes a single call (we have not tiled our program yet!):
#include "cassert"
#include "cpu-array.h" // Our include file!
// An automatically generated wrapper function name.
void function_3(library::impl::ArrayCPU& a, library::impl::ArrayCPU& b){
library::impl::add_1(a, b); // the actual function call!
}
Fern writes the generated code into a file which can then be included in a project, and run like normal.