Replies: 31 comments 32 replies
-
Benchmark PR: sampsyo/bril#356 My benchmark was a 5-input sorting network. For those who aren't familiar, a sorting network is a way of sorting fixed size inputs using a static arrangement of "comparators" that compare two values and swap them if they are not in sorted order. For small-ish inputs (like 5) it is possible to identify the fewest possible number of comparators needed for a correct sorting network and my network is optimal in that sense (AFAIK). I built it using the typescript compiler and the first thing I learned was that the warning that the ts compiler produces inefficient code was an understatement. My bril code has multiple instances of this pattern:
Otherwise I found the process to be pretty painless. My code works (on a few inputs) and the tools mostly work as advertised. My Bril tool outputs basic blocks and cfgs (in graphviz format, shout out to the lesson 2 videos) and my "do any other thing" thing was to print some basic descriptive statistics about programs. Number of functions, number of labels, how often different opcodes appear, that sort of thing. That effort brought home for me what Adrian means when he talks about this sort of assembly-like IR being "regular". For simple questions like "what percentage of all instructions are function calls?" it is just a little easier to traverse a list of instructions than it would have been to traverse a syntax tree. I think my biggest challenge was probably wrapping my head around turnt. It took me a while to realize I could use environments with different output files to define different sorts of tests on the same files. I also missed the ability to programmatically generate tests. A small sorting network can be more or less exhaustively tested and while the number of tests is not prohibitive if you can generate test cases on the fly, it is a very inconvenient number of tests if you have to generate a file for each one. My other lingering complaint with turnt is that it identifies the output of a program with its correctness. For the sorts of human-readable tools I was developing for this lesson, it would be nice to separate the formatting of the output from the content of the output. That being said, I can already see the appeal of snapshot testing and I think I just need to reframe how I think about testing. |
Beta Was this translation helpful? Give feedback.
-
Benchmark PR For my benchmark I chose Conway's Game of Life Game. I first started by generating a random nxn matrix from a seed (inspired by For my bril program transformation, I choose the problem of assigning unique, mnemonic, fixed-character-length variable names to all variables and arguments in a bril program (supports up to 1,000 transformations), like Finally, I implemented the basic blocks and cfg algorithms that we covered in class, using all the infrastructure I used for parsing for the program transformation. This wasn't too bad, the biggest difference from the lecture notes is that i relied on block ids of type int instead of strings; which meant that my cfg was a dictionay from int to a set of ints, instead of showing the labels of the blocks. I tested it out in a couple of different bril programs to make sure that it was behaving as expected (tests helped me fix a bug where i was including empty blocks). The hardest part of the assignment was to debug the bril benchmark, as I relied on a lot of printing statements (with ids and locations that helped me identify up to which point the program ran without failing). I do think that i deserve a michelin star. |
Beta Was this translation helpful? Give feedback.
-
BenchmarkMy benchmark was a general matrix multiplier on binary matrices in pure base bril (no extensions), which I built by hand. This means that each element of a matrix is a single bit, 1 or 0 in the field The algorithm was pretty interesting mainly due to the lack of bitwise logic functions in base bril, which meant that in order to check for parity I had to use integer division quirks to check for oddness and evenness, namely by checking whether The bulk of the algorithm does a very basic ToolFor my program transformation, I wrote a simple script that inserts an instruction counter into every function that increments a variable at each instruction, and prints the total instructions ran whenever exiting the function (before all returns as well as at the end of the function). Additionally, it removes existing print statements to avoid clashing of outputs. For input sanitization, it also detects whether a given input filename is TestingTesting was done using a very simple set of turnt environments, one which ran the function and checked ConclusionsI would say the most difficult part of this task was definitely handwriting bril. I have a fair amount of experience writing LLVM but the restrictiveness of bril's instruction set made a lot of simple processes more difficult than I expected, mainly when dealing with bitwise operations, which unfortunately my idea had a whole lot of. Some of my workarounds definitely felt like reinventing the wheel but poorly, especially as computers are usually great at bitwise logic. Additionally, as I had no access to dynamic memory allocation this also limited the scope of what I could do, for example when implementing |
Beta Was this translation helpful? Give feedback.
-
Benchmark PR: sampsyo/bril#362 Implementation: https://github.com/mt-xing/cs6120/tree/main/l2 My original plan for my benchmark was to implement the legendary Quake 3 Fast Inverse Square Root Algorithm using Bril. Unfortunately, I found that Bril does not support re-interpreting the bytes of a float as an int and vice versa, which is the crux of the algorithm's speedup. Through discussions on Zulip, I found that one of my peers has already submitted a PR to add this functionality to Bril, so I decided to keep this benchmark in for future use. In the meantime, I also added a second benchmark that uses the far less fun Newton's method starting at My Bril analysis tool counts the number of unique variable names declared in every function of a program (not including arguments). This is written in TypeScript and can be run with Deno. It is inside the My CFG algorithm is in the The hardest part was figuring out how to set up the environment and the Bril syntax. Most of the instructions do not work on Windows, and while I was able to figure out everything involving Deno, as far as I can tell, Flit just does not work on Windows at all, and I ultimately had to use WSL to get the bril2json working. The other difficulty is that I could not find the syntax for the I believe this work is worthy of a Michelin star because one benchmark pushes the boundaries of what Bril can do, and on top of that I went back and wrote a second benchmark that runs on the current capabilities of Bril. These benchmarks were all written by hand in Bril. On top of that, the implementations were all tested against a battery of edge cases and I even wrote out type annotations for the parsed Bril JSON, so that the TypeScript isn't just using raw |
Beta Was this translation helpful? Give feedback.
-
Benchmark/Tool Validation |
Beta Was this translation helpful? Give feedback.
-
BenchmarkThe benchmark I wrote sums up all of the digits of an input integer and prints the sum. It was slightly challenging since Bril doesn't have a modulo instruction, so I had to approximate with a division-multiplication-subtraction instruction sequence. The input arg I defined for the turnt testing was Bril toolMy Bril tool outputs the number of labels in a Bril program. I wrote it in TypeScript. The initial idea for this tool was to modify the Bril proram to print out the name of each label reached; however, after getting through 80% of the implementation I realized that printing out a string would be a lot harder than I had originally reckoned, so I switched it to just counting labels. To test it, I selected sample Bril files from I also implemented the basic block forming and CFG building algorithms in TypeScript. I think my work deserves a Michelin star because my benchmark program had to circumvent the limitations of Bril not having a modulo instruction and my Bril tools were structured well for future extension, with common types separated from implementations and taking in input through stdin so that compiler stages can eventually be chained. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Benchmark: Tool: For basic block formation and CFG construction, I followed the standard approach of identifying block boundaries at labels, jumps, and function entry points. The biggest challenge was making sure fallthrough edges were handled correctly, especially for blocks without explicit jmp instructions. Debugging this helped reinforce how Bril programs execute, and once fixed, the output matched expectations. Turnt was definitely the most challenging part of this assignment. It works well once set up, but it feels rigid in how it ties output to correctness. Formatting changes can cause tests to fail even if the transformation is functionally correct, and I found myself wishing for a way to separate formatting from actual correctness checks. I also see the appeal of snapshot testing, though—it forces you to carefully track changes in program behavior, which is useful for verifying transformations. Overall, I think this turned out well. Writing the benchmark by hand was a good exercise in working with Bril directly, and the print injection tool makes debugging easier. CFG construction was satisfying once all the edges lined up correctly. Now that Turnt is set up, it should make testing future transformations much easier. |
Beta Was this translation helpful? Give feedback.
-
Benchmark: source Tool: source My actual tool is just something that walks over the CFG and counts the in-degree of each basic block. This includes when the block is the target of a jump or branch, and also when it is the destination of some fall-through edge. I thought this was simple enough and could be an interesting analysis to do. It tells you a bit about how a program is structured. I tested it pretty much manually using most of the core bril benchmarks, and set it up to use To run the tool to generate the graph, run I think I deserve a star because I implemented what was asked, plus some extra stuff. I tested things thoroughly enough to expose and fix some bugs, and convinced myself that it works. |
Beta Was this translation helpful? Give feedback.
-
Benchmark PR: sampsyo/bril#354 For my benchmark, I implemented a simple permutation function P(n, k) which represents the number of possible permutations of k objects from a set of n. This benchmark also uses a factorial function to easily calculate the permutation, so I initially wrote both a recursive and iterative method to see how it's converted to different representations. The permutation function was tested with smaller numbers such as n=6 and k=3 (output=120) for validation. Tool: https://github.com/dhan0779/cs6120-impl/tree/main/l2 Basic Block/CFG: https://github.com/dhan0779/cs6120-impl/tree/main/l2 For constructing the CFG, I created a map to give a name for each block to make it easier to identify edges and nodes using the 'label'. There are some cases where the list of basic blocks are empty or don't have explicit terminators, so handling those were probably the trickiest part of this. I manually checked the CFG to make sure the edges made sense for each function using the benchmarks. I think the hardest part of this assignment was setting up |
Beta Was this translation helpful? Give feedback.
-
Code: Summary:
Correctness
Hardest Part Grade |
Beta Was this translation helpful? Give feedback.
-
My benchmark implements modular exponentiation using the right-to-left binary method. To create it I first converted pseudocode I found on Wikipedia to Typescript, then used My tool is a Python script that reads in a bril program and outputs some basic statistics on the variable name usage of the program (unique variable names, total variable uses, top 10 variable names). It does this by iterating over all instructions and using a Python Counter to track occurrences of strings in either the dest or args field of instructions. The implementation of the basic blocks and CFG algorithms was pretty straightforward based on the pseudocode we came up with in class. The one thing I had to think about a bit was how to handle labels, I ended up leaving labels in the basic blocks rather than storing them in a separate data structure which I think is nice to keep things simple, but might be a bit annoying in cases where you want to assume all instructions in a basic block have ops. I did my testing using turnt, which I quite like. I can see it being annoying in some cases to have correctness tied to the output format but very much appreciate the simplicity and flexibility of the .toml config file. For my tool I used a few bril tests/benchmarks as inputs and manually counted variable usage to be sure the output was correct. For my CFG I started by testing on the programs we looked at in class, then moved on to using a few benchmarks with more complex control flow. Testing on my mod_pow benchmark revealed a bug where two consecutive labels with no separating instruction caused my implementation to crash, so I was able to fix this. I think my work deserves a Michelin star because I familiarized myself with bril core features and associated tools beyond what was necessary and my implementations are clean and appropriately tested. |
Beta Was this translation helpful? Give feedback.
-
BenchmarksI tried to think of benchmarks that are heavily recursed. My first trial a classic Hanoi problem but I later found that it has already been implemented in previous semester. I then did another path counting benchmark, famously known as delannoy number, which counts the total number of paths to reach the goal given that only three possible moves are allowed. It was implemented recursively without memo. Those bril programs were compiled from typescript. ToolsMy bril analyzer tools are a simple operation counter and a cfg visualizer written in Rust. The input bril json is first deserialized into its Rust counterpart and then traversed to get the necessary op statistics and cfg information. The counter simply tracks the number of occurrences of each op type. The cfg finding algorithm is a full fledged version of the one I wrote in class. It involves two passes: i) chunk instrs into basic blocks and associate blocks with labels; ii) connect those blocks with edges. The final cfg can be converted to dot format for graphviz rendering. Some of the edge cases have been taken care of, for example consecutive labels, there might be basic blocks contain only label but no instrs (found in bril compiled from ts program with nested if-else statement). Tools have been tested thoroughly with ConclusionsI would say the most challenging part is to actually write a typescript program that can be compiled into bril. I found some of typescript semantics that are supported by current |
Beta Was this translation helpful? Give feedback.
-
CFG & basic blocks implementation For this task, I wrote a tool to build a list of basic blocks and construct a control-flow graph, I wrote a trivial analysis tool to count the number of instantiated Basic Blocks & CFG Counting Benchmark Writing the benchmark was also the hardest part of this task for me. Figuring out the convolution algorithm should work (e.g. ensuring correct indices of the kernel, array, and output, and producing the result in each index of the output) took some time, and then figuring out how to map that abstract algorithm onto an assembly-adjacent language was another layer of complexity. I was also nervous that I'd introduce some inconspicuous bug that would be impossible to debug... that almost happened but thankfully an easy fix. The upside is, I feel like I know the language well now! In the future, hopefully digging through program transformations we do won't be scary. Finally, I think my work deserves a Michelin star due to my benchmark implementation and my methodology in visually testing my BB & CFG implementation. |
Beta Was this translation helpful? Give feedback.
-
Basic Blocks & CFG Algo To test my CFG algorithm, I used property-based random testing à la QuickCheck (via Jane Street's ppx_quick_check tool) to check that certain invariants were upheld. For example, I tested that terminators (if they exist) are always the final instruction in a basic block, and that every block appears in the I also implemented JSON serialization / deserialization from scratch, and also used QuickCheck to make sure that the serialization was done properly. I also defined a typed AST for core Bril in OCaml -- being able to pattern match on instructions was very helpful when implementing the CFG algorithm. Adding Benchmark Idea behind the algorithm: for example, if I think my work deserves a Michelin star as I actively thought of new ways to test my code using QuickCheck beyond just using Turnt & unit tests (including writing QuickCheck generators for random instructions), and I built custom OCaml infrastructure for de/serializing Bril. |
Beta Was this translation helpful? Give feedback.
-
Benchmark: sampsyo/bril#374 Bril tool: https://github.com/devv64/6120/blob/main/lesson2/analyze.py CFG: https://github.com/devv64/6120/blob/main/lesson2/cfg.py Conclusion: |
Beta Was this translation helpful? Give feedback.
-
CI for all tests (there's a lot of them) passing! https://github.com/ethanuppal/cs6120/actions/runs/13065966149/job/36458272723 Benchmark
CFG Builder
bril-frontend
bril-lsp
I think my works at least a Michelin star, following this definition:
I believe these projects are successful and represent solid implementation work. I've spent over 20 hours working on them. |
Beta Was this translation helpful? Give feedback.
-
My benchmark PR: link For my benchmark, I added a function checking whether a ray intersects an axis-aligned bounding box in 2D. This is a very common operation in ray tracing, except that everything has to be in 3D there. I used the slab method for it. Interestingly, I did not know before writing this comment that the method has a name:) I wrote the code in typescript first, translated it to Bril, and then spent a lot of time cleaning up the final code from all the intermediate variables (there were 79! unnecessary variables). I ran multiple tests to make sure that my modifications did not alter the code. This part of the assignment helped me to get more used to Bril syntax. My small program is very simple. It finds all the labels for all the functions in the given program. I implemented it in python. The trickiest part was to get used to using turnt as a testing tool. Finally, I implemented the algorithms for basic block detection and CFG computation. I based my implementation on the pseudocode that we wrote during the lecture. I run the code on multiple programs. I used examples from the lecture, fact.bril, and my code for the benchmark, as well as tests designed to specifically check corner cases like consecutive labels with no code in between. To make sure that the code is correct, I plotted the CFG using graphviz. That's what the output looks like for my benchmark: When writing code, I routinely use copilot autocompletion to avoid retyping similar lines of code. For example, if I already have a line with |
Beta Was this translation helpful? Give feedback.
-
Benchmark Pull Request: sampsyo/bril#363 For my benchmark, I made a combination function, aka n choose k, defined on positive ints (I return 1 for n choose 0, and 0 for n choose k, n < k, and 0 as well for negative n or k). I tested this using turnt, using both expected inputs (ie 12 choose 3, 20 choose 10), as well as these edge cases where n or k is negative/0/n<k. One difficult thing was that I kept remembering more edge cases which I wanted to cover just in case someone inserted inputs which were not expected, and it depends on the specific definition you're using whether you want to define combinations as existing on negative numbers at all (I chose not to implement negative combinations for simplicity's sake as I was still learning to use bril; something to come back to later!). For my mini bril tool, I counted the number of "significant" commands; this is arbitrary, but I defined "significant" commands as jmp, br, function calls, and labels. This was mostly to help me build up to doing the basic blocks algorithm, as obviously already having a program which tests for these commands would be helpful when trying to separate blocks based on them (I had forgotten that we don't use function calls as delimiters for our definition of basic blocks [shoutout to the zulip post clarifying this, saved me a lot of pain with the blocks algorithm]; I could have gone back and deleted the counting of function calls, but I thought it might be useful for a different definition of CFG which is interpracedural, so I left it). Parsing the json file was a real pain in the neck, especially for my brain which gets confused where there are more than three brackets []{} next to each other. Once I figured that out, though, it wasn't too bad. I tested this again using turnt, feeding in my combination benchmark as well as the nifty benchmarks and json files laying around in the bril repo. I don't really like turnt at the moment; I couldn't get it to work for my mini bril tool and it took me longer than I'd care to admit that it was because I'd named my file "minturnt.toml" rather than "turnt.toml". But maybe I'll come to love it with time. The basic blocks algorithm and CFG algorithms weren't too bad, with the pseudocode and the json parsing work I'd already done for my mini bril tool. I had to make some design decisions for the CFG; I enforced that every block must have a child, so for leaves I just set them to have 'end' as a child. Also, it was annoying to account for blocks which might be unlabelled, like if there's a jump on line 20 that skips to line 30, and everything on lines 20-30 is inaccessible, but you still have to consider it a block. For the future when typing bril programs I will make sure to use labels liberally in order to perhaps save this pain for someone else. I just tested in the terminal for this one (my program prints the blocks and the cfg directly to the terminal, so it was easy to just test it there), using again the benchmarks and .bril files laying around in the bril repo; helped me catch a bug that I had missed when building up my cfg program using my own benchmark (which I used to test as I was building the program because it had a decent but not overwhelming amount of branches). I do think I deserve a Michelin star because I tried to build a benchmark that would be genuinely useful for the future, and while my mini bril tool was mostly just for practice, my blocks/cfg file has the advantage of printing everything out very clearly so that it is very readable; I couldn't stand the long strings of brackets that it originally generated when I just returned my entire list of blocks, so I tried to get to as close to a "pretty print" as possible for the blocks, to at least make it manageable to read. I learned a lot about bril here, and put in a lot of effort to the code I am submitting. |
Beta Was this translation helpful? Give feedback.
-
BenchmarkBinpow Bril Program I tried to implement it in typescript and compile it with ts2bril, but I ran into some errors that I wasn't sure how to fix, so I pivoted to implementing the benchmark in Bril directly; I figured it might be good practice with familiarizing myself more with Bril. I did some ad-hoc testing on the terminal with fairly basic inputs, but I tested even, odd, and zero exponents and it seems to be working. Program AnalysisCount Mini-Tool Basic Blocks and CFGsCode ConclusionGetting things set up initially proved to be a bit tricky. Learning how to use a bunch of new tools incurred a bit of overhead. I underestimated how much time it would take to go through these things. This was pretty fun though. I found it quite interesting thinking about what makes a benchmark pragmatic. Implementing basic blocks and CFGs was a bit hard for me, I think part of it was that I was thinking very imperatively, and it just felt very unergonomic to implement those thoughts into OCaml. Also, I wanted to write my own function to convert a Bril json to an AST, but this ended up consuming a lot of time to hit all cases, and I eventually abandoned this approach. On the Michelin star, not sure if I deserve it since I did finish up a bit late, but I am pretty happy with my work overall. |
Beta Was this translation helpful? Give feedback.
-
Benchmark sampsyo/bril#376 I implemented Karatsuba algorithm for fast integer multiplication by hand in Bril. This involved implementing several small functions like counting number of digits, max, and modulo: functions that I typically take for granted in high-level programming languages. I was originally planning to use the Typescript compiler rather than hand-writing it, but I quickly saw the compiler was much more limiting. Hand-writing it also helped me get a lot more familiar with the syntax and semantics of Bril. To verify the correctness of my implementation, I used differential testing. I wrote a python script to generate 500 random integer pairs and asserted that the product of each pair were the same in python and in my implementation. Tool https://github.com/arnavm30/CS6120-tasks/tree/main/l2/tool I implemented a tool that swaps the arguments of add and multiply operations. Since these operations are commutative, the swap should not change the outputs of the programs. I verified the correctness by using turnt, which naturally worked well as the already produced Basic Blocks and CFG https://github.com/arnavm30/CS6120-tasks/tree/main/l2/cfg My implementation of the algorithms to form basic blocks and then the CFG is heavily based on the discussion in class as well as the videos. Compared to the other tasks, this was harder to convince myself of its correctness. To gain more confidence in the correctness, I drew out the CFG of a few programs from benchmarks. I also compared the CFGs my implementation generated with that of the one generated in the playground. Moreover, I used turnt, which was helpful when I wanted to make some small as I could easily see if something changed from what I thought should be right. I think this work is worthy of a Michelin star because the benchmark exercises a lot of the core capabilities of Bril, and I did a solid job on testing. |
Beta Was this translation helpful? Give feedback.
-
For my benchmark, I chose to compute the characteristic polynomial of a 3x3 matrix, although it is easily extensible to nxn matrices as well. The input is a flattened matrix, or an array of 9 values, and the benchmark outputs an array of 4 values representing the coefficients of the resulting polynomial. For example, given the matrix [[1,2,3], [4,5,6], [7,8,9]], the arguments to the program are thus 1 2 3 4 5 6 7 8 9, and the program outputs -1 15 18 0, which represents the polynomial -x^3+15x^2+18x. The most commonly known way to calculate the characteristic polynomial of a matrix is to use the formula det(A - xI), where I is the identity matrix. However, there is also a closed form formula to this problem, -x^3+trace(A)x^2-trace(adjoint(A))x+det(A)=0, which is what I used. The challenge here was the allocation aspect: since I was allocating twice (once for the matrix and again for the resulting array), I was worried that the pointers would collide, resulting in overwrites, but this wasn't too difficult to fix. For my tool, I decided to implement a program that counts the number of function invocations in a Bril program. This was fairly straightforward, and allowed me to become more familiar with the nested structure of Bril as I had to iterate through the json lists. This task simply amounted to keeping track of a count variable that updated every time the "call" opcode was found in the instrs list. For my basic blocks / CFG algorithm, I used the pseudocode in the lecture video as a rough guide, ie the same high-level idea. For my CFG algorithm in particular, I named the blocks according to their label names, and for those blocks without labels, I decided to name them based on their index in the basic blocks list. Then, I created a dictionary that mapped block names to the names of their successors. I made sure to identify labels, jumps, branches, and return statements so that block boundaries could be realized. The challenge here was to make sure that fallthrough edges were handled correctly. I tested my programs using turnt, which was difficult to set up. However, I believe the effort was worth it as I can see how turnt will be useful down the line with future tasks in this class. I used several Bril programs in the repo as inputs to test my programs. Overall, I think I deserve a Michelin star for taking the effort to familiarize myself with Bril and for actively thinking about edge cases during my implementations. |
Beta Was this translation helpful? Give feedback.
-
benchmark pr: Benchmark My benchmark was an implementation of rot13, using integers as a standin for characters as brili doesn't support chars yet. I wrote it manually, but the benchmark wasn't complicated so this wasn't bad. My tool just prints out the name of every function in a program. I tested this using programs with zero, one, and multiple functions. I think the hardest part of these tasks was getting used to the bril tools and turnt. As for a Michelin star, I think I'd feel bad asking for one if I just did this, so I also wrote a small utility function that removes blocks that are never entered from a program. I think that I deserve a star for implementing and testing the assigned tasks, then adding extra functionality. |
Beta Was this translation helpful? Give feedback.
-
Benchmark PR: link CFG implementation / other code: link For this task, I decided to use Haskell. I defined my own datatypes for Bril programs, and used the For the extra task, I wrote a simple CFG dead code elimination function, which does DFS in the CFG to explore reachable basic blocks, and then gets rid of all the others. However, I didn't have time to test it adequately, so I ended up just making my program count the number of basic blocks -- much easier to test. Michelin star: I think I would've said yes if I were posting this before the deadline, but it's already 12:05am and I haven't clicked "comment" yet, so I think that means no star 😅. |
Beta Was this translation helpful? Give feedback.
-
BenchmarksI first implemented the Ackermann's algorithm, but then realized this has been added to the benchmarks 3 years ago. So I turned to the logistic map and wrote another bril code, which takes three arguments ( ToolsI simply made an uninteresting move: count the number of each type of instructions and output it. I tested the tool with turnt using existing test programs in the CFGI used Python to write the CFG code and used turnt with existing programs in the ConclusionThe hardest part is to install all the packages (honestly), because I went into a small issue when installing turnt. I do think that I deserve a Michelin star. One thing I realized after finished the work is that I shouldn't only use tests in |
Beta Was this translation helpful? Give feedback.
-
Benchmark PRA simple random walk on Here's a nifty fact (Theorem 3.15 and 3.11 form here):
(for
d = 2 and seed = 5 d = 3 and seed = 11 Another script I wrote counts how many walks terminated by returning to the start via varying the random seed from 1 to 100: 73% of 2D walks returned while only 35% of 3D walks did! also, thanks @gerardogtn, I used your tweaks to the PRNG from CFGFairly straightforward implementation of the algorithm from class. This was fun to implement and helpful for getting used to Bril tool
Since this type of reordering preserves program behavior, I tested it with
Otherwise, everything went rather smoothly! |
Beta Was this translation helpful? Give feedback.
-
Benchmark PR: Link For my benchmark, I decided to (also lol) implement Karatsuba's multiplication algorithm. I decided to represent my inputs as binary numbers to make some of the calculations easier via bit manipulation. For the algorithm, I needed to implement a way to calculate the size of numbers in binary. I was able to find (borrow) existing implementations of Rightshift, mod, leftshift, and a power function from other benchmarks in the suite, which was very helpful since I found writing Bril to be pretty time consuming. I wanted to challenge myself to build a tool that could feasibly be used when implementing a feature in a compiler or IDE. For this, I made a program that counts the number of times each variable has been used, not including initialization. This could be used for implementing something like unused variable warnings in an IDE/compiler. I wrote my tool in Typescript and didn't use any additional libraries/extensions. For my cfg, I used the algorithm discussed in class. I made the decision to begin a new block every time a label is encountered in my block building algorithm. I used these labels to create a mapping of labels and their corresponding blocks, which was helpful when implementing my CFG algorithm. Challenges: My first challenge is that I absolutely did not install anything correctly and spent most of Wednesday + Thursday just trying to debug that. I also wrote my implementation in typescript first, before realizing that most of the functions I used could not be ported to Bril, which meant I had to start over midway through Thursday :'( Besides those logistical issues, I found the rest of the implementation task to be pretty smooth + very fun! Michelin star: This is incredibly late so I probably do not deserve one. |
Beta Was this translation helpful? Give feedback.
-
Benchmark PR: link For my benchmark, I implemented a 2d convolution. The inputs are the image size (just the # of rows or columns), kernel size, and an int seed for filling the array. Originally, I manually filled the arrays, but it got very messy and wasn't easy to scale so I borrowed functions for generating arrays, filling arrays and printing arrays. I have barely every written in a language like Bril so it was fun to learn. For my tool, I was already so behind schedule because of installation issues and whatnot so I just went with something simple and counting the number of memory access instructions in a program and output the counts for the different types. For my cfg, I used the algorithm in class. I used the labels as the names for blocks if there was a branch/jump statement to it and if not I just used a default name. I also display it using graphviz. Challenges: I spent a lot of time installing things and then it worked for a while and then when I was committing to GitHub I think I broke something so I reinstalled the bril tools. I found it easy to learn Bril though and implement the tasks. I still don't really understand how Turnt works but I think I used it properly because it looks right. Michelin star: This is really late, so I probably do not deserve one, but I was working constantly, so it was just late because of installation trouble. |
Beta Was this translation helpful? Give feedback.
-
Benchmark PR Installing Bril went surprisingly smoothly - I'm a NixOS user, so I usually expect a little bit of turmoil to get things made for generic Linux environments to run, but here everything largely worked. For my benchmark, I wanted to create something non-trivial that would still be interesting. I saw that there was a typescript to bril compiler, so I learned a little bit of typescript and wrote a program to find the square root of an integer using a binary search. I struggled for a bit with the ts2bril, as I didn't realize just how much of a subset of typescript it could handle: not even a For my tool, I wanted to make something that I could plausibly imagine someone using. I decided to make a tool to count the number of instances of recursion in a program, which would just be the number of times a function has a call to itself in its own body. Of course, this couldn't handle cases where For my CFG and Benchmark, I used the algorithms in class. I did only look at the I believe my work would deserve a Michelin star had it been on-time, but it is 3 days late. I was ill for most of last week, though, so I'm asking for leniency. |
Beta Was this translation helpful? Give feedback.
-
Benchmark PR: sampsyo/bril#387 Tool: source Basic Blocks and CFG: source Conclusions: I think I got decently comfortable with the Bril tools and workflow through these tasks, and I'm starting to develop an appreciation for Turnt. I didn't run into any major issues with any of the tools, and I liked how simple the core of Bril is, which made it relatively easy to understand and pick up. Writing the tool and CFG generator was also helpful for setting up a workflow for manipulating Bril programs. Overall, I think my work deserves a Michelin star because of the Bril exploration in writing my benchmark, thorough testing with Turnt, and familiarization with the ecosystem. |
Beta Was this translation helpful? Give feedback.
-
When you finish your tasks for Lesson 2, post here! 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