From e4a7a741438b24a6de7323d03dc8e046f7101b6e Mon Sep 17 00:00:00 2001 From: Ajay Brahmakshatriya Date: Mon, 7 Dec 2020 11:36:04 -0500 Subject: [PATCH 1/2] Update README.md --- README.md | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/README.md b/README.md index fbea9c9..da1fb91 100644 --- a/README.md +++ b/README.md @@ -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 xy 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` and `static_var`) 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 +``` + +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` and the base using `dyn_var`. You can add a function definition like this - + +``` +dyn_var power(dyn_var base, static_var exponent) { + dyn_var 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.generate_function_ast(power, "power_15", exponent); + + // Generate the headers for the next stage + std::cout << "#include " << 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(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. From 5f91873adbcd0b2f05456b2e1efcd7b786154f22 Mon Sep 17 00:00:00 2001 From: Ajay Brahmakshatriya Date: Mon, 7 Dec 2020 11:40:25 -0500 Subject: [PATCH 2/2] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index da1fb91..bbc420e 100644 --- a/README.md +++ b/README.md @@ -141,21 +141,21 @@ 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.generate_function_ast(power, "power_15", exponent); - + auto ast = context.extract_function_ast(power, "power_15", exponent); + // Generate the headers for the next stage std::cout << "#include " << 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(2)); return 0}" << std::endl; - + std::cout << "int main(int argc, char* argv[]) {printf(\"2 ^ 15 = %d\\n\", power_15(2)); return 0;}" << std::endl; + return 0; } ```