Replies: 17 comments 22 replies
-
My benchmark accepts an argument and prints out the factors of the input. It uses the trial division method and pretty straightforward assembly-style code. My tool counts the number of I tested both of these using turnt. I got basic implementations working, saved the expected outputs using turnt, and then played with the code some more to try out other ways of saying the same thing. My tool is applicable to all bril programs, so I just copied the entire test/interp/ directory and ran my tool on all those programs. I was a bit confused by how bril functions take arguments. I figured it out by looking through a few other benchmarks (Ackermann and GCD). |
Beta Was this translation helpful? Give feedback.
-
My benchmark accepts two arguments My tool is pretty simple. It prints out the variables that each brill function defines. I wonder how it's output for a given brill program will perform by different optimization passes. |
Beta Was this translation helpful? Give feedback.
-
My benchmark prints the numbers less than some My tool adds a print instruction that prints the number 42 before every jump instruction. I tested the tool on several bril programs in the examples directory, some containing jump instructions and some without any. |
Beta Was this translation helpful? Give feedback.
-
My benchmark implements a Bubble Sort algorithm for a list containing 5 elements. It accepts 6 arguments: the first args is I use One trick I found useful to debug when writing bril code is that, we can also put It is worth to mention that if the same 5 elements are given in different orders, My tool is a simple program to count the number of add instructions. Note that some |
Beta Was this translation helpful? Give feedback.
-
My benchmark implements an algorithm to determine if the input integer is an Armstrong number, a number that is the sum of its own digits, each raised to the power of the number of digits. Implementing this benchmark required implementing mod and pow, as these are not supported by bril natively. To count the number of digits in the input number, I used a recursive function as it was easier than implementing log from scratch. I tested the benchmark with many different input numbers, both those that are Armstrong numbers and those that aren't. For example, 407 is an Armstrong number and 663 is not. My tool counts the number of add instructions in a bril program. The tool is implemented in rust using the bril-rs library. Testing is performed with turnt on a large number of benchmarks from the bril benchmark suite. This task was not very difficult, but it took some time to understand how to program in bril. |
Beta Was this translation helpful? Give feedback.
-
BenchmarkI implemented a graph format converter as a benchmark in this PR. It transforms a graph in adjacency matrix format (dense representation) to Compressed Sparse Row (CSR) format (sparse representation). It intensively uses the memory facility of Bril and mimics the behavior of multi-dimensional arrays. The input graph is randomly generated reusing the algorithm in Bril ToolFor the tool, I implemented a function inlining pass (written in Python) for Bril, which basically puts all the function calls inside the main function. It is an important compiler optimization that eliminates the overheads of maintaining stacks for function calls. Details can be found in my repository. At the very beginning, people may think function inlining is just about moving the whole function body to the main function, but actually it needs more consideration. In general, I did the following two things in my pass:
An example program here shows how my pass works.
We can see that from the following output, there is the only main function. Those variables inside the function are renamed, and no return instructions are involved. But there is also another issue, if we look at the original program, we can see the outer variable
After we resolve the above issues, we can finally create a main function that takes in all the function bodies. I also added five test cases in my test folder and used LimitationsThere is one limitation here -- my pass can only work with the function calls in the main function and cannot support arbitrarily nested function calls. Since for recursive functions, we do not know when it exactly stops, which is runtime information and cannot be obtained during compile time. Thus, as a simple solution, I directly raised a runtime error if some functions have nested function calls. Discussions
|
Beta Was this translation helpful? Give feedback.
-
my benchmark inverts a 3x3 matrix. It uses the usual determinant + adjoint method. Some of the index calculations for the memory would benefit from a CSE pass, which is mostly since i wrote it in a way that i could think about it more easily. my tool takes a bril program and determines (very conservatively) which functions might have side effects. Side effects include printing and escaping pointers, but I haven't considered nontermination. Ideally, functions that have no side effects can be computed at compile time if their arguments are known, like constexpr in C++. The issue of nontermination is messy here, and even if we can prove that the program would terminate, that doesn't mean it would terminate in a reasonable amount of time, so perhaps a timeout would be a better choice. Right now this is super naive, but it could be expanded to do more interesting things like propagate the "impurity" of functions through a graph of potential calls, as well as the all important escaping pointer analysis. |
Beta Was this translation helpful? Give feedback.
-
My benchmark is a simple iterative implementation of a The tool is a cycle detector, that does a static analysis and detects cycles between between function invocations. The tool works by analyzing a bril program and generating the equivalent DAG of the function-calls. Next, by executing a simple graph traversal for each individual function, it outputs the full path that leads to the cycle, e.g. Of course, a cycle might not occur despite a cycle between function calls, if the corresponding conditions are added before the calls. Thus, this tool detects only potential cycles, as I do not do any check on the conditions, or, how these methods are called. |
Beta Was this translation helpful? Give feedback.
-
My benchmark is a very simple operation; given the lengths of the sides of two rectangles (with the arguments being For the second part of the task, I wrote a simple program to swap integer arithmetic operations; addition is swapped with subtraction and vice versa; multiplication is swapped with division and vice versa. In order to test my transformation, I wrote a number of Bril programs that contained arithmetic operations, and observed both the output of my transformation via the output json, and also via the output of the transformed Bril programs themselves. The most difficult part of the task was getting used to Bril, and also getting used to reading and modifying json. I read through the documentation of Bril and looked at a couple of the existing Bril programs in the |
Beta Was this translation helpful? Give feedback.
-
BenchmarkMy benchmark implements Cholesky decomposition, a useful matrix operation for solving systems of linear equations. It decomposes a Hermitian and positive-definite matrix into the product of a lower triangular matrix and its conjugate transpose. In my implementation, the input is real number matrix, and the output is the lower triangular matrix. There are a few steps in the benchmark:
Validating the resultI validated the result by comparing with hermitian = np.matmul(A, A.T).astype(np.float32)
result_golden = scipy.linalg.cholesky(hermitian, lower=True) Problems I met
Simple Analysis PassMy pass is a simple static memory footprint profiler. It tells you how much memory is allocated in the program. I assume that For example, for the matrix multiplication benchmark, it tells you how many bytes are allocated in total, along with some other details:
Implementation
|
Beta Was this translation helpful? Give feedback.
-
My benchmark is an implementation of finding the left, midpoint and right Riemann sums for the squaring function, although the function can be replaced by other computable functions. I had some difficulty figuring out how Bril worked initially, but looking over other students' benchmarks allowed me to pick up some of the operations in Bril, and the basic assembly style. To test the correctness of this benchmark implementation, I used the given example of having a left endpoint at 2, and a right endpoint at 10 on the x-axis, and using 8 subdivisions. I verified that the sums of the squares of the left ends of the subdivisions was equal to the sums of the squares of 2 through 9, and the right Riemann sum equaled the sum of the squares of 3 through 10, and that the midpoint sums were the sum of the squares of 2.5, 3.5,..., 9.5. I also increased the number of subdivisions to be large, to see if the Riemann sums get close to 330.67. The hardest part was getting the sums correct, because I had forgot to multiply by the subdivision length. My tool iterates over Bril functions and instructions, and inserts a print operation after each instruction. The print operation is made to print the value 1, by printing from a new variable set to the value 1. Writing the tool made me realize appreciate Bril's design, especially the simplicity in seeing how Bril can be manipulated, and the similarity between the different forms in the language, which might make it easier to process than an intermediate representation with a large number of differing forms. |
Beta Was this translation helpful? Give feedback.
-
My benchmark adds an implementation of Knuth's up arrow notation for hyper operations, which generalize the idea that multiplication is iterated addition, exponentiation is iterated multiplication, and so forth. I basically wanted something that was a little repetitive and could maybe be streamlined, and which used recursion. I checked its correctness by comparing its outputs to this table of values. At first I tried just writing a typescript program and using ts2bril, but that wasn't able to handle the loop, so I removed it and then tried to put the loop back in. That totally worked, but after removing all of the variables created by ts2bril it probably would have been faster for me to just try to write the bril by hand, which I'll do next time. My tool just counts the number times each constant gets used. This was mostly prompted by me feeling weird not being able to write |
Beta Was this translation helpful? Give feedback.
-
BenchmarkI implemented the Adler-32 checksum. The program first creates an array of size Manipulating Bril ProgramsMy language of choice is Scala. It's a static, strongly typed language, and so manipulating JSON in an error free way is non-trivial so I created a simple library à la (bril-rs, bril-ocaml, etc.) to represent a Bril program in Scala. Currently it supports the core language, the memory extension, and the floating point extension. I hope to turn in into a standalone library and maybe push it to the monorepo. I first wrote the program to create a CFG from a Bril program (here's a sample). Then I wrote a program to calculate the distribution of the in-degrees and out-degrees of all the basic blocks in a program. I tested it using Turnt. The tests are here. One example for the
|
Beta Was this translation helpful? Give feedback.
-
I implemented the classic "Maximum sub-array problem" (https://en.wikipedia.org/wiki/Maximum_subarray_problem) that is the simplest ever form of dynamic programming. The program is looking of a sub-sequence with the highest sum of elements in the input sequence. I wrote it in bril. As the tool pass, I implemented a counter of functions in a given program - very simple, just to start with this. The most time-consuming part was getting started with the toolchain and learning bril. |
Beta Was this translation helpful? Give feedback.
-
BenchmarkI implemented a simple binary search algorithm. The program takes a fixed array of length 5 and a target value as input. It either outputs the index of target, or -1 if the value is not found in the input array. The benchmark is validated by manually observing multiple pairs of input/output, and by turnt. Simple Bril passI implemented a very naive memory leak checker. (Code is uploaded on CMSX) It basically checks that the variable pointing to the start of a piece of allocated memory gets freed. The implementation is done with Python. To make it actually work, I think it needs to take care of pointer arithmetic to trace the pointer so that we know we are actually freeing a valid & unfreed memory. DiscussionOne thing I found really nice about Bril is to be able to manipulate on JSON itself. It makes writing and debugging compiler passes very easy. |
Beta Was this translation helpful? Give feedback.
-
For my benchmark, I implemented a recursive function to calculate the _n_th term in the Catalan sequence. It involves many repeated computations, so I thought it would be an interesting challenge for a compiler to attempt to optimize. I tested the program manually on various inputs. My (very) simple analysis tool, implemented in python, counts the number of constants in each bril program. For me, the most time-consuming part of this task was trying to come up with a benchmark that was both interesting and not too difficult to implement in bril. I ended up asking a few friends for suggestions before I settled on this one. |
Beta Was this translation helpful? Give feedback.
-
For my benchmark, I implemented XOR, AND, and OR by simulating bit shifts one by one with repeated multiplication/division (and tracking which "bit" I was on by having just a counter that constantly multiplied by two). Kinda slow, but don't know how to do it any other way :/ My tiny program prints "8080" in addition to every print statement in the program. Learning bril was a little hard, but it's a lot better than assembly; it's helped me understand assembly a lot better now that I kind of see that assembly is just more limited IR since you can't have infinite registers + the stack is abstracted away. |
Beta Was this translation helpful? Give feedback.
-
Post any questions you have about Lesson 2! And, when you finish your implementation tasks, include a link here to your benchmark PR and your new Bril tool. Explain what you did and mention anything you found interesting about it.
Beta Was this translation helpful? Give feedback.
All reactions