Skip to content

Commit

Permalink
Merge branch 'main' of github.com:AjayBrahmakshatriya/buildit_artifac…
Browse files Browse the repository at this point in the history
…t_eval into main
  • Loading branch information
AjayBrahmakshatriya committed Dec 7, 2020
2 parents ebea9a4 + 5f91873 commit 534df5b
Showing 1 changed file with 115 additions and 0 deletions.
115 changes: 115 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,119 @@ and a large Mandelbrot set should be generated on the screen.

The reason we have included example 3 is to show that BuildIt is able to extract code from *really* large programs. The Brain Fuck program for this input is stored in `inputs/mandel.bf` and has `11597` characters. The generated code in `outputs/fig24_ex3.cpp` should be roughly `11464` lines of code. BuildIt is able to extract this code in matter of few seconds.

### Writing your own BuildIt programs
This section will describe how you can use the BuildIt library to write your own multi-stage programs. As mentioned in the paper, BuildIt takes a pure library approach and doesn't require a specialized compiler to stage the C++ program. We will start by identifying where the BuildIt headers and library is located. We will need these paths when compiling our programs. If you have followed the exact steps above, the headers should be located at the path - `buildit/include`. You can check this by running the following command from the top level directory of the repository -

ls buildit/include

You should see three folders - `blocks`, `builder` and `utils`.

Similarly the library should be built at `buildit/build/libbuildit.a`. You can run the following command to check the same -

ls buildit/build/libbuildit.a

We can now proceed to writing our own BuildIt program. In this example we will be staging the power funciton which calculates x<sup>y</sup> using repeated squaring. We will bind the exponent in the static stage and bind the base in the generated code.

Start by creating a new C++ file in your favorite text editor.

We will first include some basic headers that have the BuildIt types (`dyn_var<T>` and `static_var<T>`) and other helper functions to support code generation.

```
#include "blocks/c_code_generator.h"
#include "builder/builder.h"
#include "builder/builder_context.h"
#include "builder/static_var.h"
#include <iostream>
```

The BuildIt types are in the `builder` namespace. You can add the following lines for accessing the two new types or use the namespace every time you refer to them -

```
using builder::dyn_var;
using builder::static_var;
```

We will now write a function to actually compute the power function using repeated squaring. Since we are binding the exponent in the static stage, we will declare it using `static_var<T>` and the base using `dyn_var<T>`. You can add a function definition like this -

```
dyn_var<int> power(dyn_var<int> base, static_var<int> exponent) {
dyn_var<int> res = 1, x = base;
while (exponent > 1) {
if (exponent % 2 == 1)
res = res * x;
x = x * x;
exponent = exponent / 2;
}
return res * x;
}
```

This is exactly how you would write a power function in C++ with repeated squaring other than the templated types for staging. We have copied this exact implementation from the iterative version on [Wikipedia](https://en.wikipedia.org/wiki/Exponentiation_by_squaring).

We will now write a driver function which will supply the arguments and generate code. In BuildIt, all the extraction of program is done using a `builder::builder_context` object. The main function that we will use is the `builder::builder_context::extract_function_ast`.

This function takes the following arguments -

1. Function pointer that we want to extract the program from using staging (in our case case `power`).
2. A C string for the name for the function after extracting. This is used while generating code.

Following this, the function takes the values for the `static_var` arguments in the function in the order they are declared (skipping over the `dyn_var` arguments). In our case since the power function only takes one `static_var` argument for the exponent, that is all we will supply. The only constraint is that this function needs an `lvalue` so instead of passing a constant we will declare a variable and pass that.

This function returns a `block::block::Ptr` which is a handle to the generated AST. We can pass this to the `block::c_code_generator::generate_code` function to generate the C code for the next stage.

Adding the rest of the code our main function will look like the following -

```
int main(int argc, char* argv[]) {
// Declare the context object
builder::builder_context context;
// Generate the AST for the next stage
// The exponent can also be a command line argument, we will supply a constant for simplicity
int exponent = 15;
auto ast = context.extract_function_ast(power, "power_15", exponent);
// Generate the headers for the next stage
std::cout << "#include <stdio.h>" << std::endl;
block::c_code_generator::generate_code(ast, std::cout, 0);
// Print the main function for the next stage manually
// Can also be generated using BuildIt, but we will skip for simplicity
std::cout << "int main(int argc, char* argv[]) {printf(\"2 ^ 15 = %d\\n\", power_15(2)); return 0;}" << std::endl;
return 0;
}
```

This entire program is also provided as a sample in the `inputs/sample_power.cpp` file for your reference.

Now we will compile this program with the BuildIt library and headers. Run the following command replacing `filename.cpp` with the path to the cpp that you wrote or just use `inputs/power_sample.cpp`. Please run the command from the top level directory of this repository -

c++ -std=c++11 -O3 -rdynamic -I buildit/include -L buildit/build filename.cpp -o power_stage1 -lbuildit

This will generate the executable `power_stage1`. Run the program by simply running the command -

./power_stage1

This will print the code for the second stage on the console.

We will now also compile this code and run it. Start by saving the program in a file and compiling it as -

./power_stage1 > power_stage2.c
gcc -O3 power_stage2.c - power_stage2

Compiling the generated code doesn't require BuildIt headers or library because it is a normal C program. Finally run it as -

./power_stage2

and the program should print -

> 2 ^ 15 = 32768
You have successfully written and run your first BuildIt program.


The `buildit/samples` directory has many more samples that you can read and run (executables at `buildit/build` directory) that exercise the full power of `BuildIt`.

This concludes the artifact evaluation for BuildIt.

0 comments on commit 534df5b

Please sign in to comment.