diff --git a/README.md b/README.md index aeb3703..de6c0d1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # CS153 -Following Harvard's CS153 compiler class \ No newline at end of file +Following Harvard's CS153 compiler class + +Link from Harvard: https://canvas.harvard.edu/courses/124796 +Link from UPenn: https://www.seas.upenn.edu/~cis5521/current/ +Another alternative link: https://ilyasergey.net/CS4212/ diff --git a/hw1/.devcontainer/.zshrc b/hw1/.devcontainer/.zshrc new file mode 100644 index 0000000..d38a73f --- /dev/null +++ b/hw1/.devcontainer/.zshrc @@ -0,0 +1,13 @@ +autoload -U colors && colors +precmd() { + drawline="" + for i in {1..$COLUMNS}; drawline=" $drawline" + drawline="%U${drawline}%u" + PS1="%F{252}${drawline} +%B%F{124}%n:%~>%b%f " +} + +eval $(opam env) + +alias ls="ls --color" + diff --git a/hw1/.devcontainer/Dockerfile b/hw1/.devcontainer/Dockerfile new file mode 100644 index 0000000..5ad118f --- /dev/null +++ b/hw1/.devcontainer/Dockerfile @@ -0,0 +1,79 @@ +FROM ubuntu:20.04 + +## BEGIN: RUNS AS ROOT + +# Create a user + +ARG USERNAME=cs131 +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +ENV TZ='Asia/Shanghai' +# !!![zjy] apt change ustc source +RUN apt-get update -y \ + && apt-get install -y --no-install-recommends \ + apt-transport-https \ + ca-certificates \ + dos2unix \ + tzdata \ + && sed -i "s@http://.*.ubuntu.com@https://mirrors.ustc.edu.cn@g" /etc/apt/sources.list \ + && rm -rf /var/apt/cache/* + +RUN groupadd --gid $USER_GID $USERNAME \ + # [Optional] Add sudo support. Omit if you don't need to install software after connecting. + && apt-get update \ + && apt-get install -y sudo \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME + + +## Hack needs root permissions + +# See hack.sh +COPY hack.sh /tmp/hack.sh +# windows compatibility +RUN dos2unix /tmp/hack.sh +RUN chmod +x /tmp/hack.sh +RUN /tmp/hack.sh + +RUN apt-get update -y +RUN apt-get install -y build-essential +RUN apt-get install -y m4 +RUN apt-get install -y opam +RUN apt-get install -y clang +RUN apt-get install -y time +RUN apt-get install -y zip +# !!![zjy] install zsh first then set user +RUN apt-get install -y zsh + +# !!![zjy] install zsh first then set user +RUN useradd --uid $USER_UID --gid $USER_GID -m $USERNAME --shell /bin/zsh + + +## Set up user environmnent +COPY .zshrc /home/$USERNAME/ +RUN dos2unix /home/$USERNAME/.zshrc +RUN chown $USERNAME /home/$USERNAME/.zshrc + +## Run in usermode + +# [Optional] Set the default user. Omit if you want to keep the default as root. +USER $USERNAME + +RUN mkdir -p /home/$USERNAME/.local/state/ +RUN touch /home/$USERNAME/.local/state/utop-history + +# Configure opam/ocaml +# !!![zjy] change default repo to github (SJTU repo is failed) +# RUN opam init --yes --disable-sandboxing default https://github.com/ocaml/opam-repository.git +RUN opam init -y --disable-sandboxing --compiler=4.14.1 +# RUN opam switch create 4.14.1 ocaml-base-compiler.4.14.1 +RUN opam switch 4.14.1 +RUN opam install --yes dune +RUN opam install --yes num +RUN opam install --yes menhir +RUN opam install -y utop +RUN opam install -y ocamlformat +RUN opam install -y ocaml-lsp-server +RUN eval `opam config env` + diff --git a/hw1/.devcontainer/devcontainer.json b/hw1/.devcontainer/devcontainer.json new file mode 100644 index 0000000..1bca7ce --- /dev/null +++ b/hw1/.devcontainer/devcontainer.json @@ -0,0 +1,30 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +{ + "name": "Ubuntu", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "build": { + "dockerfile": "Dockerfile" + }, + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "ocamllabs.ocaml-platform" + ] + } + } + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/hw1/.devcontainer/hack.sh b/hw1/.devcontainer/hack.sh new file mode 100644 index 0000000..b6d2c3f --- /dev/null +++ b/hw1/.devcontainer/hack.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +### HACK - workaround ubuntu libc6 version number bug see: https://forum.odroid.com/viewtopic.php?p=344373 + +mv /bin/uname /bin/uname.orig +tee -a /bin/uname < int', which is the type of a function + that takes an int argument and produces an int result. + See IOC Chapter 3.1 + + Functions values are introduced using the 'fun' keyword and the '->' sytnax: + fun (x:int) -> x + x (* a function that takes an int and doubles it *) + + Functions are first class -- they can passed around just like integers or + other primitive data. +*) + +(* bind the variable 'double' of type 'int -> int' to a function: *) +let double : int -> int = fun (x : int) -> x + x + +(* + Functions are called or 'applied' by juxtaposition -- the space ' ' + between a function name and its arguments is the function application site. + Unlike Java or C, no parentheses are needed, exept for grouping and + precedence: +*) +let doubled_z : int = double z (* call double on z *) + +let quadrupled_z : int = double (double z) (* parens needed for grouping *) + +let sextupled_z : int = quadrupled_z + double z + +(* + Functions with more than one argument have types like: + 'int -> int -> int', which is the type of a function that takes an int + and returns a function that itself takes an int and returns an int. + i.e. 'int -> int -> int' is just 'int -> (int -> int)' +*) + +let mult : int -> int -> int = fun (x : int) (y : int) -> x * y +let squared_z : int = mult z z (* multiply z times z *) + +(* + Because functions like 'mult' above return functions, they can be + partially applied: +*) +let mult_by_3 : int -> int = mult 3 (* partially apply mult to 3 *) + +let mult_by_4 : int -> int = mult 4 (* partially apply mult to 4 *) + +let meaning_of_life : int = mult_by_3 14 +(* call the partially applied function *) + +let excellent_score : int = mult_by_4 25 (* compute 100 *) + +(* + The let-fun syntax above is a bit heavy, so OCaml provides syntactic sugar + for abbreviating function definitions, avoiding the need for 'fun' and + redundant-type annotations. + + For example, we can write double like this: +*) +let double (x : int) : int = x + x (* this definition shadows the earlier one *) + +(* and mult like this: *) +let mult (x : int) (y : int) : int = x * y + +(* We still call them in the same way as before: *) +let quadrupled_z : int = double (double z) (* parens needed for grouping *) + +let mult_by_3 : int -> int = mult 3 (* partially apply mult to 3 *) + +(* + Note the use of type annotations + let f (arg1:t1) (arg2:t2) ... (argN:tN) : retT = ... + Defines f, a function of type t1 -> t2 -> ... -> tN -> retT +*) + +(* Functions are first-class values, they can be passed to other functions: *) +let twice (f : int -> int) (x : int) : int = + (* f is a function from ints to ints *) + f (f x) + +let quadrupled_z_again : int = twice double z (* pass double to twice *) + +(* OCaml's top-level-loop --------------------------------------------------- *) +(* + + You can play around with OCaml programs in the 'top-level-loop'. This is an + interactive OCaml session that accepts OCaml expressions on the command line, + compiles them, runs the resulting bytecode, and then prints out the result. + The top-level-loop is hard to use once programs get big (and are distributed + into many source files), but it is a great way to learn the OCaml basics, and + for trying out one-file programs like 'hellocaml.ml'. + + We recommend using 'utop' -- a featureful toplevel loop that is well + integrated with VSCode. + + When you run utop, you get a welcome message and then a prompt: + + utop # + + You can type ocaml expressions at the prompt like this: + + # 3 + 4;; + -: int = 7 + + To quit, use the '#quit' directive: + + # #quit;; + + Note that, in the top-level-loop (unlike in a source file) top-level def- + -initions and expressions to be evaluated must be terminated by ';;'. OCaml + will compile and run the result (in this case computing the int 7). + + (Restart utop now.) + You can (re)load .ml files into the top-level loop via the '#use' directive: + + # #use "bin/hellocaml.ml";; + ... + + In this case, OCaml behaves as though you entered in all of the contents of + the .ml file at the command prompt (except that ';;' is not needed). + + Try it now -- load this "bin/hellocaml.ml" file into the OCaml top level. + If you succeed, you should see a long list of definitions that this file + makes. (Note that utop, by default, will start in whatever directory you + run it in; by default, that will probably be the root directory of + your project. You can change utop's working directory using the #cd command.) + + Once you '#use' a file, you can then interact with the functions and other + values it defines at the top-level. This can be very useful when playing + around with your programs, debugging, or testing functions. + + Try it now: after using Hellocaml.ml, type `twice ((+) 2) 4;;` a the + prompt. Utop should respond with: + + - : int = 8 + + In many cases are lots of files that you want to load into utop, so we have + provided a file called `.initocaml`, which sets up utop with all of the + code in your project. (If you make changes you may want to stop and + then restart utop). Rather than being directly imported into the toplevel + as with #use, the loaded code will follow the module structure of the + project. For example, the modules Hellocaml, Main, Util.Assert, etc., are + all part of this project. + + Try it now -- restart utop (remember #quit) and then begin typing + "Hellocaml.tw...". Utop will offer code completions at the bottom of the + terminal, which can be chosen using tab. For example, you can find + the `twice` function we defined earlier. + + utop # Hellocaml.tw + +*) + +(* Compiling ---------------------------------------------------------------- *) +(* + You can also run your project using the test harness and the 'oatc' file. + + If you are using VScode, you can work with the command line in its built-in + shell. Note that you can start more than one shell (which is useful to + have `make dev` going at the same time as other work). + + We recommend using the command line to build and ineract with your code, and + will provide you with a suitable Makefile for each assignment. The Makefile + includes suitable targets for building, testing, cleaning, and zipping your + homework files for submission. Just doing `make` will build the project: + + > make + dune build + [[ warnings omitted ]] + + If the project successfully compiles, you should see the `oatc` executable + in the working directory. For now, `oatc` is a simple wrapper for running + test cases. Later projects will turn `oatc` into a (more) fully-fledged + compiler. + + `make test` will execute the test harness, which is equivalent to invoking + `oatc --test` from the command line. + + The test harness is a useful way to determine how much of the assignment you + have completed. We will be using (a variant of) this test harness to + partially automate grading of your project code. We will also do some + manual grading of your code, and we may withhold some of the tests cases + we run -- you should definitely test your projects thoroughly on your own. + Later in the course we will encourage you (and may even require you) to + submit test cases so that you can help each other test your implementations. + + Hint: examining the test cases in gradedtests.ml can help you figure out + the specifications of the code you are supposed to implement. +*) + +(* PART 1 Problems ---------------------------------------------------------- *) +(* + Complete the following definitions as directed -- you can tell when you get + them right because the unit tests specified in part1_tests of the + gradedtests.ml file will succeed when you run main with the '--test' flag. + + Note that (fun _ -> failwith "unimplemented") is a function that takes any + argument and raises a Failure exception -- you will have to replace these + definitions with other function definitions to pass the tests. +*) + +(* Problem 1-1 *) +(* + The 'pieces' variable below is bound to the wrong value. Bind it to one that + makes the first case of part1_tests "Problem 1" succeed. See the + gradedtests.ml file. +*) +let pieces : int = -1 + +(* Implement a function cube that takes an int value and produces its cube. *) +let cube : int -> int = fun _ -> failwith "cube unimplemented" + +(* Problem 1-2 *) +(* + Write a function "cents_of" that takes + q - a number of quarters + d - a number of dimes + n - a number of nickels + p - a number of pennies + (all numbers non-negative) + and computes the total value of the coins in cents: +*) +let cents_of : int -> int -> int -> int -> int = + fun _ -> failwith "cents_of unimplemented" + +(* Problem 1-3 *) +(* + Edit the function argument of the "Student-Provided Problem 3" test in + test/studenttests.ml so that "case1" passes, given the definition below. You + will need to remove the function body starting with failwith and replace it + with something else. +*) +let prob3_ans : int = 42 + +(* + Edit the function argument of the "Student-Provided Problem 3" test in + test/studenttests.ml so that "case2" passes, given the definition below: +*) +let prob3_case2 (x : int) : int = prob3_ans - x + +(* + Replace 0 with a literal integer argument in the "Student-Provided Problem 3" + test in test/studenttest.ml so that "case3" passes, given the definition below: +*) +let prob3_case3 : int = + let aux = prob3_case2 10 in + double aux + +(* + In this and later projects, you can add your own test cases to the + test/studenttests.ml file. They are automatically run by the test harness + when you do `make test` or `oatc --test` from the command line. +*) + +(******************************************************************************) +(* *) +(* PART 2: Tuples, Generics, Pattern Matching *) +(* *) +(******************************************************************************) + +(* + NOTE: See IOC 5.2 + Tuples are a built-in aggregate datatype that generalizes + pairs, triples, etc. Tuples have types like: + int * bool * string + At the value level, tuples are written using ',': +*) + +let triple : int * bool * string = (3, true, "some string") + +(* NOTE: technically, the parentheses are _optional_, so we could have done: *) +let triple : int * bool * string = 3, true, "some string" + +(* Tuples can nest *) +let pair_of_triples : (int * bool * string) * (int * bool * string) = + (triple, triple) + +(* + IMPORTANT!! Be sure to learn this! + + You can destruct tuples and most other kinds of data by "pattern-matching". + + Pattern matching is a fundamental concept in OCaml: most + non-trivial OCaml types are usually "destructed" or "inspected" by + pattern matching using the 'match-with' notation. See IOC Chapter 4. + + A "pattern" looks like a value, except that it can have 'holes' + marked by _ that indicate irrelevant parts of the pattern, and + binders, indicated by variables. + + Consider: + + begin match exp with + | pat1 -> case1 + | pat2 -> case2 + ... + end + + This evaluates exp until it reaches a value. Then, that value is + 'matched' against the patterns pat1, pat2, etc. until a match is + found. When the first match is found, the variables appearing in + the pattern are bound to the corresponding parts of the value and + the case associated with the pattern is executed. + + If no match is found, OCaml will raise a Match_failure exception. + If your patterns are not exhaustive -- i.e. they do not cover + all of the possible cases, the compiler will issue a (usually very + helpful) warning. +*) + +(* + Tuples are "generic" or "polymorphic" -- you can create tuples of any + datatypes. See IOC 5.1 + + The generic parts of types in OCaml are written using tick ' notation: + as shown in the examples below. What you might write in Java as + List you would write in OCaml as 'a list -- type parameters + are written in prefix. + Similarly, Map would be written as ('a,'b) map -- multiple + type parameters use a 'tuple' notation. +*) + +(* + NOTE: + 'a is pronounced "tick a" or "alpha". + 'b is pronounced "tick b" or "beta". + 'c is pronounced "tick c" or "gamma". + + Using Greek letters -- this an ML tradition that dates back to its use + for developing formal logics and proof systems. +*) + +(* + TIP: In VSCode you can get the type of an expression by hovering the + mouse cursor over the program text. This only works if the program + successfully compiled. + + If you're using Emacs or Vim with the merlin plugin, you can get the + type of a an expression at the cursor too: ^C ^T on Emacs +*) + +(* Example pattern matching against tuples: *) +let first_of_three (t : 'a * 'b * 'c) : 'a = + (* t is a generic triple *) + match t with x, _, _ -> x + +let t1 : int = first_of_three triple (* binds t1 to 3 *) + +let second_of_three (t : 'a * 'b * 'c) : 'b = match t with _, x, _ -> x +let t2 : bool = second_of_three triple (* binds t2 to true *) + +(* + This generic function takes an arbitrary input, x, and + returns a pair both of whose components are the given input: +*) +let pair_up (x : 'a) : 'a * 'a = (x, x) + +(* Part 2 Problems ---------------------------------------------------------- *) + +(* + Problem 2-1 + + Complete the definition of third_of_three; be sure to give it + the correct type signature (we will grade that part manually): +*) +let third_of_three _ = failwith "third_of_three unimplemented" + +(* + Problem 2-2 + + Implement a function compose_pair of the given type that takes + a pair of functions and composes them in sequence. Note that + you must return a function. See the test cases in gradedtests.ml + for examples of its use. +*) + +let compose_pair (p : ('b -> 'c) * ('a -> 'b)) : 'a -> 'c = + failwith "compose_pair unimplemented" + +(******************************************************************************) +(* *) +(* PART 3: Lists and Recursion *) +(* *) +(******************************************************************************) + +(* + OCaml has a built-in datatype of generic lists: See IOC 5.3 + + [] is the nil list + if + h is a head-value of type t + tl is a list of elements of type t + then + h::tl is a list with h as the head and tl as the tail + + `::` is pronounced "cons", as it constructs a list. +*) + +let list1 : int list = [ 3; 2; 1 ] + +(* Lists can also be written using the [v1;v2;v3] notation: *) + +let list1' = [ 3; 2; 1 ] (* this is equivalent to list1 *) + +(* Lists are homogeneous -- they hold values of only one type: *) +(* Uncomment to get a type error; recomment to compile: + let bad_list = [1;"hello";true] +*) + +(* + As usual in OCaml, we use pattern matching to destruct lists. + For example, to determine whether a list has length 0 we need to + do a case-analysis (via pattern matching) to see whether it is nil + or is non-empty. The following function takes a list l and + determines whether l is empty: +*) +let is_empty (l : 'a list) : bool = + match l with [] -> true (* nil case -- return true *) | _ -> false +(* non-nil case -- return false *) + +let ans1 : bool = is_empty [] (* evaluates to true *) + +let ans2 : bool = is_empty list1 (* evaluates to false *) + +(* + Lists are an example of a "disjoint union" data type -- they are either + empty [] or have some head value consed on to a tail h::tl. + OCaml provides programmers with mechanisms to define their own generic + disjoint union and potentially recursive types using the 'type' keyword. +*) + +(* + A user-defined generic type ('a mylist) can be defined within OCaml by: +*) + +type 'a mylist = + | Nil + (* my version of [] *) + | Cons of 'a * 'a mylist +(* Cons(h,tl) is my version of h::tl *) + +(* + We build a mylist by using its 'constructors' (specified in the branches) + For example, compare mylist1 below to list1 defined by built-in lists + above: +*) +let mylist1 : int mylist = Cons (3, Cons (2, Cons (1, Nil))) + +(* + Pattern matching against a user-defined datatype works the same as for + a built-in type. The cases we need to consider in a pattern are given by + the cases of the type definition. For example, to write the is_empty + function for mylist we do the following. Compare it with is_empty: +*) +let is_mylist_empty (l : 'a mylist) : bool = + match l with Nil -> true | Cons _ -> false + +(* + IMPORTANT!! Be sure to learn this! + + Recursion: The built in list type and the mylist type we defined above + are recursive -- they are defined in terms of themselves. To implement + useful functions over such datatypes, we often need to use recursion. + + Recursive functions in OCaml use the 'rec' keyword -- inside the body + of a recursive function, you can call the function being defined. As usual + you must be careful not to introduce infinite loops. + + Recursion plus pattern matching is a very powerful combination. Here is + a recursive function that sums the elements of an integer list: +*) + +let rec sum (l : int list) : int = + (* note the 'rec' keyword! *) + match l with [] -> 0 | x :: xs -> x + sum xs +(* note the recursive call to sum *) + +let sum_ans1 : int = sum [ 1; 2; 3 ] (* evaluates to 6 *) + +(* + Here is a function that takes a list and determines whether it is + sorted and contains no duplicates according to the built-in + generic inequality test < + + Note that it uses nested pattern matching to name the + first two elements of the list in the third case of the match: +*) +let rec is_sorted (l : 'a list) : bool = + match l with + | [] -> true + | [ _ ] -> true + | h1 :: h2 :: tl -> h1 < h2 && is_sorted (h2 :: tl) + +let is_sorted_ans1 : bool = is_sorted [ 1; 2; 3 ] (* true *) + +let is_sorted_ans2 : bool = is_sorted [ 1; 3; 2 ] (* false *) + +(* + The List library + (see http://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html) + implements many useful functions for list maniuplation. You will + recreate some of them in the exercises below. + + Here is map, one of the most useful: +*) +let rec map (f : 'a -> 'b) (l : 'a list) : 'b list = + match l with [] -> [] | h :: tl -> f h :: map f tl + +let map_ans1 : int list = map double [ 1; 2; 3 ] (* evaluates to [2;4;6] *) + +let map_ans2 : (int * int) list = map pair_up [ 1; 2; 3 ] +(* evaluates to [(1,1);(2,2);(3,3)] *) + +(* + The mylist type is isomorphic to the built-in lists. + The recursive function below converts a mylist to a built-in list. +*) + +let rec mylist_to_list (l : 'a mylist) : 'a list = + match l with Nil -> [] | Cons (h, tl) -> h :: mylist_to_list tl + +(* Part 3 Problems ---------------------------------------------------------- *) + +(* + Problem 3-1 + + Implement list_to_mylist with the type signature below; this is + the inverse of the mylist_to_list function given above. +*) +let rec list_to_mylist (l : 'a list) : 'a mylist = + failwith "list_to_mylist unimplemented" + +(* + Problem 3-2 + + Implement the library function append, which takes two lists (of the same + types) and concatenates them. Do not use the library function or the built-in + short-hand '@'. + + (append [1;2;3] [4;5]) should evaluate to [1;2;3;4;5] + (append [] []) should evaluate to [] + + Note that OCaml provides the infix fuction @ as an alternate way of writing + append. So (List.append [1;2] [3]) is the same as ([1;2] @ [3]). +*) +let rec append (l1 : 'a list) (l2 : 'a list) : 'a list = + failwith "append unimplemented" + +(* + Problem 3-3 + + Implement the library function rev, which reverses a list. In this solution, + you might want to call append. Do not use the library function. +*) +let rec rev (l : 'a list) : 'a list = + failwith "rev unimplemented" + +(* + Problem 3-4 + + Read IOC 5.4 about "tail recursion" and implement a tail recursive version of + rev. Note that you will need a helper function that takes an extra parameter + -- it should be defined using a local let definition. The rev_t function + itself should not be recursive. Tail recursion is important to efficiency -- + OCaml will compile a tail recursive function to a simple loop. +*) +let rev_t (l : 'a list) : 'a list = + failwith "rev_t unimplemented" + +(* + Problem 3-5 + + Implement insert, a function that, given an element x and a sorted list l + (i.e. one for which is_sorted returns true) returns the list obtained by + inserting x into the list l at the proper location. Note that if x is + already in the list then insert should just return the original list. + + You will need to use the if-then-else expression (see IOC 2.2). Remember that + OCaml is expression-oriented; "if t then e1 else e2" evaluates to either the + value computed by e1 or the value computed by e2 depending on whether t + evaluates to true or false. +*) +let rec insert (x : 'a) (l : 'a list) : 'a list = + failwith "insert unimplemented" + +(* + Problem 3-6 + + Implement union, a function that takes two sorted lists and returns the + sorted list containing all of the elements from both of the two input lists. + Hint: you might want to use the insert function that you just defined. +*) +let rec union (l1 : 'a list) (l2 : 'a list) : 'a list = + failwith "union unimplemented" + +(******************************************************************************) +(* *) +(* PART 3: Expression Trees and Interpreters *) +(* *) +(******************************************************************************) + +(* TERMINOLOGY: "Object" level vs. "Meta" level + + When we implement a compiler, we use code in one programming language to + implement the features of another language. The language we are implementing + is called the "object language" -- it is the "object of study". In contrast, + the language we use to implement the object language in is called the + "meta language" -- it is used to "talk about" the object language. In this + course OCaml will usually be the "meta language" (indeed the 'm' and 'l' in + OCaml come from ML - meta language). + + We will implement several different object languages in this course. Within + the metalanguage, we use ordinary datatypes: lists, tuples, trees, unions,etc. + to represent the features of the object language. A compiler is just a + function that translates one representation of an object language into + another (usually while preserving some notion of a program's 'behavior'). + + The representation of a language is often best done using an "abstract syntax + tree" -- a representation that hides concrete details about parsing, + infix syntax, syntactic sugar, etc. +*) + +(* + In this course we will be working with many kinds of abstract syntax trees. + Such trees are a convenient way of representing the syntax of a programming + language. In OCaml, we build such datatypes using the technology we have + already seen above. + + Here is a simple datatype of arithemetic expressions. To make things slightly + more interesting, and to familiarize you with another important library, these + expressions trees denote 64-bit integers. See the Int64 module of the OCaml + standard library. We have to use Int64.add to work with these kinds of numbers. + (The OCaml notation Int64.add accesses the 'add' function defined in the Int64 + library -- you can use similar notation for List.map, etc. + + 64-bit literal constants are written with the `L` suffix: 0L, 1L, 2L, etc. +*) + +(* An object language: a simple datatype of 64-bit integer expressions *) +type exp = + | Var of string (* string representing an object-language variable *) + | Const of int64 (* a constant int64 value -- use the 'L' suffix *) + | Add of exp * exp (* sum of two expressions *) + | Mult of exp * exp (* product of two expressions *) + | Neg of exp (* negation of an expression *) + +(* + An object-language arithmetic expression whose concrete (ASCII) syntax is + "2 * 3" could be represented like this: +*) +let e1 : exp = Mult (Const 2L, Const 3L) (* "2 * 3" *) + +(* + If the object-level expression contains variables, we represent them as + strings, like this: +*) +let e2 : exp = Add (Var "x", Const 1L) (* "x + 1" *) + +(* Here is a more complex expression that involves multiple variables: *) + +let e3 : exp = Mult (Var "y", Mult (e2, Neg e2)) (* "y * ((x+1) * -(x+1))" *) + +(* + Problem 4-1 + + Implement vars_of -- a function that, given en expression e returns + a list containing exactly the strings representing variables that appear + in the expression. The result should be a set -- that is, it should + contain no duplicates and be sorted (according to is_sorted). + + For example: + vars_of e1 should produce [] + vars_of e2 should produce ["x"] + vars_of e3 should produce ["x";"y"] + + Hint: you need to pattern match on the exp e. + Hint: you probably want to use the 'union' function you wrote for Problem 3-5. +*) +let rec vars_of (e : exp) : string list = + failwith "vars_of unimplemented" + +(* + How should we _interpret_ (i.e. give meaning to) an expression? + + Some examples: + Add(Const 3L, Const 5L) should have the interpretation 8L + Mult(Const 2L, (Add(Const 3L, Const 5L))) denotes 16L + + What about Add(Var "x", Const 1L)? + What should we do with (Var "x")? + + Each expression denotes an int64 value, but since it can contain variables, + we need an "evaluation context" that maps variable names to int64 values. + + NOTE: an _evaluation context_ is just a finite map from variables to values. + + One simple (but not particularly efficient) way to represent a context is as + an "association list" that is just a list of (string * int64) pairs: +*) + +type ctxt = (string * int64) list + +(* Here are some example evalution contexts: *) +let ctxt1 : ctxt = [ ("x", 3L) ] (* maps "x" to 3L *) + +let ctxt2 : ctxt = [ ("x", 2L); ("y", 7L) ] (* maps "x" to 2L, "y" to 7L *) + +(* + When interpreting an expression, we need to look up the value + associated with a variable in an evaluation context. + For example: + lookup "x" ctxt1 should yield 3L + lookup "x" ctxt2 should yield 2L + lookup "y" cxtx2 should yield 7L + + What if we lookup a variable that doesn't appear in the context? In that + case we raise an exception. OCaml provides user-defined and some pre- + defined exceptions. For container-like structures (like ctxt), the + Not_found exception is appropriate. + + See IOC 9.2.1 (and 9.2 about exception handlers) + + To throw an exception Exception just use: + raise Exception + For example: + lookup "y" ctxt1 should raise Not_found + + There is one other case to consider -- if the context has two bindings for a + variable, the one closer to the head of the list should take precedence. + For example: + lookup "x" [("x", 1L);("x", 2L)] should yield 1L (not 2L) +*) + +(* + Problem 4-2 + + Implement the lookup function with the signature given below. It should find + the int64 value associated with a given string in the ctxt c. If there is no + such value, it should raise the Not_found exception. +*) +let rec lookup (x : string) (c : ctxt) : int64 = + failwith "unimplemented" + +(* + Problem 4-3 + + At last, we can write an interpreter for exp's. This is just a function + 'interpret' that, given an evaluation context c and an expression e, computes + an int64 value corresponding to the expression. If the expression mentions a + variable that does not appear in the context, interpret should throw the + Not_found exception (note that this amounts to trying to lookup the variable + and *not* catching any resulting Not_found exception.) + + For example: + interpret ctxt1 e1 should yield 6L + interpret ctxt1 e2 should yield 4L + interpret ctxt1 e3 should raise a Not_found exception + + Note that the interpreter should recursively call itself to obtain the int64 + values of subexpressions. You will need to use the Int64 library to + implement addition and multiplication. + + You should test your interpeter on more examples than just those provided in + gradedtests.ml. +*) + +let rec interpret (c : ctxt) (e : exp) : int64 = + failwith "unimplemented" + +(* + Problem 4-4 + + Now, write an _optimizer_ for expressions. An optimizer is just a function + that tries to reduce the number of operations by doing some work "at compile + time" rather than at "run time". + + For example: + optimize (Add(Const 3L, Const 4L)) might yield (Const 7L) + optimize (Mult(Const 0L, Var "x")) might yield (Const 0L) + + No matter what optimizations your function performs, it should not change the + value computed by the expression (if there is one). That is, for every + context c and exp e, if c has bindings for all the variables in e, it should + be the case that: + + (interpret c e) = (interpret c (optimize e)) + + Note that it is not always possible to reduce the size of an expression: + (Var "x") is already "optimal"). You will also have to optimize sub- + expressions before applying further optimizations -- this means that you will + need to use nested match expressions. + + Here is a (slightly) more complex example: + optimize (Add(Const 3L, Mult(Const 0L, Var "x"))) yields (Const 3L) + + Note that your optimizer won't be complete (unless you work *very* hard) + for example, + Add(Var "x", Neg(Add(Var "x", Neg(Const 1L)))) "x - (x - 1)" + is equivalent to Const 1l, but we do not expect your optimizer to + discover that. Indeed, there are many algebraic laws that would be hard + to fully exploit. + + You can get full credit for this problem if your optimizer: + (1) doesn't change the meaning of an expression in any context + that provides bindings for all of the expression's variables + (2) recursively reduces the size of the expression in "obvious" cases + -- adding 0, multiplying by 0 or 1, constants, etc. + + Hint: what simple optimizations can you do with Neg? +*) + +let rec optimize (e : exp) : exp = + failwith "optimize unimplemented" + +(******************************************************************************) +(* *) +(* PART 4: Compiling the Expression Language to a Stack-Based Language *) +(* *) +(******************************************************************************) + +(* + The interpreter for the expression language above is simple, but the language + itself is fairly high-level in the sense that we are using many meta-language + (OCaml) features to define the behavior of the object language. For example, + the natural way of defining the 'interpret' function as a recursive OCaml + function means that we rely on OCaml's function calls and its order of + evaluation. + + Let's look at a closely-related but "lower-level" language for defining + arithmetic expressions. + + Unlike the language 'exp' defined above, which has nested subexpressions, a + program in the new language will simply be a list of instructions that specify + a sequence of actions to carry out. Also unlike the 'exp' language, which uses + OCaml's recursive functions and hence a (meta-level) call stack to keep track + of the order in which subexpressions are processed, this new language will + explicitly manipulate its own stack of Int64 values. + + (ASIDE: historically, several companies actually built calculators that used + this "reverse polish notation" programming language to express their + computations. Google for it to find out more...) + *) + +(* + The instructions of the new language are defined as follows. Note that the + instructions IMul, IAdd, and INeg pop their input values from the stack and + push their results onto the stack. +*) +type insn = + | IPushC of int64 (* push an int64 constant onto the stack *) + | IPushV of string (* push (lookup string ctxt) onto the stack *) + | IMul (* multiply the top two values on the stack *) + | IAdd (* add the top two values on the stack *) + | INeg +(* negate the top value on the stack *) + +(* A stack program is just a list of instructions. *) +type program = insn list + +(* + The stack itself is represented as a list of int64 values, where the head of + the list is the top of the stack. +*) +type stack = int64 list + +(* + The operational semantics (i.e. behavior) of this new language can easily be + specified by saying how one instruction step is performed. Each step takes a + stack and returns the new stack resulting from carrying out the computation. + + Note that this function is not recursive, and also that it might raise an + exception if the stack doesn't have enough entries. As with the 'exp' + language interpreter, we use a context to lookup the value of variables. +*) + +let step (c : ctxt) (s : stack) (i : insn) : stack = + match (i, s) with + | IPushC n, _ -> n :: s (* push n onto the stack *) + | IPushV x, _ -> lookup x c :: s (* lookup x, push it *) + | IMul, v1 :: v2 :: s -> Int64.mul v1 v2 :: s + | IAdd, v1 :: v2 :: s -> Int64.add v1 v2 :: s + | INeg, v1 :: s -> Int64.neg v1 :: s + | _ -> failwith "Stack had too few values" + +(* + To define how a program executes, we simply iterate over the + instructions, threading the stack through. +*) +let rec execute (c : ctxt) (s : stack) (p : program) : stack = + match p with + | [] -> s (* no more instructions to execute *) + | i :: cont -> execute c (step c s i) cont + +(* + If you want to be slick, you can write the above equivalently using + List.fold_left (which is tail recrusive and hence iterative): +*) +let execute' (c : ctxt) = List.fold_left (step c) + +(* + Let us define 'answer' to mean the sole value of a stack containing only one + element. This makes sense since: if a program left the stack empty, there + wouldn't be any int64 value computed and if there is more than one value on + the stack, that means that the program 'stopped' too early. +*) +let answer (s : stack) : int64 = + match s with [ n ] -> n | _ -> failwith "no answer" + +(* + Finally, we can 'run' a program in a given context by executing it starting + from the empty stack and returning the answer that the program computes. + *) +let run (c : ctxt) (p : program) : int64 = answer (execute c [] p) + +(* + As an example program in this stack language, consider the following program + that runs to produce the answer 6. + + Compare this program to the 'exp' program called e1 above. They both compute + the value 2 * 3. +*) +let p1 = [ IPushC 2L; IPushC 3L; IMul ] +let ans1 = run [] p1 + +(* + Problem 5 + + Implement a function 'compile' that takes a program in the 'exp' language and + translates it to an equivalent program in the 'stack' language. + + For example, (compile e1) should yield the program p1 given above. + + Correctness means that: + For all expressions e, contexts c (defining the variables in e), and int64 + values v: + + (interpret c e) = v if and only if + (run c (compile e)) = v + + Hints: + - Think about how to define your compiler compositionally so that you build + up the sequence of instructions for a compound expression like Add(e1, e2) + from the programs that compute e1 and e2. + + - You may want to use the append function (or the built in @) function to + glue together two programs. + + - You should test the correctness of your compiler on several examples. +*) +let rec compile (e : exp) : program = + failwith "compile unimplemented" + +(************) +(* Epilogue *) +(************) + +(* + Whew! That was a whirl-wind tour of OCaml. There are still quite a few + features we haven't seen -- we'll mention them in the next project and later + as needed. However, even with this little bit of OCaml and a few basic ideas + you've probably seen in other languages, you can already go quite far. + + Take a quick read through lib/util/assert.ml -- this is a small libary for writing + unit tests that we'll use for grading throughout this course. It makes + extensive use of unions, lists, strings, ints, and a few List and Printf + library functions, but otherwise it should be fairly readable to you already... +*) diff --git a/hw1/bin/main.ml b/hw1/bin/main.ml new file mode 100644 index 0000000..09dd6b0 --- /dev/null +++ b/hw1/bin/main.ml @@ -0,0 +1,45 @@ +(* CIS341 main test harness *) +(* Author: Steve Zdancewic *) + +(* Do NOT modify this file -- we will overwrite it with our *) +(* own version when we test your homework. *) + +open Util.Assert +open Arg + +exception Ran_tests + +let worklist = ref [] + +let suite = ref (Studenttests.student_tests @ Gradedtests.graded_tests) + +let exec_tests () = + let o = run_suite !suite in + Printf.printf "%s\n" (outcome_to_string o) ; + raise Ran_tests + + +let do_one_file fn = + let _ = Printf.printf "Processing: %s\n" fn in + () + + +(* Use the --test option to run unit tests and the quit the program. *) +let argspec = + [ ("--test", Unit exec_tests, "run the test suite, ignoring other inputs") ] + + +let _ = + try + Arg.parse + argspec + (fun f -> worklist := f :: !worklist) + "CIS341 main test harness \n" ; + match !worklist with + | [] -> + print_endline "* Nothing to do" + | _ -> + List.iter do_one_file !worklist + with + | Ran_tests -> + () diff --git a/hw1/doc/hw1-hellocaml.rst b/hw1/doc/hw1-hellocaml.rst new file mode 100644 index 0000000..39a0275 --- /dev/null +++ b/hw1/doc/hw1-hellocaml.rst @@ -0,0 +1,141 @@ +.. -*- mode: rst -*- + +.. include:: course.links + +.. _hellocaml: + +HW1: Hellocaml +============== + +Overview +-------- + +This project provides a refresher on OCaml programming and some +warm-up exercises involving tree manipulation and recursive +programming (both of which will be highly useful when building the +compiler). It will also familiarize you with the basic workflow of the +projects in this course, including the testing framework that we will +use to (partially) automate the grading of your projects. + +Before you begin +---------------- + +For help on how to get started with OCaml see the :ref:`toolchain web pages ` +and the `OCaml web site `_. + +Please also take some time to skim the available resources on the +course homepage -- in particular, the book `Introduction to Objective +Caml <../../../current/_static/files/ocaml-book.pdf>`_ +provides a very good reference for learning OCaml. In the problems +below when you see a note like "See IOC 5.2" please refer to the +corresponding section of the book. + + +**Getting Started** + +Unlike future projects, most of the instructions for this project are +found as comments in the source files. To get started on this project, +run ``make`` from the project root directory (in VSCode or in a terminal) +and then continue to the ``bin/hellocaml.ml`` file and follow the instructions +(in comments) there. + +**Building the Project** + +It is recommended that you compile your projects from the command +line, using ``make``. We have included a ``Makefile`` that provides +several make targets that can help you with the homework:: + + make -- builds oatc using dune + make dev -- runs dune build in "watch" mode for more interactive errors + make test -- runs the test suite + make clean -- cleans your project directory + make utop -- starts a utop for the project + make zip -- creates a zip file with the code you need to submit + +For example, using make we can build the project and run the tests all +in one go:: + + > make test + dune build + ... [[ warnings omitted ]] + ./oatc --test + Running test Student-Provided Tests For Problem 1-3 + Running test Problem1-1 + Running test Problem1-2 + ... + +Command-line Running and Testing Projects +----------------------------------------- + +After compiling the project, you can run it from the command line. + +The projects in this course are designed to have a single, top-level +entry point in the file ``main.ml``. Upon running ``make``, it compiles to +an executable ``main.exe``, and copies it as ``oatc`` to the root of the project. + +The ``oatc`` program provides a test harness that can be used from the command +line with a variety of switches and command-line arguments, just like +any other compiler. You can always check which command-line switches +are available by using the ``-help`` or ``--help`` flags. For example, +HW1 supports only one interesting command-line option ``--test``:: + + > ./oatc -help + Main test harness + + --test run the test suite, ignoring other inputs + -help Display this list of options + --help Display this list of options + +All of our projects will support the ``--test`` option, which will +simply run the project's unit tests, print a summary of the results +and then exit. It might give output something like this (bogus sample) +that will give you some idea about how much of the project you've +completed:: + + > ./oatc --test + + Test1: + case1: failed - not equal + case2: failed - assert fail + case3: failed - test threw an unknown exception + Test2: + OK + Test3 (3/10 points) + case1: failed - not equal + case2: failed - not equal + case3: passed + Test4-Manual (0/3 points = 0/1 tests) + FAILED - manually: assert fail + Test5 (??/20 points): + Hidden + Test5 (10/10 points): + OK + --------------------------------------------------- + Passed: 5/10 + Failed: 5/10 + Score: 13/20 (given) + ??/20 (hidden) + +**Note:** problems that will be manually graded after you submit the +homework are considered to "fail" according to the test harness. + +Once the compiler projects reach the stage where we can generate good +assembly output, ``oatc`` will support more interesting +command-line options and be able to process input files in a way that +should be familiar if you've ever used gcc or another compiler. + +Grading +------- + +Submit your solution to this assignment by following the :ref:`submission instructions ` + +**Projects that do not compile will receive no credit!** + +Your grade for this project will be based on: + +* 64 Points for the test cases that are visible to you +* 23 Points for the hidden test cases +* 13 Points of manually graded parts + * 3 points for the type annotations in problem 2-1 (manually graded) + * 5 points for proper tail call implementation in 3-4 (manually graded) + * 5 points for "Style" and additional test cases for 4-3 and 5 (manually graded) diff --git a/hw1/dune-project b/hw1/dune-project new file mode 100644 index 0000000..9f9c83d --- /dev/null +++ b/hw1/dune-project @@ -0,0 +1,2 @@ +(lang dune 2.9) +(name hw1) diff --git a/hw1/hw1.opam b/hw1/hw1.opam new file mode 100644 index 0000000..e69de29 diff --git a/hw1/lib/util/assert.ml b/hw1/lib/util/assert.ml new file mode 100644 index 0000000..8e326a0 --- /dev/null +++ b/hw1/lib/util/assert.ml @@ -0,0 +1,195 @@ +(* CIS341 Assertion Testing and Grading Infrastructure *) +(* Author: Steve Zdancewic *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = unit -> unit + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = assertion test list + +(**************) +(* Assertions *) + +let assert_eq v1 v2 : assertion = + fun () -> if v1 <> v2 then failwith "not equal" else () + + +let assert_eqf f v2 : assertion = + fun () -> if f () <> v2 then failwith "not equal" else () + + +let assert_eqfs f v2 : assertion = + fun () -> + let s1 = f () in + if s1 <> v2 + then failwith @@ Printf.sprintf "not equal\n\texpected:%s\n\tgot:%s\n" v2 s1 + else () + + +let assert_fail : assertion = fun () -> failwith "assert fail" + +exception Timeout + +let timeout_assert (time : int) (a : assertion) : assertion = + fun () -> + let handler = Sys.Signal_handle (fun _ -> raise Timeout) in + let old = Sys.signal Sys.sigalrm handler in + let reset_sigalrm () = Sys.set_signal Sys.sigalrm old in + ignore (Unix.alarm time) ; + try + a () ; + reset_sigalrm () + with + | Timeout -> + reset_sigalrm () ; + failwith @@ Printf.sprintf "Timed out after %d seconds" time + | exc -> + reset_sigalrm () ; + raise exc + + +let timeout_test (time : int) (t : assertion test) : assertion test = + let map_timeout l = List.map (fun (i, a) -> (i, timeout_assert time a)) l in + match t with + | GradedTest (s, i, ls) -> + GradedTest (s, i, map_timeout ls) + | Test (s, ls) -> + Test (s, map_timeout ls) + + +let timeout_suite (time : int) (s : suite) : suite = + List.map (timeout_test time) s + + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = result test list + +let run_assertion (f : assertion) : result = + try + f () ; + Pass + with + | Failure m -> + Fail m + | e -> + Fail ("test threw exception: " ^ Printexc.to_string e) + + +let run_test (t : assertion test) : result test = + let run_case (cn, f) = (cn, run_assertion f) in + match t with + | GradedTest (n, s, cases) -> + Printf.eprintf "Running test %s\n%!" n ; + GradedTest (n, s, List.map run_case cases) + | Test (n, cases) -> + Printf.eprintf "Running test %s\n%!" n ; + Test (n, List.map run_case cases) + + +let run_suite (s : suite) : outcome = List.map run_test s + +(***********************) +(* Reporting functions *) + +let result_test_to_string (name_pts : string) (r : result test) : string = + let string_of_case (name, res) = + match res with + | Pass -> + "passed - " ^ name + | Fail msg -> + "FAILED - " ^ name ^ ": " ^ msg + in + match r with + | GradedTest (_, _, cases) | Test (_, cases) -> + name_pts + ^ List.fold_left + (fun rest case -> rest ^ "\n" ^ string_of_case case) + "" + cases + + +(* Number of digits of precision for a float x. Argument p is the number of decimal places desired (must be at least 1) *) +let prec_digits p x = (int_of_float @@ floor @@ log10 x) + (1 + p) + +(* returns (name_pts, passed, failed, total, points_earned, max_given, max_hidden) *) +let get_results (t : result test) = + let num_passed cases = + List.fold_left + (fun cnt (_, r) -> match r with Pass -> cnt + 1 | _ -> cnt) + 0 + cases + in + let num_failed cases = + List.fold_left + (fun cnt (_, r) -> match r with Fail _ -> cnt + 1 | _ -> cnt) + 0 + cases + in + match t with + | GradedTest (name, pts, cases) -> + let passed = num_passed cases in + let failed = num_failed cases in + let total = List.length cases in + if total > 0 + then + let points_earned = ((float_of_int passed) /. (float_of_int total)) *. (float_of_int pts) in + let name_pts = + Printf.sprintf "%s (%1.*g/%d points = %d/%d tests)" name (prec_digits 1 points_earned) points_earned pts passed total + in + (name_pts, passed, failed, total, points_earned, pts, 0) + else + let name_pts = Printf.sprintf "%s (?/%d points)" name pts in + (name_pts, passed, failed, total, 0.0, 0, pts) + | Test (name, cases) -> + let total = List.length cases in + let passed = num_passed cases in + let failed = num_failed cases in + (name, passed, failed, total, 0.0, 0, 0) + + +let outcome_to_string (o : outcome) : string = + let sep = "\n---------------------------------------------------\n" in + let helper (passed, failed, total, pts, maxg, maxh, str) (t : result test) = + let name_pts, p, f, tot, s, mg, mh = get_results t in + ( passed + p + , failed + f + , total + tot + , s +. pts + , maxg + mg + , maxh + mh + , str + ^ "\n" + ^ + if f > 0 + then result_test_to_string name_pts t + else if tot > 0 + then name_pts ^ ":\n OK" + else name_pts ^ ":\n Hidden" ) + in + let p, f, tot, pts, maxg, maxh, str = + List.fold_left helper (0, 0, 0, 0.0, 0, 0, "") o + in + str + ^ sep + ^ Printf.sprintf + "Passed: %d/%d\n\ + Failed: %d/%d\n\ + Score: %1.1f/%d (given)\n\ + \ ?/%d (hidden)" + p tot + f tot + pts maxg + maxh diff --git a/hw1/lib/util/assert.mli b/hw1/lib/util/assert.mli new file mode 100644 index 0000000..9dfa6d0 --- /dev/null +++ b/hw1/lib/util/assert.mli @@ -0,0 +1,57 @@ +(* CIS341 Assertion Testing and Grading Infrastructure *) +(* Author: Steve Zdancewic *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +exception Timeout + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = unit -> unit + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = assertion test list + +(**************) +(* Assertions *) + +val assert_eq : 'a -> 'a -> assertion + +val assert_eqf : (unit -> 'a) -> 'a -> assertion + +val assert_eqfs : (unit -> string) -> string -> assertion + +val assert_fail : assertion + +val timeout_assert : int -> assertion -> assertion + +val timeout_test : int -> assertion test -> assertion test + +val timeout_suite : int -> suite -> suite + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = result test list + +val run_assertion : assertion -> result + +val run_test : assertion test -> result test + +val run_suite : suite -> outcome + +(***********************) +(* Reporting functions *) + +val result_test_to_string : string -> result test -> string + +(* val get_results result test -> (string * int * int * int * float * int * int) *) +val outcome_to_string : outcome -> string diff --git a/hw1/lib/util/dune b/hw1/lib/util/dune new file mode 100644 index 0000000..aa0f522 --- /dev/null +++ b/hw1/lib/util/dune @@ -0,0 +1,3 @@ +(library + (name util) + (libraries str unix)) \ No newline at end of file diff --git a/hw1/lib/util/platform.ml b/hw1/lib/util/platform.ml new file mode 100644 index 0000000..13a96a0 --- /dev/null +++ b/hw1/lib/util/platform.ml @@ -0,0 +1,237 @@ +(* -------------------------------------------------------------------------- *) +(** Assembling and linking for X86. Depends on the underlying OS platform *) + +open Printf +open Unix + +exception PlatformError of string * string + +(* paths -------------------------------------------------------------------- *) +let path_sep = "/" + +let bin_path = "./bin" + +let dot_path = "./" + +let executable_name = ref "a.out" + +let output_path = ref "output" + +let libs = ref [] + +let lib_paths = ref [] + +let lib_search_paths = ref [] + +let include_paths = ref [] + +(* unix utility scripts ----------------------------------------------------- *) +let pp_cmd = ref "cpp -E " + +let rm_cmd = ref "rm -rf " + +(* -------------------------------------------------------------------------- *) +(* Platform specific configuration: Unix/Linux vs. Mac OS X *) + +let os = + let ic = Unix.open_process_in "uname -s" in + let uname = input_line ic in + let () = close_in ic in + uname + +let cpu = + let ic = Unix.open_process_in "uname -m" in + let cpuname = input_line ic in + let () = close_in ic in + cpuname + +(* One of "Darwin" or "Linux" *) + +let linux = ref false + +let mangle name = if !linux then name else "_" ^ name + +let osx_target_triple = "x86_64-apple-macosx10.13.0" + +let linux_target_triple = "x86_64-unknown-linux" + +let target_triple = ref osx_target_triple + +let platform_flags = ref "" + +(* Set the link commands properly, ensure output directory exists *) +let configure_os () = + if os = "Linux" + then ( + linux := true ; + target_triple := linux_target_triple ; + platform_flags := "" ) + else if os = "Darwin" + then ( + linux := false ; + target_triple := osx_target_triple ; + platform_flags := "-fno-asynchronous-unwind-tables -mstackrealign" ) + else failwith @@ "Unsupported OS detected: " ^ os + + +(* verbose compiler output -------------------------------------------------- *) +let verbose = ref false + +let verb msg = + if !verbose + then ( + print_string msg ; + flush Stdlib.stdout ) + + +let verb_os () = + verb + @@ Printf.sprintf + "* PLATFORM: %s TRIPLE: %s FLAGS %s\n" + os + !target_triple + !platform_flags + + +let enable_verbose () = + verbose := true ; + verb_os () + + +(* create the output directory, which is assumed to exist *) +let create_output_dir () = + try ignore (stat !output_path) with + | Unix_error (ENOENT, _, _) -> + verb @@ Printf.sprintf "creating output directory: %s\n" !output_path ; + mkdir !output_path 0o755 + + +(* clang invocation stuff --------------------------------------------------- *) +let common_flags = "-Wno-override-module" + +let link_flags = "-Wno-unused-command-line-argument -mstackrealign" + +let clang_ll_mode = "-S" + +let as_mode = "-c" + +let rosetta_prefix = "arch -x86_64 " + +let prefix = if cpu = "arm64" then rosetta_prefix else "" + +let opt_level = ref "-O1 -Wall" + +let clang args = Printf.sprintf "%sclang %s -o " prefix (String.concat " " args) + +let clang_cmd () = + clang [ clang_ll_mode; !opt_level; common_flags; !platform_flags ] + + +let as_cmd () = clang [ as_mode; !opt_level; common_flags; !platform_flags ] + +let link_cmd () = clang [ common_flags; !opt_level; !platform_flags; link_flags ] + +(* filename munging --------------------------------------------------------- *) +let path_to_basename_ext (path : string) : string * string = + (* The path is of the form ... "foo/bar/baz/.ext" *) + let paths = Str.split (Str.regexp_string path_sep) path in + let _ = + if List.length paths = 0 then failwith @@ sprintf "bad path: %s" path + in + let filename = List.hd (List.rev paths) in + match Str.split (Str.regexp_string ".") filename with + | [ root ] -> + (root, "") + | [ root; ext ] -> + (root, ext) + | _ -> + failwith @@ sprintf "bad filename: %s" filename + + +(* compilation and shell commands-------------------------------------------- *) + +(* Platform independent shell command *) +let sh (cmd : string) (ret : string -> int -> 'a) : 'a = + verb (sprintf "* %s\n" cmd) ; + match system cmd with + | WEXITED i -> + ret cmd i + | WSIGNALED i -> + raise (PlatformError (cmd, sprintf "Signaled with %d." i)) + | WSTOPPED i -> + raise (PlatformError (cmd, sprintf "Stopped with %d." i)) + +(* Platform independent shell command with a timeout (in seconds) *) +let timeout_sh (time: int)(cmd : string) (ret : string -> int -> 'a) : 'a = + let timeout_cmd = sprintf "%s/timeout3 -t %d %s" bin_path time cmd in + verb (sprintf "* %s\n" timeout_cmd) ; + match system timeout_cmd with + | WEXITED i -> + ret cmd i + | WSIGNALED i -> + if i == Sys.sigterm + then raise (PlatformError (cmd, sprintf "Timed-out after %d s" time)) + else raise (PlatformError (cmd, sprintf "Signaled with %d." i)) + | WSTOPPED i -> + raise (PlatformError (cmd, sprintf "Stopped with %d." i)) + + +(* Generate a file name that does not already exist. + basedir includes the path separator +*) +let gen_name (basedir : string) (basen : string) (baseext : string) : string = + let rec nocollide ofs = + let nfn = + sprintf + "%s/%s%s%s" + basedir + basen + (if ofs = 0 then "" else "_" ^ string_of_int ofs) + baseext + in + try + ignore (stat nfn) ; + nocollide (ofs + 1) + with + | Unix_error (ENOENT, _, _) -> + nfn + in + nocollide 0 + + +let raise_error cmd i = + if i <> 0 then raise (PlatformError (cmd, sprintf "Exited with status %d." i)) + + +let ignore_error _ _ = () + +let preprocess (dot_oat : string) (dot_i : string) : unit = + sh + (sprintf + "%s%s %s %s" + !pp_cmd + (List.fold_left (fun s i -> s ^ " -I" ^ i) "" !include_paths) + dot_oat + dot_i) + raise_error + + +let clang_compile (dot_ll : string) (dot_s : string) : unit = + sh (sprintf "%s%s %s" (clang_cmd ()) dot_s dot_ll) raise_error + + +let assemble (dot_s : string) (dot_o : string) : unit = + sh (sprintf "%s%s %s" (as_cmd ()) dot_o dot_s) raise_error + + +let link (mods : string list) (out_fn : string) : unit = + sh + (sprintf + "%s%s %s %s %s %s" + (link_cmd ()) + out_fn + (String.concat " " (mods @ !lib_paths)) + (List.fold_left (fun s i -> s ^ " -L" ^ i) "" !lib_search_paths) + (List.fold_left (fun s i -> s ^ " -I" ^ i) "" !include_paths) + (List.fold_left (fun s l -> s ^ " -l" ^ l) "" !libs)) + raise_error diff --git a/hw1/lib/util/range.ml b/hw1/lib/util/range.ml new file mode 100644 index 0000000..9a78d1a --- /dev/null +++ b/hw1/lib/util/range.ml @@ -0,0 +1,56 @@ +open Lexing + +type pos = int * int (* Line number and column *) + +type t = string * pos * pos + +let line_of_pos (l, _) = l + +let col_of_pos (_, c) = c + +let mk_pos line col = (line, col) + +let file_of_range (f, _, _) = f + +let start_of_range (_, s, _) = s + +let end_of_range (_, _, e) = e + +let mk_range f s e = (f, s, e) + +let valid_pos (l, c) = l >= 0 && c >= 0 + +let merge_range ((f, s1, e1) as r1) ((f', s2, e2) as r2) = + if f <> f' + then + failwith + @@ Printf.sprintf "merge_range called on different files: %s and %s" f f' + else if not (valid_pos s1) + then r2 + else if not (valid_pos s2) + then r1 + else mk_range f (min s1 s2) (max e1 e2) + + +let string_of_range (f, (sl, sc), (el, ec)) = + Printf.sprintf "%s:[%d.%d-%d.%d]" f sl sc el ec + + +let ml_string_of_range (f, (sl, sc), (el, ec)) = + Printf.sprintf "(\"%s\", (%d, %d), (%d, %d))" f sl sc el ec + + +let norange = ("__internal", (0, 0), (0, 0)) + +(* Creates a Range.pos from the Lexing.position data *) +let pos_of_lexpos (p : position) : pos = + mk_pos p.pos_lnum (p.pos_cnum - p.pos_bol) + + +let mk_lex_range (p1 : position) (p2 : position) : t = + mk_range p1.pos_fname (pos_of_lexpos p1) (pos_of_lexpos p2) + + +(* Expose the lexer state as a Range.t value *) +let lex_range lexbuf : t = + mk_lex_range (lexeme_start_p lexbuf) (lexeme_end_p lexbuf) diff --git a/hw1/lib/util/range.mli b/hw1/lib/util/range.mli new file mode 100644 index 0000000..9603713 --- /dev/null +++ b/hw1/lib/util/range.mli @@ -0,0 +1,53 @@ +(* Ranges and utilities on ranges. *) + +(* A range represents a segment of text in a given file; it has a + * beginning and ending position specified in terms of line and column + * numbers. A range is associated with tokens during lexing to allow + * the compiler to give better error messages during lexing and + * parsing. + *) + +(* a position in the source file; line number and column *) +type pos = int * int + +(* a range of positions in a particular file *) +type t = string * pos * pos + +(* line of position *) +val line_of_pos : pos -> int + +(* column of position *) +val col_of_pos : pos -> int + +(* new position with given line and col *) +val mk_pos : int -> int -> pos + +(* the filename a range is in *) +val file_of_range : t -> string + +(* the beginning of the range *) +val start_of_range : t -> pos + +(* the end of the range *) +val end_of_range : t -> pos + +(* create a new range from the given filename and start, end positions *) +val mk_range : string -> pos -> pos -> t + +(* merge two ranges together *) +val merge_range : t -> t -> t + +(* pretty-print a range *) +val string_of_range : t -> string + +(* print a range as an ocaml value *) +val ml_string_of_range : t -> string + +(* use to tag generated AST nodes where range does not apply *) +val norange : t + +val pos_of_lexpos : Lexing.position -> pos + +val mk_lex_range : Lexing.position -> Lexing.position -> t + +val lex_range : Lexing.lexbuf -> t diff --git a/hw1/submit_zip_contents.txt b/hw1/submit_zip_contents.txt new file mode 100644 index 0000000..1cd8c61 --- /dev/null +++ b/hw1/submit_zip_contents.txt @@ -0,0 +1,2 @@ +bin/hellocaml.ml +test/studenttests.ml diff --git a/hw1/test/dune b/hw1/test/dune new file mode 100644 index 0000000..29d8823 --- /dev/null +++ b/hw1/test/dune @@ -0,0 +1,11 @@ +(library + (name studenttests) + (modules studenttests) + (libraries util hellocaml)) + +(library + (name gradedtests) + (modules gradedtests) + (libraries util hellocaml)) + + diff --git a/hw1/test/gradedtests.ml b/hw1/test/gradedtests.ml new file mode 100644 index 0000000..17e64fb --- /dev/null +++ b/hw1/test/gradedtests.ml @@ -0,0 +1,187 @@ +open Util.Assert +open Hellocaml + +(* Test suite for hellocaml.ml *) + +(* Do NOT modify this file -- we will overwrite it with our *) +(* own version when we test your project. *) + +(* These tests will be used to grade your assignment *) + +(*** Part 1 Tests ***) +let part1_tests : suite = [ + + (* assert_eq asserts that the two values are equal *) + GradedTest ("Problem1-1", 3, [ + ("pieces", assert_eq pieces 8); + + (* assert_eqf f v + * asserts that applying a unit-accepting function f + * returns the value v *) + ("cube0", assert_eqf (fun () -> cube 0) 0); + ("cube1", assert_eqf (fun () -> cube 1) 1); + ("cube2", assert_eqf (fun () -> cube 2) 8); + ("cube3", assert_eqf (fun () -> cube (-1)) (-1)); + ]); + + + + GradedTest ("Problem1-2", 3, [ + ("cents_of1", assert_eqf (fun () -> cents_of 0 0 0 0) 0); + ("cents_of2", assert_eqf (fun () -> cents_of 1 1 1 1) 41); + ("cents_of3", assert_eqf (fun () -> cents_of 1 2 3 4) 64); + ("cents_of4", assert_eqf (fun () -> cents_of 1 0 0 0) 25); + ("cents_of5", assert_eqf (fun () -> cents_of 0 1 0 0) 10); + ("cents_of6", assert_eqf (fun () -> cents_of 0 0 1 0) 5); + ("cents_of7", assert_eqf (fun () -> cents_of 0 0 0 1) 1); + ]); + + GradedTest ("Problem1-3", 3, [ + + ]); +] + +(*** Part 2 Tests ***) +let part2_tests : suite = [ + GradedTest ("Problem2-1", 3, [ + ("third_of_three1", assert_eqf (fun () -> third_of_three triple) "some string"); + ("third_of_three2", assert_eqf (fun () -> third_of_three (1,2,3)) 3); + ("third_of_three3", assert_eqf (fun () -> third_of_three ((),"a",false)) false); + ]); + + GradedTest ("Problem2-1Manual", 3, [ + + ]); + + GradedTest ("Problem2-2", 5, + let id (x:int) : int = x in + let const3 (_:string) : int = 3 in [ + ("compose_pair1", assert_eqf (fun () -> compose_pair (id, const3) "a") 3); + ("compose_pair2", assert_eqf (fun () -> compose_pair (fst, pair_up) "a") "a"); + ("compose_pair3", assert_eqf (fun () -> compose_pair (double, fst) (pair_up 5)) 10); + ]); +] + +(*** Part 3 Tests ***) +let part3_tests : suite = [ + GradedTest ("Problem3-1", 5, [ + ("list_to_mylist1", assert_eqf (fun () -> list_to_mylist []) Nil); + ("list_to_mylist2", assert_eqf (fun () -> list_to_mylist [1]) (Cons(1,Nil))); + ("list_to_mylist3", assert_eqf (fun () -> list_to_mylist ["a";"b"]) (Cons("a",Cons("b",Nil)))); + ("list_to_mylist4", assert_eqf (fun () -> mylist_to_list (list_to_mylist [1;2;3;4;5])) [1;2;3;4;5]); + ]); + + GradedTest ("Problem3-2", 5, [ + ("append1", assert_eqf (fun () -> append [] []) []); + ("append2", assert_eqf (fun () -> append [] [1]) [1]); + ("append3", assert_eqf (fun () -> append [1] []) [1]); + ("append4", assert_eqf (fun () -> append [1] [1]) [1;1]); + ("append5", assert_eqf (fun () -> append [1;2] [3]) [1;2;3]); + ("append6", assert_eqf (fun () -> append [1] [2;3]) [1;2;3]); + ("append7", assert_eqf (fun () -> append [true] [false]) [true;false]); + ]); + + GradedTest ("Problem3-3", 5, [ + ("rev1", assert_eqf (fun () -> rev []) []); + ("rev2", assert_eqf (fun () -> rev [1]) [1]); + ("rev3", assert_eqf (fun () -> rev [1;2]) [2;1]); + ("rev4", assert_eqf (fun () -> rev ["a";"b"]) ["b";"a"]); + ("rev5", assert_eqf (fun () -> rev [1;2;3;4]) [4;3;2;1]); + ]); + + GradedTest ("Problem3-4", 5, [ + ("rev_t1", assert_eqf (fun () -> rev_t []) []); + ("rev_t2", assert_eqf (fun () -> rev_t [1]) [1]); + ("rev_t3", assert_eqf (fun () -> rev_t [1;2]) [2;1]); + ("rev_t4", assert_eqf (fun () -> rev_t ["a";"b"]) ["b";"a"]); + ("rev_t5", assert_eqf (fun () -> rev_t [1;2;3;4]) [4;3;2;1]); + ]); + + GradedTest ("Problem3-4Manual", 5, [ + + ]); + + GradedTest ("Problem3-5", 5, [ + ("insert1", assert_eqf (fun () -> insert 1 []) [1]); + ("insert2", assert_eqf (fun () -> insert 1 [1]) [1]); + ("insert3", assert_eqf (fun () -> insert 1 [2]) [1;2]); + ("insert4", assert_eqf (fun () -> insert 1 [0]) [0;1]); + ("insert5", assert_eqf (fun () -> insert 1 [0;2]) [0;1;2]); + ("insert6", assert_eqf (fun () -> insert "b" ["a";"c"]) ["a";"b";"c"]); + ]); + + GradedTest ("Problem3-6", 5, [ + ("union1", assert_eqf (fun () -> union [] []) []); + ("union2", assert_eqf (fun () -> union [1] []) [1]); + ("union3", assert_eqf (fun () -> union [] [1]) [1]); + ("union4", assert_eqf (fun () -> union [1] [1]) [1]); + ("union5", assert_eqf (fun () -> union [1] [2]) [1;2]); + ("union6", assert_eqf (fun () -> union [2] [1]) [1;2]); + ("union7", assert_eqf (fun () -> union [1;3] [0;2]) [0;1;2;3]); + ("union8", assert_eqf (fun () -> union [0;2] [1;3]) [0;1;2;3]); + ]); +] + + +(*** Part 4 Tests ***) + + + +let part4_tests : suite = [ + GradedTest ("Problem4-1", 5, [ + ("vars_of1", assert_eqf (fun () -> vars_of e1) []); + ("vars_of2", assert_eqf (fun () -> vars_of e2) ["x"]); + ("vars_of3", assert_eqf (fun () -> vars_of e3) ["x"; "y"]); + + ]); + + GradedTest ("Problem4-2", 5, [ + ("lookup1", assert_eqf (fun () -> lookup "x" ctxt1) 3L); + ("lookup2", assert_eqf (fun () -> lookup "x" ctxt2) 2L); + ("lookup3", assert_eqf (fun () -> lookup "y" ctxt2) 7L); + ("lookup4", (fun () -> try ignore (lookup "y" ctxt1); failwith "bad lookup" with Not_found -> ())); + ("lookup5", assert_eqf (fun () -> lookup "x" [("x", 1L);("x", 2L)]) 1L); + + ]); + + GradedTest ("Problem4-3", 5, [ + ("interpret1", assert_eqf (fun () -> interpret ctxt1 e1) 6L); + ("interpret2", assert_eqf (fun () -> interpret ctxt1 e2) 4L); + ("interpret3", (fun () -> try ignore (interpret ctxt1 e3); failwith "bad interpret" with Not_found -> ())); + ]); + + GradedTest ("Problem4-3harder", 5, [ + + ]); + + GradedTest ("Problem4-4", 5, [ + ("optimize1", assert_eqf (fun () -> optimize (Add(Const 3L, Const 4L))) (Const 7L)); + ("optimize2", assert_eqf (fun () -> optimize (Mult(Const 0L, Var "x"))) (Const 0L)); + ("optimize3", assert_eqf (fun () -> optimize (Add(Const 3L, Mult(Const 0L, Var "x")))) (Const 3L)); + ]); + + GradedTest ("Problem4-4harder", 5, [ + + ]); + + GradedTest ("Problem4-4hardest", 5, [ + + ]); + + GradedTest ("Problem5", 5, [ + + ]); +] + +let style_test : suite = [ + GradedTest ("StyleManual", 5, [ + + ]); +] + +let graded_tests : suite = + part1_tests @ + part2_tests @ + part3_tests @ + part4_tests @ + style_test diff --git a/hw1/test/studenttests.ml b/hw1/test/studenttests.ml new file mode 100644 index 0000000..31b1f80 --- /dev/null +++ b/hw1/test/studenttests.ml @@ -0,0 +1,16 @@ +open Util.Assert +open Hellocaml + +(* These tests are provided by you -- they will be graded manually *) + +(* You should also add additional test cases here to help you *) +(* debug your program. *) + +let student_tests : suite = [ + Test ("Student-Provided Tests For Problem 1-3", [ + ("case1", assert_eqf (fun () -> failwith "Problem 3 case1 test unimplemented") prob3_ans ); + ("case2", assert_eqf (fun () -> failwith "Problem 3 case2 test unimplemented") (prob3_case2 17) ); + ("case3", assert_eqf (fun () -> prob3_case3) 0); + ]); + +] diff --git a/hw2/.devcontainer/.zshrc b/hw2/.devcontainer/.zshrc new file mode 100644 index 0000000..d38a73f --- /dev/null +++ b/hw2/.devcontainer/.zshrc @@ -0,0 +1,13 @@ +autoload -U colors && colors +precmd() { + drawline="" + for i in {1..$COLUMNS}; drawline=" $drawline" + drawline="%U${drawline}%u" + PS1="%F{252}${drawline} +%B%F{124}%n:%~>%b%f " +} + +eval $(opam env) + +alias ls="ls --color" + diff --git a/hw2/.devcontainer/Dockerfile b/hw2/.devcontainer/Dockerfile new file mode 100644 index 0000000..f6b7689 --- /dev/null +++ b/hw2/.devcontainer/Dockerfile @@ -0,0 +1,73 @@ +FROM ubuntu:20.04 + +## BEGIN: RUNS AS ROOT + +# Create a user + +ARG USERNAME=cis3410 +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +ENV TZ='Asia/Shanghai' +# !!![zjy] apt change ustc source +RUN apt-get update -y\ + && apt-get install -y --no-install-recommends \ + apt-transport-https \ + ca-certificates \ + tzdata \ + && sed -i "s@http://.*.ubuntu.com@https://mirrors.ustc.edu.cn@g" /etc/apt/sources.list \ + && rm -rf /var/apt/cache/* + +RUN groupadd --gid $USER_GID $USERNAME \ + # + # [Optional] Add sudo support. Omit if you don't need to install software after connecting. + && apt-get update -y \ + && apt-get install -y sudo \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME + +## Hack needs root permissions + +# See hack.sh +COPY hack.sh /tmp/hack.sh +RUN chmod +x /tmp/hack.sh +RUN /tmp/hack.sh + +RUN apt-get update -y +RUN apt-get install -y build-essential +RUN apt-get install -y m4 +RUN apt-get install -y opam +RUN apt-get install -y clang +RUN apt-get install -y time +RUN apt-get install -y zip +# !!![zjy] install zsh first then set user +RUN apt-get install -y zsh + +# !!![zjy] install zsh first then set user +RUN useradd --uid $USER_UID --gid $USER_GID -m $USERNAME --shell /bin/zsh + +## Set up user environmnent +COPY .zshrc /home/$USERNAME/ +RUN chown $USERNAME /home/$USERNAME/.zshrc + +## Run in usermode + +# [Optional] Set the default user. Omit if you want to keep the default as root. +USER $USERNAME + +RUN mkdir -p /home/$USERNAME/.local/state/ +RUN touch /home/$USERNAME/.local/state/utop-history + +# Configure opam/ocaml +# !!![zjy] change default repo to github (SJTU repo is failed) +RUN opam init --yes --disable-sandboxing default https://github.com/ocaml/opam-repository.git +RUN opam switch create 4.14.1 ocaml-base-compiler.4.14.1 +RUN opam switch 4.14.1 +RUN opam install -y dune +RUN opam install -y num +RUN opam install -y menhir +RUN opam install -y utop +RUN opam install -y ocamlformat +RUN opam install -y ocaml-lsp-server +RUN eval `opam config env` + diff --git a/hw2/.devcontainer/devcontainer.json b/hw2/.devcontainer/devcontainer.json new file mode 100644 index 0000000..4561462 --- /dev/null +++ b/hw2/.devcontainer/devcontainer.json @@ -0,0 +1,31 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +{ + "name": "Ubuntu", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "build": { + "dockerfile": "Dockerfile" + }, + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "ocamllabs.ocaml-platform", + "allanblanchard.ocp-indent" + ] + } + } + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/hw2/.devcontainer/hack.sh b/hw2/.devcontainer/hack.sh new file mode 100644 index 0000000..b6d2c3f --- /dev/null +++ b/hw2/.devcontainer/hack.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +### HACK - workaround ubuntu libc6 version number bug see: https://forum.odroid.com/viewtopic.php?p=344373 + +mv /bin/uname /bin/uname.orig +tee -a /bin/uname < t + +val neg : int64 -> t +val succ : int64 -> t +val pred : int64 -> t + +val add : int64 -> int64 -> t +val sub : int64 -> int64 -> t +val mul : int64 -> int64 -> t \ No newline at end of file diff --git a/hw2/bin/main.ml b/hw2/bin/main.ml new file mode 100644 index 0000000..d6d63bb --- /dev/null +++ b/hw2/bin/main.ml @@ -0,0 +1,31 @@ +open Util.Assert +open Arg +open X86 +open Sim.Simulator + +exception Ran_tests +let worklist = ref [] + +let suite = ref (timeout_suite 5 (Studenttests.provided_tests @ Gradedtests.graded_tests)) + +let exec_tests () = + let o = run_suite !suite in + Printf.printf "%s\n" (outcome_to_string o); + raise Ran_tests + +let do_one_file fn = + let _ = Printf.printf "Processing: %s\n" fn in () + +(* Use the --test option to run unit tests and the quit the program. *) +let argspec = [ + ("--test", Unit exec_tests, "run the test suite, ignoring other inputs"); +] + +let _ = + try + Arg.parse argspec (fun f -> worklist := f :: !worklist) + "CIS341 main test harness \n"; + match !worklist with + | [] -> print_endline "* Nothing to do" + | _ -> List.iter do_one_file !worklist + with Ran_tests -> () diff --git a/hw2/bin/simulator.ml b/hw2/bin/simulator.ml new file mode 100644 index 0000000..b12b45b --- /dev/null +++ b/hw2/bin/simulator.ml @@ -0,0 +1,304 @@ +(* X86lite Simulator *) + +(* See the documentation in the X86lite specification, available on the + course web pages, for a detailed explanation of the instruction + semantics. +*) + +open X86 + +(* simulator machine state -------------------------------------------------- *) + +let mem_bot = 0x400000L (* lowest valid address *) +let mem_top = 0x410000L (* one past the last byte in memory *) +let mem_size = Int64.to_int (Int64.sub mem_top mem_bot) +let nregs = 17 (* including Rip *) +let ins_size = 8L (* assume we have a 8-byte encoding *) +let exit_addr = 0xfdeadL (* halt when m.regs(%rip) = exit_addr *) + +(* The simulator memory maps addresses to symbolic bytes. Symbolic + bytes are either actual data indicated by the Byte constructor or + 'symbolic instructions' that take up eight bytes for the purposes of + layout. + + The symbolic bytes abstract away from the details of how + instructions are represented in memory. Each instruction takes + exactly eight consecutive bytes, where the first byte InsB0 stores + the actual instruction, and the next sevent bytes are InsFrag + elements, which aren't valid data. + + For example, the two-instruction sequence: + at&t syntax ocaml syntax + movq %rdi, (%rsp) Movq, [~%Rdi; Ind2 Rsp] + decq %rdi Decq, [~%Rdi] + + is represented by the following elements of the mem array (starting + at address 0x400000): + + 0x400000 : InsB0 (Movq, [~%Rdi; Ind2 Rsp]) + 0x400001 : InsFrag + 0x400002 : InsFrag + 0x400003 : InsFrag + 0x400004 : InsFrag + 0x400005 : InsFrag + 0x400006 : InsFrag + 0x400007 : InsFrag + 0x400008 : InsB0 (Decq, [~%Rdi]) + 0x40000A : InsFrag + 0x40000B : InsFrag + 0x40000C : InsFrag + 0x40000D : InsFrag + 0x40000E : InsFrag + 0x40000F : InsFrag + 0x400010 : InsFrag +*) +type sbyte = InsB0 of ins (* 1st byte of an instruction *) + | InsFrag (* 2nd - 8th bytes of an instruction *) + | Byte of char (* non-instruction byte *) + +(* memory maps addresses to symbolic bytes *) +type mem = sbyte array + +(* Flags for condition codes *) +type flags = { mutable fo : bool + ; mutable fs : bool + ; mutable fz : bool + } + +(* Register files *) +type regs = int64 array + +(* Complete machine state *) +type mach = { flags : flags + ; regs : regs + ; mem : mem + } + +(* simulator helper functions ----------------------------------------------- *) + +(* The index of a register in the regs array *) +let rind : reg -> int = function + | Rip -> 16 + | Rax -> 0 | Rbx -> 1 | Rcx -> 2 | Rdx -> 3 + | Rsi -> 4 | Rdi -> 5 | Rbp -> 6 | Rsp -> 7 + | R08 -> 8 | R09 -> 9 | R10 -> 10 | R11 -> 11 + | R12 -> 12 | R13 -> 13 | R14 -> 14 | R15 -> 15 + +(* Helper functions for reading/writing sbytes *) + +(* Convert an int64 to its sbyte representation *) +let sbytes_of_int64 (i:int64) : sbyte list = + let open Char in + let open Int64 in + List.map (fun n -> Byte (shift_right i n |> logand 0xffL |> to_int |> chr)) + [0; 8; 16; 24; 32; 40; 48; 56] + +(* Convert an sbyte representation to an int64 *) +let int64_of_sbytes (bs:sbyte list) : int64 = + let open Char in + let open Int64 in + let f b i = match b with + | Byte c -> logor (shift_left i 8) (c |> code |> of_int) + | _ -> 0L + in + List.fold_right f bs 0L + +(* Convert a string to its sbyte representation *) +let sbytes_of_string (s:string) : sbyte list = + let rec loop acc = function + | i when i < 0 -> acc + | i -> loop (Byte s.[i]::acc) (pred i) + in + loop [Byte '\x00'] @@ String.length s - 1 + +(* Serialize an instruction to sbytes *) +let sbytes_of_ins (op, args:ins) : sbyte list = + let check = function + | Imm (Lbl _) | Ind1 (Lbl _) | Ind3 (Lbl _, _) -> + invalid_arg "sbytes_of_ins: tried to serialize a label!" + | _ -> () + in + List.iter check args; + [InsB0 (op, args); InsFrag; InsFrag; InsFrag; + InsFrag; InsFrag; InsFrag; InsFrag] + +(* Serialize a data element to sbytes *) +let sbytes_of_data : data -> sbyte list = function + | Quad (Lit i) -> sbytes_of_int64 i + | Asciz s -> sbytes_of_string s + | Quad (Lbl _) -> invalid_arg "sbytes_of_data: tried to serialize a label!" + + +(* It might be useful to toggle printing of intermediate states of your + simulator. Our implementation uses this mutable flag to turn on/off + printing. For instance, you might write something like: + + [if !debug_simulator then print_endline @@ string_of_ins u; ...] + +*) +let debug_simulator = ref false + + +(* override some useful operators *) +let ( +. ) = Int64.add +let ( -. ) = Int64.sub +let ( *. ) = Int64.mul +let ( <. ) a b = (Int64.compare a b) < 0 +let ( >. ) a b = (Int64.compare a b) > 0 +let ( <=. ) a b = (Int64.compare a b) <= 0 +let ( >=. ) a b = (Int64.compare a b) >= 0 + +(* Interpret a condition code with respect to the given flags. *) +(* !!! Check the Specification for Help *) +let interp_cnd {fo; fs; fz} : cnd -> bool = fun x -> failwith "interp_cnd unimplemented" + + +(* Maps an X86lite address into Some OCaml array index, + or None if the address is not within the legal address space. *) +let map_addr (addr:quad) : int option = + failwith "map_addr not implemented" + +(* Your simulator should raise this exception if it tries to read from or + store to an address not within the valid address space. *) +exception X86lite_segfault + +(* Raise X86lite_segfault when addr is invalid. *) +let map_addr_segfault (addr:quad) : int = + failwith "map_addr_segfault not implemented" + +(* Simulates one step of the machine: + - fetch the instruction at %rip + - compute the source and/or destination information from the operands + - simulate the instruction semantics + - update the registers and/or memory appropriately + - set the condition flags + + We provide the basic structure of step function and helper functions. + Implement the subroutine below to complete the step function. + See step function to understand each subroutine and how they + are glued together. +*) + +let readquad (m:mach) (addr:quad) : quad = + failwith "readquad not implemented" + + +let writequad (m:mach) (addr:quad) (w:quad) : unit = + failwith "writequad not implemented" + +let fetchins (m:mach) (addr:quad) : ins = + failwith "fetchins not implemented" + +(* Compute the instruction result. + * NOTE: See int64_overflow.ml for the definition of the return type +* Int64_overflow.t. *) +let interp_opcode (m: mach) (o:opcode) (args:int64 list) : Int64_overflow.t = + let open Int64 in + let open Int64_overflow in + match o, args with + | _ -> failwith "interp_opcode not implemented" + +(** Update machine state with instruction results. *) +let ins_writeback (m: mach) : ins -> int64 -> unit = + failwith "ins_writeback not implemented" + + +(* mem addr ---> mem array index *) +let interp_operands (m:mach) : ins -> int64 list = + failwith "interp_operands not implemented" + +let validate_operands : ins -> unit = function + | _ -> failwith "validate_operands not implemented" + + +let crack : ins -> ins list = function + | _ -> failwith "crack not implemented" + + +(* TODO: double check against spec *) +let set_flags (m:mach) (op:opcode) (ws: quad list) (w : Int64_overflow.t) : unit = + failwith "set_flags not implemented" + +let step (m:mach) : unit = + (* execute an instruction *) + let (op, args) as ins = fetchins m m.regs.(rind Rip) in + validate_operands ins; + + (* Some instructions involve running two or more basic instructions. + * For other instructions, just return a list of one instruction. + * See the X86lite specification for details. *) + let uops: ins list = crack (op,args) in + + m.regs.(rind Rip) <- m.regs.(rind Rip) +. ins_size; + + List.iter + (fun (uop,_ as u) -> + if !debug_simulator then print_endline @@ string_of_ins u; + let ws = interp_operands m u in + let res = interp_opcode m uop ws in + ins_writeback m u @@ res.Int64_overflow.value; + set_flags m op ws res + ) uops + +(* Runs the machine until the rip register reaches a designated + memory address. Returns the contents of %rax when the + machine halts. *) +let run (m:mach) : int64 = + while m.regs.(rind Rip) <> exit_addr do step m done; + m.regs.(rind Rax) + +(* assembling and linking --------------------------------------------------- *) + +(* A representation of the executable *) +type exec = { entry : quad (* address of the entry point *) + ; text_pos : quad (* starting address of the code *) + ; data_pos : quad (* starting address of the data *) + ; text_seg : sbyte list (* contents of the text segment *) + ; data_seg : sbyte list (* contents of the data segment *) + } + +(* Assemble should raise this when a label is used but not defined *) +exception Undefined_sym of lbl + +(* Assemble should raise this when a label is defined more than once *) +exception Redefined_sym of lbl + +(* Convert an X86 program into an object file: + - separate the text and data segments + - compute the size of each segment + Note: the size of an Asciz string section is (1 + the string length) + due to the null terminator + + - resolve the labels to concrete addresses and 'patch' the instructions to + replace Lbl values with the corresponding Imm values. + HINT: consider building a mapping from symboli Lbl to memory address + + - the text segment starts at the lowest address + - the data segment starts after the text segment + + HINT: List.fold_left and List.fold_right are your friends. + *) +let is_size (is: ins list): quad = + failwith "is_size not implemented" + +let ds_size (ds: data list): quad = + failwith "ds_size not implemented" + +let assemble (p:prog) : exec = + failwith "assemble unimplemented" + +(* Convert an object file into an executable machine state. + - allocate the mem array + - set up the memory state by writing the symbolic bytes to the + appropriate locations + - create the inital register state + - initialize rip to the entry point address + - initializes rsp to the last word in memory + - the other registers are initialized to 0 + - the condition code flags start as 'false' + + Hint: The Array.make, Array.blit, and Array.of_list library functions + may be of use. +*) +let load {entry; text_pos; data_pos; text_seg; data_seg} : mach = + failwith "load not implemented" \ No newline at end of file diff --git a/hw2/dune-project b/hw2/dune-project new file mode 100644 index 0000000..56d3ea5 --- /dev/null +++ b/hw2/dune-project @@ -0,0 +1,2 @@ +(lang dune 3.0) +(name hw2) diff --git a/hw2/hw2.opam b/hw2/hw2.opam new file mode 100755 index 0000000..e69de29 diff --git a/hw2/lib/util/assert.ml b/hw2/lib/util/assert.ml new file mode 100644 index 0000000..8e326a0 --- /dev/null +++ b/hw2/lib/util/assert.ml @@ -0,0 +1,195 @@ +(* CIS341 Assertion Testing and Grading Infrastructure *) +(* Author: Steve Zdancewic *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = unit -> unit + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = assertion test list + +(**************) +(* Assertions *) + +let assert_eq v1 v2 : assertion = + fun () -> if v1 <> v2 then failwith "not equal" else () + + +let assert_eqf f v2 : assertion = + fun () -> if f () <> v2 then failwith "not equal" else () + + +let assert_eqfs f v2 : assertion = + fun () -> + let s1 = f () in + if s1 <> v2 + then failwith @@ Printf.sprintf "not equal\n\texpected:%s\n\tgot:%s\n" v2 s1 + else () + + +let assert_fail : assertion = fun () -> failwith "assert fail" + +exception Timeout + +let timeout_assert (time : int) (a : assertion) : assertion = + fun () -> + let handler = Sys.Signal_handle (fun _ -> raise Timeout) in + let old = Sys.signal Sys.sigalrm handler in + let reset_sigalrm () = Sys.set_signal Sys.sigalrm old in + ignore (Unix.alarm time) ; + try + a () ; + reset_sigalrm () + with + | Timeout -> + reset_sigalrm () ; + failwith @@ Printf.sprintf "Timed out after %d seconds" time + | exc -> + reset_sigalrm () ; + raise exc + + +let timeout_test (time : int) (t : assertion test) : assertion test = + let map_timeout l = List.map (fun (i, a) -> (i, timeout_assert time a)) l in + match t with + | GradedTest (s, i, ls) -> + GradedTest (s, i, map_timeout ls) + | Test (s, ls) -> + Test (s, map_timeout ls) + + +let timeout_suite (time : int) (s : suite) : suite = + List.map (timeout_test time) s + + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = result test list + +let run_assertion (f : assertion) : result = + try + f () ; + Pass + with + | Failure m -> + Fail m + | e -> + Fail ("test threw exception: " ^ Printexc.to_string e) + + +let run_test (t : assertion test) : result test = + let run_case (cn, f) = (cn, run_assertion f) in + match t with + | GradedTest (n, s, cases) -> + Printf.eprintf "Running test %s\n%!" n ; + GradedTest (n, s, List.map run_case cases) + | Test (n, cases) -> + Printf.eprintf "Running test %s\n%!" n ; + Test (n, List.map run_case cases) + + +let run_suite (s : suite) : outcome = List.map run_test s + +(***********************) +(* Reporting functions *) + +let result_test_to_string (name_pts : string) (r : result test) : string = + let string_of_case (name, res) = + match res with + | Pass -> + "passed - " ^ name + | Fail msg -> + "FAILED - " ^ name ^ ": " ^ msg + in + match r with + | GradedTest (_, _, cases) | Test (_, cases) -> + name_pts + ^ List.fold_left + (fun rest case -> rest ^ "\n" ^ string_of_case case) + "" + cases + + +(* Number of digits of precision for a float x. Argument p is the number of decimal places desired (must be at least 1) *) +let prec_digits p x = (int_of_float @@ floor @@ log10 x) + (1 + p) + +(* returns (name_pts, passed, failed, total, points_earned, max_given, max_hidden) *) +let get_results (t : result test) = + let num_passed cases = + List.fold_left + (fun cnt (_, r) -> match r with Pass -> cnt + 1 | _ -> cnt) + 0 + cases + in + let num_failed cases = + List.fold_left + (fun cnt (_, r) -> match r with Fail _ -> cnt + 1 | _ -> cnt) + 0 + cases + in + match t with + | GradedTest (name, pts, cases) -> + let passed = num_passed cases in + let failed = num_failed cases in + let total = List.length cases in + if total > 0 + then + let points_earned = ((float_of_int passed) /. (float_of_int total)) *. (float_of_int pts) in + let name_pts = + Printf.sprintf "%s (%1.*g/%d points = %d/%d tests)" name (prec_digits 1 points_earned) points_earned pts passed total + in + (name_pts, passed, failed, total, points_earned, pts, 0) + else + let name_pts = Printf.sprintf "%s (?/%d points)" name pts in + (name_pts, passed, failed, total, 0.0, 0, pts) + | Test (name, cases) -> + let total = List.length cases in + let passed = num_passed cases in + let failed = num_failed cases in + (name, passed, failed, total, 0.0, 0, 0) + + +let outcome_to_string (o : outcome) : string = + let sep = "\n---------------------------------------------------\n" in + let helper (passed, failed, total, pts, maxg, maxh, str) (t : result test) = + let name_pts, p, f, tot, s, mg, mh = get_results t in + ( passed + p + , failed + f + , total + tot + , s +. pts + , maxg + mg + , maxh + mh + , str + ^ "\n" + ^ + if f > 0 + then result_test_to_string name_pts t + else if tot > 0 + then name_pts ^ ":\n OK" + else name_pts ^ ":\n Hidden" ) + in + let p, f, tot, pts, maxg, maxh, str = + List.fold_left helper (0, 0, 0, 0.0, 0, 0, "") o + in + str + ^ sep + ^ Printf.sprintf + "Passed: %d/%d\n\ + Failed: %d/%d\n\ + Score: %1.1f/%d (given)\n\ + \ ?/%d (hidden)" + p tot + f tot + pts maxg + maxh diff --git a/hw2/lib/util/assert.mli b/hw2/lib/util/assert.mli new file mode 100644 index 0000000..9dfa6d0 --- /dev/null +++ b/hw2/lib/util/assert.mli @@ -0,0 +1,57 @@ +(* CIS341 Assertion Testing and Grading Infrastructure *) +(* Author: Steve Zdancewic *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +exception Timeout + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = unit -> unit + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = assertion test list + +(**************) +(* Assertions *) + +val assert_eq : 'a -> 'a -> assertion + +val assert_eqf : (unit -> 'a) -> 'a -> assertion + +val assert_eqfs : (unit -> string) -> string -> assertion + +val assert_fail : assertion + +val timeout_assert : int -> assertion -> assertion + +val timeout_test : int -> assertion test -> assertion test + +val timeout_suite : int -> suite -> suite + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = result test list + +val run_assertion : assertion -> result + +val run_test : assertion test -> result test + +val run_suite : suite -> outcome + +(***********************) +(* Reporting functions *) + +val result_test_to_string : string -> result test -> string + +(* val get_results result test -> (string * int * int * int * float * int * int) *) +val outcome_to_string : outcome -> string diff --git a/hw2/lib/util/dune b/hw2/lib/util/dune new file mode 100644 index 0000000..aa0f522 --- /dev/null +++ b/hw2/lib/util/dune @@ -0,0 +1,3 @@ +(library + (name util) + (libraries str unix)) \ No newline at end of file diff --git a/hw2/lib/util/platform.ml b/hw2/lib/util/platform.ml new file mode 100644 index 0000000..13a96a0 --- /dev/null +++ b/hw2/lib/util/platform.ml @@ -0,0 +1,237 @@ +(* -------------------------------------------------------------------------- *) +(** Assembling and linking for X86. Depends on the underlying OS platform *) + +open Printf +open Unix + +exception PlatformError of string * string + +(* paths -------------------------------------------------------------------- *) +let path_sep = "/" + +let bin_path = "./bin" + +let dot_path = "./" + +let executable_name = ref "a.out" + +let output_path = ref "output" + +let libs = ref [] + +let lib_paths = ref [] + +let lib_search_paths = ref [] + +let include_paths = ref [] + +(* unix utility scripts ----------------------------------------------------- *) +let pp_cmd = ref "cpp -E " + +let rm_cmd = ref "rm -rf " + +(* -------------------------------------------------------------------------- *) +(* Platform specific configuration: Unix/Linux vs. Mac OS X *) + +let os = + let ic = Unix.open_process_in "uname -s" in + let uname = input_line ic in + let () = close_in ic in + uname + +let cpu = + let ic = Unix.open_process_in "uname -m" in + let cpuname = input_line ic in + let () = close_in ic in + cpuname + +(* One of "Darwin" or "Linux" *) + +let linux = ref false + +let mangle name = if !linux then name else "_" ^ name + +let osx_target_triple = "x86_64-apple-macosx10.13.0" + +let linux_target_triple = "x86_64-unknown-linux" + +let target_triple = ref osx_target_triple + +let platform_flags = ref "" + +(* Set the link commands properly, ensure output directory exists *) +let configure_os () = + if os = "Linux" + then ( + linux := true ; + target_triple := linux_target_triple ; + platform_flags := "" ) + else if os = "Darwin" + then ( + linux := false ; + target_triple := osx_target_triple ; + platform_flags := "-fno-asynchronous-unwind-tables -mstackrealign" ) + else failwith @@ "Unsupported OS detected: " ^ os + + +(* verbose compiler output -------------------------------------------------- *) +let verbose = ref false + +let verb msg = + if !verbose + then ( + print_string msg ; + flush Stdlib.stdout ) + + +let verb_os () = + verb + @@ Printf.sprintf + "* PLATFORM: %s TRIPLE: %s FLAGS %s\n" + os + !target_triple + !platform_flags + + +let enable_verbose () = + verbose := true ; + verb_os () + + +(* create the output directory, which is assumed to exist *) +let create_output_dir () = + try ignore (stat !output_path) with + | Unix_error (ENOENT, _, _) -> + verb @@ Printf.sprintf "creating output directory: %s\n" !output_path ; + mkdir !output_path 0o755 + + +(* clang invocation stuff --------------------------------------------------- *) +let common_flags = "-Wno-override-module" + +let link_flags = "-Wno-unused-command-line-argument -mstackrealign" + +let clang_ll_mode = "-S" + +let as_mode = "-c" + +let rosetta_prefix = "arch -x86_64 " + +let prefix = if cpu = "arm64" then rosetta_prefix else "" + +let opt_level = ref "-O1 -Wall" + +let clang args = Printf.sprintf "%sclang %s -o " prefix (String.concat " " args) + +let clang_cmd () = + clang [ clang_ll_mode; !opt_level; common_flags; !platform_flags ] + + +let as_cmd () = clang [ as_mode; !opt_level; common_flags; !platform_flags ] + +let link_cmd () = clang [ common_flags; !opt_level; !platform_flags; link_flags ] + +(* filename munging --------------------------------------------------------- *) +let path_to_basename_ext (path : string) : string * string = + (* The path is of the form ... "foo/bar/baz/.ext" *) + let paths = Str.split (Str.regexp_string path_sep) path in + let _ = + if List.length paths = 0 then failwith @@ sprintf "bad path: %s" path + in + let filename = List.hd (List.rev paths) in + match Str.split (Str.regexp_string ".") filename with + | [ root ] -> + (root, "") + | [ root; ext ] -> + (root, ext) + | _ -> + failwith @@ sprintf "bad filename: %s" filename + + +(* compilation and shell commands-------------------------------------------- *) + +(* Platform independent shell command *) +let sh (cmd : string) (ret : string -> int -> 'a) : 'a = + verb (sprintf "* %s\n" cmd) ; + match system cmd with + | WEXITED i -> + ret cmd i + | WSIGNALED i -> + raise (PlatformError (cmd, sprintf "Signaled with %d." i)) + | WSTOPPED i -> + raise (PlatformError (cmd, sprintf "Stopped with %d." i)) + +(* Platform independent shell command with a timeout (in seconds) *) +let timeout_sh (time: int)(cmd : string) (ret : string -> int -> 'a) : 'a = + let timeout_cmd = sprintf "%s/timeout3 -t %d %s" bin_path time cmd in + verb (sprintf "* %s\n" timeout_cmd) ; + match system timeout_cmd with + | WEXITED i -> + ret cmd i + | WSIGNALED i -> + if i == Sys.sigterm + then raise (PlatformError (cmd, sprintf "Timed-out after %d s" time)) + else raise (PlatformError (cmd, sprintf "Signaled with %d." i)) + | WSTOPPED i -> + raise (PlatformError (cmd, sprintf "Stopped with %d." i)) + + +(* Generate a file name that does not already exist. + basedir includes the path separator +*) +let gen_name (basedir : string) (basen : string) (baseext : string) : string = + let rec nocollide ofs = + let nfn = + sprintf + "%s/%s%s%s" + basedir + basen + (if ofs = 0 then "" else "_" ^ string_of_int ofs) + baseext + in + try + ignore (stat nfn) ; + nocollide (ofs + 1) + with + | Unix_error (ENOENT, _, _) -> + nfn + in + nocollide 0 + + +let raise_error cmd i = + if i <> 0 then raise (PlatformError (cmd, sprintf "Exited with status %d." i)) + + +let ignore_error _ _ = () + +let preprocess (dot_oat : string) (dot_i : string) : unit = + sh + (sprintf + "%s%s %s %s" + !pp_cmd + (List.fold_left (fun s i -> s ^ " -I" ^ i) "" !include_paths) + dot_oat + dot_i) + raise_error + + +let clang_compile (dot_ll : string) (dot_s : string) : unit = + sh (sprintf "%s%s %s" (clang_cmd ()) dot_s dot_ll) raise_error + + +let assemble (dot_s : string) (dot_o : string) : unit = + sh (sprintf "%s%s %s" (as_cmd ()) dot_o dot_s) raise_error + + +let link (mods : string list) (out_fn : string) : unit = + sh + (sprintf + "%s%s %s %s %s %s" + (link_cmd ()) + out_fn + (String.concat " " (mods @ !lib_paths)) + (List.fold_left (fun s i -> s ^ " -L" ^ i) "" !lib_search_paths) + (List.fold_left (fun s i -> s ^ " -I" ^ i) "" !include_paths) + (List.fold_left (fun s l -> s ^ " -l" ^ l) "" !libs)) + raise_error diff --git a/hw2/lib/util/range.ml b/hw2/lib/util/range.ml new file mode 100644 index 0000000..9a78d1a --- /dev/null +++ b/hw2/lib/util/range.ml @@ -0,0 +1,56 @@ +open Lexing + +type pos = int * int (* Line number and column *) + +type t = string * pos * pos + +let line_of_pos (l, _) = l + +let col_of_pos (_, c) = c + +let mk_pos line col = (line, col) + +let file_of_range (f, _, _) = f + +let start_of_range (_, s, _) = s + +let end_of_range (_, _, e) = e + +let mk_range f s e = (f, s, e) + +let valid_pos (l, c) = l >= 0 && c >= 0 + +let merge_range ((f, s1, e1) as r1) ((f', s2, e2) as r2) = + if f <> f' + then + failwith + @@ Printf.sprintf "merge_range called on different files: %s and %s" f f' + else if not (valid_pos s1) + then r2 + else if not (valid_pos s2) + then r1 + else mk_range f (min s1 s2) (max e1 e2) + + +let string_of_range (f, (sl, sc), (el, ec)) = + Printf.sprintf "%s:[%d.%d-%d.%d]" f sl sc el ec + + +let ml_string_of_range (f, (sl, sc), (el, ec)) = + Printf.sprintf "(\"%s\", (%d, %d), (%d, %d))" f sl sc el ec + + +let norange = ("__internal", (0, 0), (0, 0)) + +(* Creates a Range.pos from the Lexing.position data *) +let pos_of_lexpos (p : position) : pos = + mk_pos p.pos_lnum (p.pos_cnum - p.pos_bol) + + +let mk_lex_range (p1 : position) (p2 : position) : t = + mk_range p1.pos_fname (pos_of_lexpos p1) (pos_of_lexpos p2) + + +(* Expose the lexer state as a Range.t value *) +let lex_range lexbuf : t = + mk_lex_range (lexeme_start_p lexbuf) (lexeme_end_p lexbuf) diff --git a/hw2/lib/util/range.mli b/hw2/lib/util/range.mli new file mode 100644 index 0000000..9603713 --- /dev/null +++ b/hw2/lib/util/range.mli @@ -0,0 +1,53 @@ +(* Ranges and utilities on ranges. *) + +(* A range represents a segment of text in a given file; it has a + * beginning and ending position specified in terms of line and column + * numbers. A range is associated with tokens during lexing to allow + * the compiler to give better error messages during lexing and + * parsing. + *) + +(* a position in the source file; line number and column *) +type pos = int * int + +(* a range of positions in a particular file *) +type t = string * pos * pos + +(* line of position *) +val line_of_pos : pos -> int + +(* column of position *) +val col_of_pos : pos -> int + +(* new position with given line and col *) +val mk_pos : int -> int -> pos + +(* the filename a range is in *) +val file_of_range : t -> string + +(* the beginning of the range *) +val start_of_range : t -> pos + +(* the end of the range *) +val end_of_range : t -> pos + +(* create a new range from the given filename and start, end positions *) +val mk_range : string -> pos -> pos -> t + +(* merge two ranges together *) +val merge_range : t -> t -> t + +(* pretty-print a range *) +val string_of_range : t -> string + +(* print a range as an ocaml value *) +val ml_string_of_range : t -> string + +(* use to tag generated AST nodes where range does not apply *) +val norange : t + +val pos_of_lexpos : Lexing.position -> pos + +val mk_lex_range : Lexing.position -> Lexing.position -> t + +val lex_range : Lexing.lexbuf -> t diff --git a/hw2/lib/x86/dune b/hw2/lib/x86/dune new file mode 100644 index 0000000..abab108 --- /dev/null +++ b/hw2/lib/x86/dune @@ -0,0 +1,3 @@ +(library + (name x86) + (modules x86)) diff --git a/hw2/lib/x86/x86.ml b/hw2/lib/x86/x86.ml new file mode 100644 index 0000000..514a5c5 --- /dev/null +++ b/hw2/lib/x86/x86.ml @@ -0,0 +1,165 @@ +(* X86lite language representation. *) + +(* assembler syntax --------------------------------------------------------- *) + +(* Labels for code blocks and global data. *) +type lbl = string + +type quad = int64 + +(* Immediate operands *) +type imm = Lit of quad + | Lbl of lbl + +(* Registers: + instruction pointer: rip + arguments: rdi, rsi, rdx, rcx, r09, r08 + callee-save: rbx, rbp, r12-r15 +*) +type reg = Rip + | Rax | Rbx | Rcx | Rdx | Rsi | Rdi | Rbp | Rsp + | R08 | R09 | R10 | R11 | R12 | R13 | R14 | R15 + +type operand = Imm of imm (* immediate *) + | Reg of reg (* register *) + | Ind1 of imm (* indirect: displacement *) + | Ind2 of reg (* indirect: (%reg) *) + | Ind3 of (imm * reg) (* indirect: displacement(%reg) *) + +(* Condition Codes *) +type cnd = Eq | Neq | Gt | Ge | Lt | Le + +type opcode = Movq | Pushq | Popq + | Leaq + | Incq | Decq | Negq | Notq + | Addq | Subq | Imulq | Xorq | Orq | Andq + | Shlq | Sarq | Shrq + | Jmp | J of cnd + | Cmpq | Set of cnd + | Callq | Retq + +(* An instruction is an opcode plus its operands. + Note that arity and other constraints about the operands + are not checked. *) +type ins = opcode * operand list + +type data = Asciz of string + | Quad of imm + +type asm = Text of ins list (* code *) + | Data of data list (* data *) + +(* labeled blocks of data or code *) +type elem = { lbl: lbl; global: bool; asm: asm } + +type prog = elem list + +(* Provide some syntactic sugar for writing x86 code in OCaml files. *) +module Asm = struct + let (~$) i = Imm (Lit (Int64.of_int i)) (* int64 constants *) + let (~$$) l = Imm (Lbl l) (* label constants *) + let (~%) r = Reg r (* registers *) + + (* helper functions for building blocks of data or code *) + let data l ds = { lbl = l; global = true; asm = Data ds } + let text l is = { lbl = l; global = false; asm = Text is } + let gtext l is = { lbl = l; global = true; asm = Text is } +end + +(* pretty printing ----------------------------------------------------------- *) + +let string_of_reg : reg -> string = function + | Rip -> "%rip" + | Rax -> "%rax" | Rbx -> "%rbx" | Rcx -> "%rcx" | Rdx -> "%rdx" + | Rsi -> "%rsi" | Rdi -> "%rdi" | Rbp -> "%rbp" | Rsp -> "%rsp" + | R08 -> "%r8 " | R09 -> "%r9 " | R10 -> "%r10" | R11 -> "%r11" + | R12 -> "%r12" | R13 -> "%r13" | R14 -> "%r14" | R15 -> "%r15" + +let string_of_byte_reg : reg -> string = function + | Rip -> failwith "%rip used as byte register" + | Rax -> "%al" | Rbx -> "%bl" | Rcx -> "%cl" | Rdx -> "%dl" + | Rsi -> "%sil" | Rdi -> "%dil" | Rbp -> "%bpl" | Rsp -> "%spl" + | R08 -> "%r8b" | R09 -> "%r9b" | R10 -> "%r10b" | R11 -> "%r11b" + | R12 -> "%r12b" | R13 -> "%r13b" | R14 -> "%r14b" | R15 -> "%r15b" + +let string_of_lbl (l:lbl) : string = l + +let string_of_imm : imm -> string = function + | Lit i -> Int64.to_string i + | Lbl l -> string_of_lbl l + +let string_of_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_byte_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_byte_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_jmp_operand : operand -> string = function + | Imm i -> string_of_imm i + | Reg r -> "*" ^ string_of_reg r + | Ind1 i -> "*" ^ string_of_imm i + | Ind2 r -> "*" ^ "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> "*" ^ string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_cnd : cnd -> string = function + | Eq -> "e" | Neq -> "ne" | Gt -> "g" + | Ge -> "ge" | Lt -> "l" | Le -> "le" + +let string_of_opcode : opcode -> string = function + | Movq -> "movq" | Pushq -> "pushq" | Popq -> "popq" + | Leaq -> "leaq" + | Incq -> "incq" | Decq -> "decq" | Negq -> "negq" | Notq -> "notq" + | Addq -> "addq" | Subq -> "subq" | Imulq -> "imulq" + | Xorq -> "xorq" | Orq -> "orq" | Andq -> "andq" + | Shlq -> "shlq" | Sarq -> "sarq" | Shrq -> "shrq" + | Jmp -> "jmp" | J c -> "j" ^ string_of_cnd c + | Cmpq -> "cmpq" | Set c -> "set" ^ string_of_cnd c + | Callq -> "callq" | Retq -> "retq" + +let map_concat s f l = String.concat s @@ List.map f l + +let string_of_shift op = function + | [ Imm _i ; _dst ] as args -> + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " string_of_operand args + | [ Reg Rcx ; dst ] -> + Printf.sprintf "\t%s\t%%cl, %s" (string_of_opcode op) (string_of_operand dst) + | args -> failwith (Printf.sprintf "shift instruction has invalid operands: %s\n" + (map_concat ", " string_of_operand args)) + +let string_of_ins (op, args: ins) : string = + match op with + | Shlq | Sarq | Shrq -> string_of_shift op args + | _ -> + let f = match op with + | J _ | Jmp | Callq -> string_of_jmp_operand + | Set _ -> string_of_byte_operand + | _ -> string_of_operand + in + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " f args + +let string_of_data : data -> string = function + | Asciz s -> "\t.asciz\t" ^ "\"" ^ (String.escaped s) ^ "\"" + | Quad i -> "\t.quad\t" ^ string_of_imm i + +let string_of_asm : asm -> string = function + | Text is -> "\t.text\n" ^ map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n" ^ map_concat "\n" string_of_data ds + +let string_of_elem {lbl; global; asm} : string = + let sec, body = match asm with + | Text is -> "\t.text\n", map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n", map_concat "\n" string_of_data ds + in + let glb = if global then "\t.globl\t" ^ string_of_lbl lbl ^ "\n" else "" in + sec ^ glb ^ string_of_lbl lbl ^ ":\n" ^ body + +let string_of_prog (p:prog) : string = + String.concat "\n" @@ List.map string_of_elem p diff --git a/hw2/submit_zip_contents.txt b/hw2/submit_zip_contents.txt new file mode 100644 index 0000000..46eef0e --- /dev/null +++ b/hw2/submit_zip_contents.txt @@ -0,0 +1,2 @@ +bin/simulator.ml +test/studenttests.ml diff --git a/hw2/test/dune b/hw2/test/dune new file mode 100644 index 0000000..c398bf0 --- /dev/null +++ b/hw2/test/dune @@ -0,0 +1,17 @@ +(env + (dev + (flags + (:standard -g -w "+a-4-7-9-26-27-29-30-32..42-44-45-48-50-60-66..70")))) + +(library + (name studenttests) + (modules studenttests) + (libraries util sim x86 gradedtests)) + +(library + (name gradedtests) + (modules + gradedtests + ; project libraries + ) + (libraries util sim x86)) diff --git a/hw2/test/gradedtests.ml b/hw2/test/gradedtests.ml new file mode 100644 index 0000000..9f214a5 --- /dev/null +++ b/hw2/test/gradedtests.ml @@ -0,0 +1,655 @@ +open Util.Assert +open Sim.Simulator +open X86 +open Asm + +(* Test suite for asm.ml *) + +(* Do NOT modify this file -- we will overwrite it with our *) +(* own version when we test your project. *) + +(* These tests will be used to grade your assignment *) + +(* Example Programs *) + +let helloworld = [ text "foo" + [ Xorq, [~%Rax; ~%Rax] + ; Movq, [~$100; ~%Rax] + ; Retq, [] + ] + ; text "main" + [ Xorq, [~%Rax; ~%Rax] + ; Movq, [Ind1 (Lbl "baz"); ~%Rax] + ; Retq, [] + ] + ; data "baz" + [ Quad (Lit 99L) + ; Asciz "Hello, world!" + ] + ] + +let factorial_iter n = [ text "main" + [ Movq, [~$1; ~%Rax] + ; Movq, [~$n; ~%Rdi] + ] + ; text "loop" + [ Cmpq, [~$0; ~%Rdi] + ; J Eq, [~$$"exit"] + ; Imulq, [~%Rdi; ~%Rax] + ; Decq, [~%Rdi] + ; Jmp, [~$$"loop"] + ] + ; text "exit" + [ Retq, [] + ] + ] + +let factorial_rec n = [ text "fac" + [ Subq, [~$8; ~%Rsp] + ; Cmpq, [~$1; ~%Rdi] + ; J Le, [~$$"exit"] + ; Movq, [~%Rdi; Ind2 Rsp] + ; Decq, [~%Rdi] + ; Callq, [~$$"fac"] + ; Imulq, [Ind2 Rsp; ~%Rax] + ; Addq, [~$8; ~%Rsp] + ; Retq, [] + ] + ; text "exit" + [ Movq, [~$1; ~%Rax] + ; Addq, [~$8; ~%Rsp] + ; Retq, [] + ] + ; gtext "main" + [ Movq, [~$n; ~%Rdi] + ; Callq, [~$$"fac"] + ; Retq, [] + ] + ] + +(* Object Builders *) + +let sbyte_list (a: sbyte array) (start: int) : sbyte list = + Array.to_list (Array.sub a start 8) + +let stack_offset (i: quad) : operand = Ind3 (Lit i, Rsp) + +let test_exec: exec = + { entry = 0x400008L + ; text_pos = 0x400000L + ; data_pos = 0x400064L + ; text_seg = [] + ; data_seg = [] + } + + + +let test_machine (bs: sbyte list): mach = + let mem = (Array.make mem_size (Byte '\x00')) in + Array.blit (Array.of_list bs) 0 mem 0 (List.length bs); + let regs = Array.make nregs 0L in + regs.(rind Rip) <- mem_bot; + regs.(rind Rsp) <- Int64.sub mem_top 8L; + { flags = {fo = false; fs = false; fz = false}; + regs = regs; + mem = mem + } + +let helloworld_dataseg = + [ Byte 'c'; Byte '\x00'; Byte '\x00'; Byte '\x00' + ; Byte '\x00'; Byte '\x00'; Byte '\x00'; Byte '\x00' + ; Byte 'H'; Byte 'e' ; Byte 'l'; Byte 'l' + ; Byte 'o'; Byte ','; Byte ' '; Byte 'w' + ; Byte 'o'; Byte 'r'; Byte 'l'; Byte 'd' + ; Byte '!'; Byte '\x00' ] + +let helloworld_textseg = + [ InsB0 (Xorq, [Reg Rax; Reg Rax]); InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ; InsB0 (Movq, [Imm (Lit 100L); Reg Rax]); InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ; InsB0 (Retq, []); InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ; InsB0 (Xorq, [Reg Rax; Reg Rax]); InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ; InsB0 (Movq, [Ind1 (Lit 0x400030L); Reg Rax]); InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ; InsB0 (Retq, []); InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +(* Testing Functions *) + +let interp_cnd_test (fo, fs, fz) tru () = + let flags = {fo = fo; fs = fs; fz = fz} in + let all = [Eq;Neq;Gt;Ge;Lt;Le] in + let fls = List.filter (fun c -> not (List.mem c tru)) all in + let fn = interp_cnd flags in + let tru' = List.filter fn all in + let fls' = List.filter (fun c -> not (List.mem c tru')) all in + List.iter (fun c -> + if not (List.mem c tru) + then failwith (Printf.sprintf "o:%b s:%b f:%b %s expected" + fo fs fz (string_of_cnd c)) + else () + ) tru'; + List.iter (fun c -> + if not (List.mem c fls) + then failwith (Printf.sprintf "o:%b s:%b f:%b %s !expected" + fo fs fz (string_of_cnd c)) + else () + ) fls' + + + + +let cc_test (s:string) (n: int) (m: mach) (fo', fs', fz') (f: mach -> bool) () = + let m' = {m with flags = {fo=fo';fs=fs';fz=fz'}} in + for _ri=1 to n do step m' done; + if (f m') then () else failwith s + +let cs_test (n:int) (m:mach) (fo',fs',fz') = + cc_test (Printf.sprintf "expected OF:%b SF:%b ZF:%b" fo' fs' fz') + n m (not fo',not fs',not fz') + (fun m -> m.flags.fo = fo' && m.flags.fs = fs' && m.flags.fz = fz') + +let cso_test (n: int) (m:mach) (fo':bool) = + cc_test (Printf.sprintf "expected OF:%b" fo') n m (not fo',false,false) + (fun m -> m.flags.fo = fo') + +let csi_test (n: int) (m:mach) = + cc_test "expected TTT ccodes" n m (true,true,true) + (fun m -> m.flags.fo && m.flags.fs && m.flags.fz) + +let segfault_test addr () = + match map_addr addr with + | Some _ -> failwith "Should have raised X86_segmentation_fault" + | None -> () + +let undefinedsym_test (p:prog) () = + try ignore (assemble p); + failwith "Should have raised Undefined_sym" + with + | Undefined_sym _ -> () + | _ -> failwith "Should have raised Undefined_sym" + +let machine_test (s:string) (n: int) (m: mach) (f:mach -> bool) () = + for _i=1 to n do step m done; + if (f m) then () else failwith ("expected " ^ s) + +let program_test (p:prog) (ans:int64) () = + let res = assemble p |> load |> run in + if res <> ans + then failwith (Printf.sprintf("Expected %Ld but got %Ld") ans res) + else () + + +(* Tests *) + +let map_addr_tests = [ + ("map_addr1", assert_eqf (fun () -> (map_addr 0x40FFF8L)) (Some 65528)); + ("map_addr2", assert_eqf (fun () -> (map_addr 0x4000FFL)) (Some 255)); + ("map_addr3", assert_eqf (fun () -> (map_addr 0x400000L)) (Some 0)); + ("map_addr4", segfault_test 0x0000000000000000L); + ("map_addr5", segfault_test 0xFFFFFFFFFFFFFFFDL); + (* we expect your segfault function works correctly *) + ("map_addr_seg_error", assert_eqf (fun () -> try map_addr_segfault 0xFFFFFFFFFFFFFFFDL with X86lite_segfault -> 42;) 42); + ("map_addr_seg_valid", assert_eqf (fun () -> map_addr_segfault 0x40FFF8L) 65528) +] + +let read_write_quad_tests = + (* kkkk *) + let test_code = [ + InsB0 (Movq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] in + let m = test_machine test_code in + let test_addr = 0x40FFF8L in + [ + ("read_quad1", assert_eqf (fun () -> readquad m test_addr) (0L)); + ("read_write_quad", assert_eqf (fun ()-> + let _ = (writequad m test_addr 114514L) in + readquad m test_addr) (114514L)) +] + +let set_flags_tests = + (* see manual for more information *) + let test_code = [ + InsB0 (Movq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] in + let m = test_machine test_code in + let opcode = Sarq in + let oprands = [2L; 1L] in + [("set_flags", assert_eqf + (fun () -> let () = set_flags m opcode oprands {value=0L; overflow=false} in m.flags) + ({fo=false; fs=false; fz=true})) + ] + + + +let fetch_ins_tests = + let test_code = [ + InsB0 (Movq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] in + let m = test_machine test_code in + let rip : quad = m.regs.(rind Rip) in + let instr : ins = (Movq, [~$42; ~%Rax]) in + [ + ("fetch instruction", + assert_eqf (fun () -> fetchins m rip) instr) + ] + + +let interp_cnd_tests = [ + ("ccs_fff", interp_cnd_test (false,false,false) [Neq;Gt;Ge] ); + ("ccs_fft", interp_cnd_test (false,false,true) [Eq;Le;Ge] ); + ("ccs_ftf", interp_cnd_test (false,true,false) [Neq;Le;Lt] ); + ("ccs_ftt", interp_cnd_test (false,true,true) [Eq;Le;Lt] ); + ("ccs_tff", interp_cnd_test (true,false,false) [Neq;Le;Lt] ); + ("ccs_tft", interp_cnd_test (true,false,true) [Eq;Le;Lt] ); + ("ccs_ttf", interp_cnd_test (true,true,false) [Neq;Gt;Ge] ); + ("ccs_ttt", interp_cnd_test (true,true,true) [Eq;Le;Ge] ); +] + +let mov_ri = test_machine + [InsB0 (Movq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + + + +let add = test_machine + [InsB0 (Addq, [~$1; ~%Rax]) ;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Addq, [~%Rax; ~%Rbx]) ;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Addq, [~%Rbx; stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + + + +let hidden_functionality_tests = [ + +] + +let functionality_tests = [ + ("mov_ri", machine_test "rax=42" 1 mov_ri + (fun m -> m.regs.(rind Rax) = 42L) + ); + ("add", machine_test "rax=rbx=*66528=1" 3 add + (fun m -> m.regs.(rind Rax) = 1L + && m.regs.(rind Rbx) = 1L + && int64_of_sbytes (sbyte_list m.mem (mem_size-8)) = 1L + ) + ); +] + +let mov_mr = test_machine + [InsB0 (Movq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~%Rax; stack_offset (-8L)]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + + +let subq = test_machine + [InsB0 (Subq, [~$1; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Subq, [~%Rax; ~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Subq, [~%Rbx; stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let andq = test_machine + [InsB0 (Movq, [~$2; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$3; ~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$255; ~%Rcx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$1; stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Andq, [~%Rax; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Andq, [~$2; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Andq, [~%Rax; ~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Andq, [stack_offset 0L; ~%Rcx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + + +let negq = test_machine + [InsB0 (Movq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$(-24); stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [Imm (Lit Int64.min_int); ~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Negq, [~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Negq, [stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Negq, [~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + + +let shl = test_machine + [InsB0 (Movq, [~$1; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$2; stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$3; ~%Rcx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Shlq, [~$2; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Shlq, [~%Rcx; stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + + +let imul = test_machine + [InsB0 (Movq, [~$2; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$22; ~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Imulq, [~%Rbx; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let pushq = test_machine + [InsB0 (Pushq, [~$42]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let popq = test_machine + [InsB0 (Addq, [~$(-8); ~%Rsp]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$42; stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Popq, [~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let cmpq = test_machine + [InsB0 (Movq, [~$4; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$2; stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Cmpq, [~$1; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Cmpq, [~%Rax; ~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Cmpq, [~%Rbx; stack_offset 0L]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let hidden_instruction_tests = [ + +] + +let instruction_tests = [ + ("mov_mr", machine_test "*65520=42" 2 mov_mr + (fun m -> int64_of_sbytes (sbyte_list m.mem (mem_size-16)) = 42L) + ); + ("subq", machine_test "rax=*65528=-1L; rbx=1" 3 subq + (fun m -> m.regs.(rind Rax) = (Int64.neg 1L) + && m.regs.(rind Rbx) = 1L + && int64_of_sbytes (sbyte_list m.mem (mem_size-8)) = (Int64.neg 1L) + ) + ); + ("andq", machine_test "rax=2 rbx=2 rcx=1 *65528=1" 8 andq + (fun m -> m.regs.(rind Rax) = 2L + && m.regs.(rind Rbx) = 2L + && m.regs.(rind Rcx) = 1L + && int64_of_sbytes (sbyte_list m.mem (mem_size-8)) = 1L + ) + ); + ("negq", machine_test "rax=-42 rbx=min_int64 *65528=24" 6 negq + (fun m -> m.regs.(rind Rax) = Int64.neg 42L + && m.regs.(rind Rbx) = Int64.min_int + && int64_of_sbytes (sbyte_list m.mem (mem_size-8)) = 24L + ) + ); + ("shl", machine_test "rax=4 *65528=16" 5 shl + (fun m -> m.regs.(rind Rax) = 4L + && int64_of_sbytes (sbyte_list m.mem (mem_size-8)) = 16L + ) + ); + ("imul", machine_test "rax=44 *65528=2" 3 imul + (fun m -> m.regs.(rind Rax) = 44L) + ); + ("pushq", machine_test "rsp=4 *65520=2A" 1 pushq + (fun m -> m.regs.(rind Rsp) = 0x0040FFF0L + && int64_of_sbytes (sbyte_list m.mem (mem_size-16)) = 0x2AL + ) + ); + ("popq", machine_test "rsp=4259832 rax=2A" 3 popq + (fun m -> m.regs.(rind Rax) = 0x2AL + && m.regs.(rind Rsp) = 0x0040FFF8L + ) + ); + ("cmpq", machine_test "rax=4 rbx=0" 5 cmpq + (fun m -> m.regs.(rind Rax) = 4L + && m.regs.(rind Rbx) = 0L + && int64_of_sbytes (sbyte_list m.mem (mem_size-8)) = 2L + ) + ); +] + +let cc_add_1 = test_machine + [InsB0 (Movq, [Imm (Lit 0xFFFFFFFFFFFFFFFFL); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Addq, [~$1; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let cc_add_2 = test_machine + [InsB0 (Movq, [Imm (Lit 0xFFFFFFFFFFFFFFFFL); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Addq, [Imm (Lit 0xFFFFFFFFFFFFFFFFL); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let cc_add_3 = test_machine + [InsB0 (Movq, [Imm (Lit 0x7FFFFFFFFFFFFFFFL); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Addq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let cc_add_4 = test_machine + [InsB0 (Movq, [Imm (Lit 0x9000000000000000L); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Addq, [Imm (Lit 0xA000000000000000L); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + + ] + +let cc_neg_1 = test_machine + [InsB0 (Movq, [Imm (Lit Int64.min_int); ~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Negq, [~%Rbx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let cc_neg_2 = test_machine + [InsB0 (Movq, [~$1; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Negq, [~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + + +let cc_cmp_1 = test_machine + [InsB0 (Movq, [~$0; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Cmpq, [Imm (Lit 0x8000000000000000L); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let cc_cmp_2 = test_machine + [InsB0 (Movq, [Imm (Lit 0x8000000000000000L); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Cmpq, [~$0; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + + +let cc_imul_1 = test_machine + [InsB0 (Movq, [~$(-1); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Imulq, [~$(-1); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + + +let cc_and = test_machine + [InsB0 (Movq, [Imm (Lit 0x0F0F0F0FL); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Andq, [Imm (Lit 0xF0F0F0F0L); ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + +let cc_or = test_machine + [InsB0 (Movq, [~$0xFFFFFFF; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Orq, [~$0xF0F0F0F0; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] + + +let cc_set = test_machine + [InsB0 (Set Neq, [~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_push = test_machine + [InsB0 (Pushq, [~$0]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_pop = test_machine + [InsB0 (Popq, [~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_ret = test_machine + [InsB0 (Retq, []);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_mov = test_machine + [InsB0 (Movq, [~$0; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_jmp = test_machine + [InsB0 (Jmp, [~$0x400008]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_js = test_machine + [InsB0 (J Neq, [~$0x400008]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_jf = test_machine + [InsB0 (J Eq, [~$0x400008]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_call = test_machine + [InsB0 (Callq, [~$0x400008]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + +let cc_lea = test_machine + [InsB0 (Movq, [~$0x400600; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~$0x408000; ~%Rcx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Leaq, [Ind2 Rax; ~%R08]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ;InsB0 (Movq, [~%R08; Ind2 Rcx]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag] + + + +let hidden_condition_flag_set_tests = [ + +] + +let condition_flag_set_tests = + [ ("cc_add_1", cs_test 2 cc_add_1 (false, false, true)) + ; ("cc_add_2", cs_test 2 cc_add_2 (false, true, false)) + ; ("cc_add_3", cs_test 2 cc_add_3 (true, true, false)) + ; ("cc_add_4", cs_test 2 cc_add_4 (true, false, false)) + ; ("cc_neg_1", cs_test 2 cc_neg_1 (true, true, false)) + ; ("cc_neg_2", cs_test 2 cc_neg_2 (false, true, false)) + ; ("cc_cmp_1", cs_test 2 cc_cmp_1 (true, true, false)) + ; ("cc_cmp_2", cs_test 2 cc_cmp_2 (false, true, false)) + ; ("cc_imul_1", cso_test 2 cc_imul_1 false) + ; ("cc_and", cs_test 2 cc_and (false, false, true)) + ; ("cc_or", cs_test 2 cc_or (false, false, false)) + ; ("cc_push", csi_test 1 cc_push) + ; ("cc_pop", csi_test 1 cc_pop) + ; ("cc_set", csi_test 1 cc_set) + ; ("cc_ret", csi_test 1 cc_ret) + ; ("cc_mov", csi_test 1 cc_mov) + ; ("cc_jmp", csi_test 1 cc_jmp) + ; ("cc_jmp", csi_test 1 cc_js) + ; ("cc_jmp", csi_test 1 cc_jf) + ; ("cc_call", csi_test 1 cc_call) + ; ("cc_lea", csi_test 3 cc_lea) + ] + + +let interpret_opcode_tests = + (* kkkk *) + let open Int64 in + let open Sim.Simulator in + let open Sim.Int64_overflow in + let test_code = [ + InsB0 (Movq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] in + let m = test_machine test_code in + let opcode, args = (Movq, [~$42; ~%Rax]) in + let expected_state = ok 42L in + + [ + ("intepret_opcode", assert_eqf (fun()-> + let ws = interp_operands m (opcode, args) in + interp_opcode m opcode ws) expected_state); + ] + + +let crack_tests = + let open Asm in + let i = (Pushq, [~$42]) in + [ + ("crack_pushq", assert_eqf (fun() -> + crack i) ([ Subq, [Imm (Lit 8L); Reg Rsp] + ; Movq, [~$42; Ind2 Rsp] ])) + ;] + + +(* Test Suites *) + +let ins_writeback_tests = + let test_code = [ + InsB0 (Movq, [~$42; ~%Rax]);InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag;InsFrag + ] in + let m = test_machine test_code in + [ + ("instruction write back unit", assert_eqf + (fun () -> + let closure = ins_writeback m (Movq, [~$45; ~%Rax]) in + closure 99L; m.regs.(rind Rax)) + 99L) + ] + + let load_chunk_size_tests= + let inss = [ + (Movq, [~$42; ~%Rax]); + (Movq, [~$43; ~%Rbx]); + (Movq, [~$44; ~%Rcx]); + (Movq, [~$45; ~%Rdx])] in + + let data = [ + Quad (Lit 99L) + ; Asciz "Hello, world!" + ] in + [ + ("ins size", assert_eqf (fun () -> is_size(inss)) 32L); + ("data size", assert_eqf (fun () -> ds_size(data)) 22L) + ] + + +let easy_tests : suite = +[ + GradedTest("Map AddressesUnit", 1, map_addr_tests); + GradedTest("Read Write Quad Unit", 1, read_write_quad_tests); + + GradedTest("Condition Codes Unit", 1, interp_cnd_tests); + GradedTest("Fetch Instructions Unit", 1, fetch_ins_tests); + GradedTest("Interpret Opcode Unit", 1, interpret_opcode_tests); + GradedTest("Crack Ops Unit", 1, crack_tests); + GradedTest("Set Flag Unit", 1, set_flags_tests); + GradedTest("Ins Write Back Unit", 1, ins_writeback_tests); + + + GradedTest("Data Chunk Size Unit", 2, load_chunk_size_tests); + GradedTest("Easy Assemble Tests", 2, [ + ("assemble1", assert_eqf (fun () -> (assemble helloworld).text_pos) 0x400000L ); + ("assemble2", assert_eqf (fun () -> (assemble helloworld).data_pos) 0x400030L ); + ]); + + + + GradedTest("Easy Load Tests", 3, [ + ("load_flags", assert_eqf (fun () -> (load test_exec).flags) + {fo = false; fs = false; fz = false}); + ("load_rip", assert_eqf (fun () -> (load test_exec).regs.(rind Rip)) + 0x400008L); + ("load_rsp", assert_eqf (fun () -> (load test_exec).regs.(rind Rsp)) + 0x40FFF8L); + ]); +] + +let medium_tests : suite = [ + GradedTest("Medium Assemble Tests", 5,[ + ("assemble1", assert_eqf (fun () -> (assemble helloworld).text_seg) helloworld_textseg ); + ("assemble2", undefinedsym_test [text "foo" [Retq,[]]]); + ("assemble3", assert_eqf (fun () -> (assemble helloworld).data_seg) helloworld_dataseg ); + ("assemble4", undefinedsym_test [text "main" [Jmp,[~$$"loop"];Retq,[]]]); + ]); + GradedTest("Medium Load Tests", 5,[ + ("load_exit_addr", assert_eqf (fun () -> + let m = load test_exec in + int64_of_sbytes (sbyte_list m.mem 0x0fff8) + ) exit_addr); + ]); + GradedTest("Functionality Tests", 3, functionality_tests); + GradedTest("Hidden Functionality Tests", 2, hidden_functionality_tests); + GradedTest("Instruction Tests", 5, instruction_tests); + GradedTest("Hidden Instruction Tests", 5, hidden_instruction_tests); + GradedTest("Condition Flag Set Tests", 3, condition_flag_set_tests); + GradedTest("Hidden Condition Flag Set Tests", 2, hidden_condition_flag_set_tests); +] + +let hard_tests : suite = [ + GradedTest ("End-to-end Factorial", 10, [ + ("fact6", program_test (factorial_rec 6) 720L); + ]); + GradedTest ("Hidden End-to-end Hard", 20, + [] + )] + +let manual_tests : suite = [ + GradedTest ("PartIIITestCase (manual)", 10, [ + + ]); + GradedTest ("Other Team Tests (manual)", 10, + [] + ); + GradedTest ("Style (manual)", 5, [ + + ]); +] + +let graded_tests : suite = + timeout_suite 3 ( + easy_tests @ + medium_tests @ + hard_tests @ + manual_tests) diff --git a/hw2/test/studenttests.ml b/hw2/test/studenttests.ml new file mode 100644 index 0000000..bf9e221 --- /dev/null +++ b/hw2/test/studenttests.ml @@ -0,0 +1,57 @@ +open Util.Assert +open X86 +open Sim.Simulator +open Gradedtests +open Asm +(* These tests are provided by you -- they will be graded manually *) + +(* You should also add additional test cases here to help you *) +(* debug your program. *) + + +let test_my = + let bin = [ + InsB0 (Movq, Asm.[ ~$42; ~%Rax ]); + InsFrag; + InsFrag; + InsFrag; + InsFrag; + InsFrag; + InsFrag; + InsFrag; + ] + + in + + let asm = [gtext "main" + [ + Movq, [~$42; ~%Rax]]; + ] in + + (assert_eqf (fun() -> (assemble asm).text_seg) bin ) + + +let mov_ri = + test_machine + [ + InsB0 (Movq, Asm.[ ~$42; ~%Rax ]); + InsFrag; + InsFrag; + InsFrag; + InsFrag; + InsFrag; + InsFrag; + InsFrag; + ] + +let provided_tests : suite = [ + + Test ("My Tests", [ + ("assert", test_my) + ]); + + Test ("Student-Provided Big Test for Part III: Score recorded as PartIIITestCase", [ + + ]); + +] diff --git a/hw3/Makefile b/hw3/Makefile new file mode 100644 index 0000000..7e30842 --- /dev/null +++ b/hw3/Makefile @@ -0,0 +1,22 @@ +all: main.native + +.PHONY: test +test: main.native + ./main.native --test + +main.native: + ocamlbuild -Is util,x86,ll,grading -libs unix,str,nums main.native -use-menhir + +main.byte: + ocamlbuild -Is util,x86,ll,grading -libs unix,str,nums main.byte -use-menhir + +.PHONY: utop repl +utop: main.byte + utop -require unix,str,num + +repl: utop + +.PHONY: clean +clean: + ocamlbuild -clean + rm -rf output a.out diff --git a/hw3/README b/hw3/README new file mode 100644 index 0000000..0ad0ac0 --- /dev/null +++ b/hw3/README @@ -0,0 +1,76 @@ +Using main.native: + +main.native acts like the clang compiler. Given several .ll, .c, and .o files, +it will compile the .ll files to .s files (using the compilerdesign backend) and then combine +the results with the .c and .o files to produce an executable named a.out. You can +also compile the .ll files using clang instead of the compilerdesign backend, which can +be useful for testing purposes. + + +* To run the automated test harness do: + ./main.native --test + +* To compile ll files using the compilerdesign backend: + ./main.native path/to/foo.ll + + - creates output/foo.s backend assembly code + - creates output/foo.o assembled object file + - creates a.out linked executable + + NOTE: by default the .s and .o files are created in + a directory called output, and the filenames are + chosen so that multiple runs of the compiler will + not overwrite previous outputs. foo.ll will be + compiled first to foo.s then foo_1.s, foo_2.s, etc. + + +* To compile ll files using the clang backend: + ./main.native --clang path/to/foo.ll + +* Useful flags: + + --print-ll + echoes the ll program to the terminal + + --print-x86 + echoes the resulting .s file to the terminal + + --interpret-ll + runs the ll file through the reference interpreter + and outputs the results to the console + + --simulate-x86 + runs the resulting .s file through the reference + x86 simulator and outputs the result to the console + + --execute-x86 + runs the resulting a.out file natively + (applies to either the compilerdesign backend or clang-compiled code) + + -v + generates verbose output, showing which commands are used + for linking, etc. + + -op + change the output path [DEFAULT=output] + + -o + change the generated executable's name [DEFAULT=a.out] + + -S + stop after generating .s files + + -c + stop after generating .o files + + -h or --help + display the list of options + +* Example uses: + +Run the test case /programs/factrect.ll using the compilerdesign backend: + + +./main.native --execute-x86 programs/factrect.ll +--------------------------------------------------------------- Executing: a.out +* a.out returned 120 diff --git a/hw3/backend.ml b/hw3/backend.ml new file mode 100644 index 0000000..fda53eb --- /dev/null +++ b/hw3/backend.ml @@ -0,0 +1,309 @@ +(* ll ir compilation -------------------------------------------------------- *) + +open Ll +open X86 + +(* Overview ----------------------------------------------------------------- *) + +(* We suggest that you spend some time understanding this entire file and + how it fits with the compiler pipeline before making changes. The suggested + plan for implementing the compiler is provided on the project web page. +*) + + +(* helpers ------------------------------------------------------------------ *) + +(* Map LL comparison operations to X86 condition codes *) +let compile_cnd = function + | Ll.Eq -> X86.Eq + | Ll.Ne -> X86.Neq + | Ll.Slt -> X86.Lt + | Ll.Sle -> X86.Le + | Ll.Sgt -> X86.Gt + | Ll.Sge -> X86.Ge + + + +(* locals and layout -------------------------------------------------------- *) + +(* One key problem in compiling the LLVM IR is how to map its local + identifiers to X86 abstractions. For the best performance, one + would want to use an X86 register for each LLVM %uid. However, + since there are an unlimited number of %uids and only 16 registers, + doing so effectively is quite difficult. We will see later in the + course how _register allocation_ algorithms can do a good job at + this. + + A simpler, but less performant, implementation is to map each %uid + in the LLVM source to a _stack slot_ (i.e. a region of memory in + the stack). Since LLVMlite, unlike real LLVM, permits %uid locals + to store only 64-bit data, each stack slot is an 8-byte value. + + [ NOTE: For compiling LLVMlite, even i1 data values should be + represented as a 8-byte quad. This greatly simplifies code + generation. ] + + We call the datastructure that maps each %uid to its stack slot a + 'stack layout'. A stack layout maps a uid to an X86 operand for + accessing its contents. For this compilation strategy, the operand + is always an offset from %rbp (in bytes) that represents a storage slot in + the stack. +*) + +type layout = (uid * X86.operand) list + +(* A context contains the global type declarations (needed for getelementptr + calculations) and a stack layout. *) +type ctxt = { tdecls : (tid * ty) list + ; layout : layout + } + +(* useful for looking up items in tdecls or layouts *) +let lookup m x = List.assoc x m + + +(* compiling operands ------------------------------------------------------ *) + +(* LLVM IR instructions support several kinds of operands. + + LL local %uids live in stack slots, whereas global ids live at + global addresses that must be computed from a label. Constants are + immediately available, and the operand Null is the 64-bit 0 value. + + NOTE: two important facts about global identifiers: + + (1) You should use (Platform.mangle gid) to obtain a string + suitable for naming a global label on your platform (OS X expects + "_main" while linux expects "main"). + + (2) 64-bit assembly labels are not allowed as immediate operands. + That is, the X86 code: movq _gid %rax which looks like it should + put the address denoted by _gid into %rax is not allowed. + Instead, you need to compute an %rip-relative address using the + leaq instruction: leaq _gid(%rip). + + One strategy for compiling instruction operands is to use a + designated register (or registers) for holding the values being + manipulated by the LLVM IR instruction. You might find it useful to + implement the following helper function, whose job is to generate + the X86 instruction that moves an LLVM operand into a designated + destination (usually a register). +*) +let compile_operand (ctxt:ctxt) (dest:X86.operand) : Ll.operand -> ins = + function _ -> failwith "compile_operand unimplemented" + + + +(* compiling call ---------------------------------------------------------- *) + +(* You will probably find it helpful to implement a helper function that + generates code for the LLVM IR call instruction. + + The code you generate should follow the x64 System V AMD64 ABI + calling conventions, which places the first six 64-bit (or smaller) + values in registers and pushes the rest onto the stack. Note that, + since all LLVM IR operands are 64-bit values, the first six + operands will always be placed in registers. (See the notes about + compiling fdecl below.) + + [ NOTE: It is the caller's responsibility to clean up arguments + pushed onto the stack, so you must free the stack space after the + call returns. ] + + [ NOTE: Don't forget to preserve caller-save registers (only if + needed). ] +*) + + + + +(* compiling getelementptr (gep) ------------------------------------------- *) + +(* The getelementptr instruction computes an address by indexing into + a datastructure, following a path of offsets. It computes the + address based on the size of the data, which is dictated by the + data's type. + + To compile getelementptr, you must generate x86 code that performs + the appropriate arithmetic calculations. +*) + +(* [size_ty] maps an LLVMlite type to a size in bytes. + (needed for getelementptr) + + - the size of a struct is the sum of the sizes of each component + - the size of an array of t's with n elements is n * the size of t + - all pointers, I1, and I64 are 8 bytes + - the size of a named type is the size of its definition + + - Void, i8, and functions have undefined sizes according to LLVMlite. + Your function should simply return 0 in those cases +*) +let rec size_ty (tdecls:(tid * ty) list) (t:Ll.ty) : int = +failwith "size_ty not implemented" + + + + +(* Generates code that computes a pointer value. + + 1. op must be of pointer type: t* + + 2. the value of op is the base address of the calculation + + 3. the first index in the path is treated as the index into an array + of elements of type t located at the base address + + 4. subsequent indices are interpreted according to the type t: + + - if t is a struct, the index must be a constant n and it + picks out the n'th element of the struct. [ NOTE: the offset + within the struct of the n'th element is determined by the + sizes of the types of the previous elements ] + + - if t is an array, the index can be any operand, and its + value determines the offset within the array. + + - if t is any other type, the path is invalid + + 5. if the index is valid, the remainder of the path is computed as + in (4), but relative to the type f the sub-element picked out + by the path so far +*) +let compile_gep (ctxt:ctxt) (op : Ll.ty * Ll.operand) (path: Ll.operand list) : ins list = +failwith "compile_gep not implemented" + + + +(* compiling instructions -------------------------------------------------- *) + +(* The result of compiling a single LLVM instruction might be many x86 + instructions. We have not determined the structure of this code + for you. Some of the instructions require only a couple of assembly + instructions, while others require more. We have suggested that + you need at least compile_operand, compile_call, and compile_gep + helpers; you may introduce more as you see fit. + + Here are a few notes: + + - Icmp: the Setb instruction may be of use. Depending on how you + compile Cbr, you may want to ensure that the value produced by + Icmp is exactly 0 or 1. + + - Load & Store: these need to dereference the pointers. Const and + Null operands aren't valid pointers. Don't forget to + Platform.mangle the global identifier. + + - Alloca: needs to return a pointer into the stack + + - Bitcast: does nothing interesting at the assembly level +*) +let compile_insn (ctxt:ctxt) ((uid:uid), (i:Ll.insn)) : X86.ins list = + failwith "compile_insn not implemented" + + + +(* compiling terminators --------------------------------------------------- *) + +(* prefix the function name [fn] to a label to ensure that the X86 labels are + globally unique . *) +let mk_lbl (fn:string) (l:string) = fn ^ "." ^ l + +(* Compile block terminators is not too difficult: + + - Ret should properly exit the function: freeing stack space, + restoring the value of %rbp, and putting the return value (if + any) in %rax. + + - Br should jump + + - Cbr branch should treat its operand as a boolean conditional + + [fn] - the name of the function containing this terminator +*) +let compile_terminator (fn:string) (ctxt:ctxt) (t:Ll.terminator) : ins list = + failwith "compile_terminator not implemented" + + +(* compiling blocks --------------------------------------------------------- *) + +(* We have left this helper function here for you to complete. + [fn] - the name of the function containing this block + [ctxt] - the current context + [blk] - LLVM IR code for the block +*) +let compile_block (fn:string) (ctxt:ctxt) (blk:Ll.block) : ins list = + failwith "compile_block not implemented" + +let compile_lbl_block fn lbl ctxt blk : elem = + Asm.text (mk_lbl fn lbl) (compile_block fn ctxt blk) + + + +(* compile_fdecl ------------------------------------------------------------ *) + + +(* This helper function computes the location of the nth incoming + function argument: either in a register or relative to %rbp, + according to the calling conventions. You might find it useful for + compile_fdecl. + + [ NOTE: the first six arguments are numbered 0 .. 5 ] +*) +let arg_loc (n : int) : operand = +failwith "arg_loc not implemented" + + +(* We suggest that you create a helper function that computes the + stack layout for a given function declaration. + + - each function argument should be copied into a stack slot + - in this (inefficient) compilation strategy, each local id + is also stored as a stack slot. + - see the discussion about locals + +*) +let stack_layout (args : uid list) ((block, lbled_blocks):cfg) : layout = +failwith "stack_layout not implemented" + +(* The code for the entry-point of a function must do several things: + + - since our simple compiler maps local %uids to stack slots, + compiling the control-flow-graph body of an fdecl requires us to + compute the layout (see the discussion of locals and layout) + + - the function code should also comply with the calling + conventions, typically by moving arguments out of the parameter + registers (or stack slots) into local storage space. For our + simple compilation strategy, that local storage space should be + in the stack. (So the function parameters can also be accounted + for in the layout.) + + - the function entry code should allocate the stack storage needed + to hold all of the local stack slots. +*) +let compile_fdecl (tdecls:(tid * ty) list) (name:string) ({ f_ty; f_param; f_cfg }:fdecl) : prog = +failwith "compile_fdecl unimplemented" + + + +(* compile_gdecl ------------------------------------------------------------ *) +(* Compile a global value into an X86 global data declaration and map + a global uid to its associated X86 label. +*) +let rec compile_ginit : ginit -> X86.data list = function + | GNull -> [Quad (Lit 0L)] + | GGid gid -> [Quad (Lbl (Platform.mangle gid))] + | GInt c -> [Quad (Lit c)] + | GString s -> [Asciz s] + | GArray gs | GStruct gs -> List.map compile_gdecl gs |> List.flatten + | GBitcast (t1,g,t2) -> compile_ginit g + +and compile_gdecl (_, g) = compile_ginit g + + +(* compile_prog ------------------------------------------------------------- *) +let compile_prog {tdecls; gdecls; fdecls} : X86.prog = + let g = fun (lbl, gdecl) -> Asm.data (Platform.mangle lbl) (compile_gdecl gdecl) in + let f = fun (name, fdecl) -> compile_fdecl tdecls name fdecl in + (List.map g gdecls) @ (List.map f fdecls |> List.flatten) diff --git a/hw3/cinterop.c b/hw3/cinterop.c new file mode 100644 index 0000000..f200ba2 --- /dev/null +++ b/hw3/cinterop.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +void ll_puts(int8_t *s) { + puts((char *)s); +} + +int8_t* ll_strcat(int8_t* s1, int8_t* s2) { + int l1 = strlen((char*)s1); + int l2 = strlen((char*)s2); + char* buf = (char*)calloc(l1 + l2 + 1, sizeof(char)); + strncpy(buf, (char*)s1, l1); + strncpy(buf + l1, (char*)s2, l2+1); + return (int8_t*) buf; +} + +int64_t ll_callback(int64_t (*fun)(int64_t, int64_t)) { + int64_t x = 19L; + return fun(x, x); +} + +int8_t* ll_ltoa(int64_t i) { + char* buf = (char*)calloc(20, sizeof(char)); + snprintf((char *)buf, 20, "%ld", (long)i); + return (int8_t *)buf; +} + +void *ll_malloc(int64_t n, int64_t size) { + return calloc(n, size); +} diff --git a/hw3/driver.ml b/hw3/driver.ml new file mode 100644 index 0000000..0637456 --- /dev/null +++ b/hw3/driver.ml @@ -0,0 +1,171 @@ +open Printf +open Platform + +(* configuration flags ------------------------------------------------------ *) +let interpret_ll = ref false (* run the ll interpreter? *) +let print_ll_flag = ref false (* print the generated ll code? *) +let print_x86_flag = ref false (* print the generated x86 code? *) +let clang = ref false (* use the clang backend? *) +let assemble = ref true (* assemble the .s to .o files? *) +let link = ref true (* combine multiple .o files executable? *) +let execute_x86 = ref false (* run the resulting x86 program? *) +let executable_filename = ref "a.out" + + +(* files processed during this run of the compiler *) +let files : string list ref = ref [] + +let link_files = ref [] +let add_link_file path = + link_files := path :: (!link_files) + + +(* terminal output ---------------------------------------------------------- *) + +let print_banner s = + let rec dashes n = if n = 0 then "" else "-"^(dashes (n-1)) in + printf "%s %s\n%!" (dashes (79 - (String.length s))) s + +let print_ll file ll_ast = + print_banner (file ^ ".ll"); + print_endline (Llutil.string_of_prog ll_ast) + +let print_x86 file asm_str = + print_banner file; + print_endline asm_str + +(* file i/o ----------------------------------------------------------------- *) + +let read_file (file:string) : string = + let lines = ref [] in + let channel = open_in file in + try while true; do + lines := input_line channel :: !lines + done; "" + with End_of_file -> + close_in channel; + String.concat "\n" (List.rev !lines) + +let write_file (file:string) (out:string) = + let channel = open_out file in + fprintf channel "%s" out; + close_out channel + + +(* running the generated code ----------------------------------------------- *) + +let interpret program args : string = + let result = Llinterp.interp_prog program args in + Llinterp.string_of_sval result + +let string_of_file (f:in_channel) : string = + let rec _string_of_file (stream:string list) (f:in_channel) : string list= + try + let s = input_line f in + _string_of_file (s::stream) f + with + | End_of_file -> stream + in + String.concat "\n" (List.rev (_string_of_file [] f)) + +let run_executable arg pr = + let cmd = sprintf "%s%s %s" dot_path pr arg in + sh cmd (fun _ i -> i) + +let run_executable_to_tmpfile arg pr tmp = + let cmd = sprintf "%s%s %d > %s 2>&1" dot_path pr arg tmp in + sh cmd ignore_error + + +let run_program (args:string) (executable:string) (tmp_out:string) : string = + let _ = + let cmd = sprintf "%s%s %s > %s 2>&1" dot_path executable args tmp_out in + sh cmd ignore_error + in + let fi = open_in tmp_out in + let result = string_of_file fi in + let _ = close_in fi in + result + + +(* compiler pipeline -------------------------------------------------------- *) + +(* These functions implement the compiler pipeline for a single ll file: + - parse the file + - compile to a .s file using either clang or backend.ml + - assemble the .s to a .o file using clang +*) +let parse_ll_file filename = + let program = read_file filename |> + Lexing.from_string |> + Llparser.prog Lllexer.token + in + program + + +let process_ll_ast path file ll_ast = + let _ = if !print_ll_flag then print_ll file ll_ast in + + (* Optionally interpret it using the compilerdesign reference interperter. *) + let _ = if !interpret_ll then + let result = interpret ll_ast [] in + Printf.printf "Interpreter Result: %s\n" result + in + + (* generated file names *) + let dot_s_file = Platform.gen_name !Platform.output_path file ".s" in + let dot_o_file = Platform.gen_name !Platform.output_path file ".o" in + + let _ = + if !clang then begin + Platform.verb "* compiling with clang"; + Platform.clang_compile path dot_s_file; + if !print_x86_flag then begin + print_banner dot_s_file; + Platform.sh (Printf.sprintf "cat %s" dot_s_file) Platform.raise_error + end + end else begin + Platform.verb "* compiling with compilerdesign backend"; + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + let _ = if !print_x86_flag then print_x86 dot_s_file asm_str in + let _ = write_file dot_s_file asm_str in + () + end + in + let _ = if !assemble then Platform.assemble dot_s_file dot_o_file in + let _ = add_link_file dot_o_file in + () + +let process_ll_file path file = + let _ = Platform.verb @@ Printf.sprintf "* processing file: %s\n" path in + let ll_ast = parse_ll_file path in + process_ll_ast path file ll_ast + +(* process files based on extension ----------------------------------------- *) + +let process_file path = + let basename, ext = Platform.path_to_basename_ext path in + begin match ext with + | "ll" -> process_ll_file path basename + | "o" -> add_link_file path + | "c" -> add_link_file path + | _ -> failwith @@ Printf.sprintf "found unsupported file type: %s" path + end + +(* process each file separately and then link all of them together *) +let process_files files = + if (List.length files) > 0 then begin + + List.iter process_file files; + + ( if !assemble && !link then + Platform.link (List.rev !link_files) !executable_filename ); + + ( if !assemble && !link && !execute_x86 then + let ret = run_executable "" !executable_filename in + print_banner @@ Printf.sprintf "Executing: %s" !executable_filename; + Printf.printf "* %s returned %d\n" !executable_filename ret ) + end + + diff --git a/hw3/gradedtests.ml b/hw3/gradedtests.ml new file mode 100644 index 0000000..b7c259a --- /dev/null +++ b/hw3/gradedtests.ml @@ -0,0 +1,182 @@ +open Assert +open X86 +open Ll +open Backend + +(* Do NOT modify this file -- we will overwrite it with our *) +(* own version when we test your project. *) + +(* These tests will be used to grade your assignment *) + +let size_ty_tests = + [ ("ty_size1", assert_eqf (fun () -> size_ty [] I1) 8) + ; ("ty_size3", assert_eqf (fun () -> size_ty [] I64) 8) + ; ("ty_size4", assert_eqf (fun () -> size_ty [] (Ptr Void)) 8) + ; ("ty_size2", assert_eqf (fun () -> size_ty [] (Ptr I1)) 8) + ; ("ty_size5", assert_eqf (fun () -> size_ty [] (Array (3, I64))) 24) + ; ("ty_size6", assert_eqf + (fun () -> size_ty [] (Struct [I64; I1; Ptr I8; Ptr I64; Array (10, I1) ])) 112) + ; ("ty size7", assert_eqf + (fun () -> size_ty [("O", I1);("S", I64)] (Struct [Namedt "O"; (Array (2, Namedt "S"))])) 24) + ] + +let arg_loc_tests = + [] + +let exec_e2e_ast ll_ast args extra_files = + let output_path = !Platform.output_path in + let dot_s_file = Platform.gen_name output_path "test" ".s" in + let exec_file = Platform.gen_name output_path "exec" "" in + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + let _ = Driver.write_file dot_s_file asm_str in + let _ = Platform.link (dot_s_file::extra_files) exec_file in + let result = Driver.run_executable args exec_file in + let _ = Platform.sh (Printf.sprintf "rm -f %s %s" dot_s_file exec_file) Platform.ignore_error in + let _ = Platform.verb @@ Printf.sprintf "** Executable exited with: %d\n" result in + Int64.of_int result + + +let exec_e2e_file path args = + let ast = Driver.parse_ll_file path in + exec_e2e_ast ast args [] + +let io_test path args = + let ll_ast = Driver.parse_ll_file path in + let output_path = !Platform.output_path in + let dot_s_file = Platform.gen_name output_path "test" ".s" in + let exec_file = Platform.gen_name output_path "exec" "" in + let tmp_file = Platform.gen_name output_path "tmp" ".txt" in + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + let _ = Driver.write_file dot_s_file asm_str in + let _ = Platform.link (dot_s_file::["cinterop.c"]) exec_file in + let args = String.concat " " args in + let result = Driver.run_program args exec_file tmp_file in + let _ = Platform.sh (Printf.sprintf "rm -f %s %s %s" dot_s_file exec_file tmp_file) Platform.ignore_error in + let _ = Platform.verb @@ Printf.sprintf "** Executable output:\n%s\n" result in + result + +let c_link_test c_files path args = + let ll_ast = Driver.parse_ll_file path in + let output_path = !Platform.output_path in + let dot_s_file = Platform.gen_name output_path "test" ".s" in + let exec_file = Platform.gen_name output_path "exec" "" in + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + let _ = Driver.write_file dot_s_file asm_str in + let _ = Platform.link (dot_s_file::c_files) exec_file in + let args = String.concat " " args in + let result = Driver.run_executable args exec_file in + let _ = Platform.sh (Printf.sprintf "rm -f %s %s" dot_s_file exec_file) Platform.ignore_error in + Int64.of_int result + +let executed tests = + List.map (fun (fn, ans) -> + fn, assert_eqf (fun () -> exec_e2e_file fn "") ans) + tests + +let executed_io tests = + List.map (fun (fn, args, ans) -> + (fn ^ ":" ^ (String.concat " " args)), assert_eqf (fun () -> io_test fn args) ans) + tests + +let executed_c_link tests = + List.map (fun (c_file, fn, args, ans) -> + (fn ^ ":" ^ (String.concat " " args)), assert_eqf (fun () -> c_link_test c_file fn args) ans) + tests + +let binop_tests = + [ "llprograms/add.ll", 14L + ; "llprograms/sub.ll", 1L + ; "llprograms/mul.ll", 45L + ; "llprograms/and.ll", 0L + ; "llprograms/or.ll", 1L + ; "llprograms/xor.ll", 0L + ; "llprograms/shl.ll", 168L + ; "llprograms/lshr.ll", 10L + ; "llprograms/ashr.ll", 5L ] + +let calling_convention_tests = + [ "llprograms/call.ll", 42L + ; "llprograms/call1.ll", 17L + ; "llprograms/call2.ll", 19L + ; "llprograms/call3.ll", 34L + ; "llprograms/call4.ll", 34L + ; "llprograms/call5.ll", 24L + ; "llprograms/call6.ll", 26L + ] + +let memory_tests = + [ "llprograms/alloca1.ll", 17L + ; "llprograms/alloca2.ll", 17L + ; "llprograms/global1.ll", 12L + ] + +let terminator_tests = + [ "llprograms/return.ll", 0L + ; "llprograms/return42.ll", 42L + ; "llprograms/br1.ll", 9L + ; "llprograms/br2.ll", 17L + ; "llprograms/cbr1.ll", 7L + ; "llprograms/cbr2.ll", 9L + ; "llprograms/duplicate_lbl.ll", 1L + ] + +let bitcast_tests = + [ "llprograms/bitcast1.ll", 3L + ] + +let gep_tests = + [ "llprograms/gep1.ll", 6L + ; "llprograms/gep2.ll", 4L + ; "llprograms/gep3.ll", 1L + ; "llprograms/gep4.ll", 2L + ; "llprograms/gep5.ll", 4L + ; "llprograms/gep6.ll", 7L + ; "llprograms/gep7.ll", 7L + ; "llprograms/gep8.ll", 2L + ] + +let io_tests = + [ "llprograms/helloworld.ll", [], "hello, world!" + ; "llprograms/string1.ll", [], "hello, world!hello, world!" + ; "llprograms/callback1.ll", [], "38" + ; "llprograms/args1.ll", ["hello"], "argc < 3" + ; "llprograms/args1.ll", ["hello"; "compilerdesign"], "hellocompilerdesign" + ; "llprograms/args1.ll", ["hello"; "compilerdesign"; "foo"], "argc > 3" + ] + + + + +(* Hidden *) +let hidden_large_tests = + [] + +let large_tests = [ "llprograms/list1.ll", 3L + ; "llprograms/cbr.ll", 42L + ; "llprograms/factorial.ll", 120L + ; "llprograms/factrect.ll", 120L + ; "llprograms/duplicate_factorial.ll", 240L + ] + + + +let tests : suite = + [ GradedTest("size_ty tests", 5, size_ty_tests) + ; GradedTest("arg_loc tests", 5, arg_loc_tests) + ; GradedTest("executed binop tests", 5, executed binop_tests) + ; GradedTest("terminator tests", 10, executed terminator_tests) + ; GradedTest("memory tests", 10, executed memory_tests) + ; GradedTest("calling convention tests", 15, executed calling_convention_tests) + ; GradedTest("bitcast tests", 2, executed bitcast_tests) + ; GradedTest("gep tests", 10, executed gep_tests) + ; GradedTest("large tests", 10, executed large_tests) + ; GradedTest("hidden large tests", 18, hidden_large_tests) + ; GradedTest("io tests", 10, executed_io io_tests) + ] + + +let graded_tests : suite = + tests diff --git a/hw3/ll/ll.ml b/hw3/ll/ll.ml new file mode 100644 index 0000000..9cd2ff8 --- /dev/null +++ b/hw3/ll/ll.ml @@ -0,0 +1,98 @@ +(* LLVMlite: A simplified subset of LLVM IR *) + +(* Local identifiers *) +type uid = string + +(* Global identifiers *) +type gid = string + +(* Named types *) +type tid = string + +(* Labels *) +type lbl = string + +(* LLVM types *) +type ty = +| Void +| I1 +| I8 +| I64 +| Ptr of ty +| Struct of ty list +| Array of int * ty +| Fun of ty list * ty +| Namedt of tid + +(* Function type: argument types and return type *) +type fty = ty list * ty + +(* Syntactic Values *) +type operand = +| Null +| Const of int64 +| Gid of gid +| Id of uid + +(* Binary i64 Operations *) +type bop = +| Add +| Sub +| Mul +| Shl +| Lshr +| Ashr +| And +| Or +| Xor + +(* Comparison Operators *) +type cnd = +| Eq +| Ne +| Slt +| Sle +| Sgt +| Sge + +(* Instructions *) +type insn = +| Binop of bop * ty * operand * operand +| Alloca of ty +| Load of ty * operand +| Store of ty * operand * operand +| Icmp of cnd * ty * operand * operand +| Call of ty * operand * (ty * operand) list +| Bitcast of ty * operand * ty +| Gep of ty * operand * operand list + +type terminator = +| Ret of ty * operand option +| Br of lbl +| Cbr of operand * lbl * lbl + +(* Basic Blocks *) +type block = { insns : (uid * insn) list; term : (uid * terminator) } + +(* Control Flow Graphs: entry and labeled blocks *) +type cfg = block * (lbl * block) list + +(* Function Declarations *) +type fdecl = { f_ty : fty; f_param : uid list; f_cfg : cfg } + +(* Global Data Initializers *) +type ginit = +| GNull +| GGid of gid +| GInt of int64 +| GString of string +| GArray of (ty * ginit) list +| GStruct of (ty * ginit) list +| GBitcast of ty * ginit * ty + +(* Global Declarations *) +type gdecl = ty * ginit + +(* LLVMlite Programs *) +type prog = { tdecls : (tid * ty) list; gdecls : (gid * gdecl) list; + fdecls : (gid * fdecl) list; edecls : (gid * ty) list } diff --git a/hw3/ll/llinterp.ml b/hw3/ll/llinterp.ml new file mode 100644 index 0000000..2e2388b --- /dev/null +++ b/hw3/ll/llinterp.ml @@ -0,0 +1,470 @@ +open Ll +open Llutil + +(* LLVMlite interpreter *) + +type mid = int (* memory block id *) +type fid = int (* stack frame id *) +type idx = int (* index *) + +(* Memory block identifier *) +type bid = GlobId of gid + | HeapId of mid + | StckId of fid + | NullId + +(* Pointers are tagged with a description of the block they reference + offsets are represented as paths into memory values *) +type ptr = ty * bid * idx list + +(* "Simple" or stack values *) +type sval = + | VUndef + | VInt of int64 + | VPtr of ptr + +(* Memory values *) +type mtree = MWord of sval + | MStr of string + | MNode of mval +and mval = mtree list + +(* Locals *) +type locals = uid -> sval + +(* The memory state *) +type config = + { globals : (gid * mval) list + ; heap : (mid * mval) list + ; stack : (fid * mval) list + } + +(* Create memory value for global declaration *) +let mval_of_gdecl (gd:gdecl) : mval = + let rec mtree_of_gdecl : gdecl -> mtree = function + | ty, GNull -> MWord (VPtr (ty, NullId, [0])) + | ty, GGid g -> MWord (VPtr (ty, GlobId g, [0])) + | _, GBitcast (t1, v,t2) -> mtree_of_gdecl (t1, v) + | _, GInt i -> MWord (VInt i) + | _, GString s -> MStr s + | _, GArray gs + | _, GStruct gs -> MNode (List.map mtree_of_gdecl gs) + in [mtree_of_gdecl gd] + +(* Create fully undefined memory value for a type *) +let mval_of_ty (nt:tid -> ty) (t:ty) : mval = + let rec mtree_of_ty : ty -> mtree = function + | I1 | I8 | I64 | Ptr _ -> MWord VUndef + | Array (n, I8) -> MStr (String.make n '\x00') + | Array (n, t) -> MNode Array.(make n (MWord VUndef) |> to_list) + | Struct ts -> MNode (List.map mtree_of_ty ts) + | Fun _ | Void -> failwith "mval_of_ty: mval for bad type" + | Namedt id -> mtree_of_ty (nt id) + in [mtree_of_ty t] + + +(* Printing machine states *) +let mapcat s f l = String.concat s @@ List.map f l +let prefix p f a = p ^ f a +let ( ^. ) s t = if s = "" || t = "" then "" else s ^ t +let pp = Printf.sprintf + +let string_of_bid = function + | GlobId gid -> "@" ^ gid + | HeapId mid -> "M" ^ (string_of_int mid) + | StckId fid -> "S" ^ (string_of_int fid) + | NullId -> "null" + +let string_of_ptr (t, b, i) = + pp "%s %s %s" (string_of_ty t) (string_of_bid b) + (mapcat ", " string_of_int i) + +let string_of_sval (sv:sval) : string = + match sv with + | VUndef -> "undef" + | VInt x -> Int64.to_string x + | VPtr p -> string_of_ptr p + +let rec string_of_mval (mv:mval) : string = + "[" ^ (mapcat " " string_of_mtree mv) ^ "]" + +and string_of_mtree = function + | MWord sv -> string_of_sval sv + | MStr s -> "\"" ^ s ^ "\"" + | MNode m -> string_of_mval m + + +(* Varieties of undefined behavior. Can be raised by load/store *) +exception OOBIndexDeref (* mem access not in bounds of an array *) +exception NullPtrDeref (* deref Null *) +exception UndefPtrDeref (* deref Undef pointer (from bad GEP) *) +exception IncompatTagDeref (* deref pointer at wrong type (bad bitcast) *) +exception UndefMemDeref (* read uninitialized memory *) +exception UninitMemLoad (* uninitialized memory load *) +exception UseAfterFree (* deref freed stack/heap memory *) + + +(* Arithmetic operations are all signed 64bit 2s compliment (mod In64.max_int) *) +let interp_bop (b:bop) (v1:sval) (v2:sval) : sval = + let i, j = match v1, v2 with + | VInt i, VInt j -> i, j + | _ -> invalid_arg "interp_bop" + in + let open Int64 in + let f = match b with + | Add -> add | Sub -> sub | Mul -> mul + | And -> logand | Or -> logor | Xor -> logxor + | Shl -> fun i j -> shift_left i @@ to_int j + | Lshr -> fun i j -> shift_right_logical i @@ to_int j + | Ashr -> fun i j -> shift_right i @@ to_int j + in VInt (f i j) + +let interp_cnd (c:cnd) (v1:sval) (v2:sval) = + let f = match c with + | Eq -> (=) | Ne -> (<>) | Slt -> (<) + | Sle -> (<=) | Sgt -> (>) | Sge -> (>=) + in + match v1, v2, c with + | VPtr (_,b1,i1), VPtr (_,b2,i2), Eq + | VPtr (_,b1,i1), VPtr (_,b2,i2), Ne -> + VInt (if f (b1,i1) (b2,i2) then 1L else 0L) + | VInt i, VInt j, _ -> + VInt (if f i j then 1L else 0L) + | _ -> invalid_arg "interp_cnd" + +let interp_i1 : sval -> bool = function + | VInt 0L -> false + | VInt 1L -> true + | _ -> invalid_arg "interp_i1" + +let rec interp_operand (nt:tid -> ty) (locs:locals) (ty:ty) (o:operand) : sval = + match ty, o with + | I64, Const i -> VInt i + | Ptr ty, Null -> VPtr (ty, NullId, [0]) + | Ptr ty, Gid g -> VPtr (ty, GlobId g, [0]) + | _, Id u -> locs u + | Namedt id, o -> interp_operand nt locs (nt id) o + | _ -> failwith @@ "interp_operand: malformed operand " ^ soo o ^ ":" ^ sot ty + + +(* Some utility functions *) +let update f k v = fun k' -> if k = k' then v else f k' + +let rec is_prefix (l:'a list) (m:'a list) : bool = + match l, m with + | [], _ -> true + | _, [] -> false + | a::l, b::m -> a = b && is_prefix l m + +let replace_assoc (l:('a * 'b) list) (a:'a) (b:'b) : ('a * 'b) list = + let rec loop acc = function + | [] -> List.rev @@ (a,b)::acc + | (a',_)::l' when a = a' -> List.rev_append acc @@ (a,b):: l' + | e::l' -> loop (e::acc) l' + in + loop [] l + +let replace_nth (l:'a list) (n:int) (a:'a) : 'a list = + let rec loop acc n = function + | [] -> raise Not_found + | a'::l' -> if n = 0 then List.rev_append acc (a::l') + else loop (a'::acc) (pred n) l' + in + loop [] n l + + +(* Memory access *) +let rec load_idxs (m:mval) (idxs:idx list) : mtree = + match idxs with + | [] -> MNode m + | i::idxs' -> + let len = List.length m in + if len <= i || i < 0 then raise OOBIndexDeref else + match idxs', List.nth m i with + | [], mt -> mt + | [0], MStr s -> MStr s (* [n x i8]* %p and gep [n x i8]* %p, 0, 0 alias *) + | _, MWord v -> failwith "load_idxs: attempted to index into word" + | _, MStr _ -> failwith "load_idxs: attempted to index into string" + | _, MNode m' -> load_idxs m' idxs' + +let rec store_idxs (m:mval) (idxs:idx list) (mt:mtree) : mval = + match idxs with + | [] -> [mt] + | i::idxs' -> + let len = List.length m in + if len <= i || i < 0 then raise OOBIndexDeref else + match idxs', List.nth m i with + | [], _ -> replace_nth m i mt + | _, MWord v -> failwith "store_idxs: attempted to index into word" + | _, MStr _ -> failwith "store_idxs: attempted to index into string" + | _, MNode m' -> replace_nth m i @@ MNode (store_idxs m' idxs' mt) + +let load_bid (c:config) (bid:bid) : mval = + match bid with + | NullId -> raise NullPtrDeref + | HeapId mid -> + (try List.assoc mid c.heap + with Not_found -> raise UseAfterFree) + | GlobId gid -> + (try List.assoc gid c.globals + with Not_found -> failwith "Load: bogus gid") + | StckId fid -> + (try List.assoc fid c.stack + with Not_found -> raise UseAfterFree) + + +let load_ptr (c:config) (_, bid, idxs:ptr) : mtree = + load_idxs (load_bid c bid) idxs + +let store_ptr (c:config) (_, bid, idxs:ptr) (mt:mtree) : config = + let mval = load_bid c bid in + match bid with + | NullId -> raise NullPtrDeref + | HeapId mid -> + let mval' = store_idxs mval idxs mt in + let heap = replace_assoc c.heap mid mval' in + {c with heap} + | GlobId gid -> + let mval' = store_idxs mval idxs mt in + let globals = replace_assoc c.globals gid mval' in + {c with globals} + | StckId fid -> + let frame' = store_idxs mval idxs mt in + let stack = replace_assoc c.stack fid frame' in + {c with stack} + + +(* Tag and GEP implementation *) +let effective_tag (nt:tid -> ty) (tag, _, idxs :ptr) : ty = + let rec loop tag idxs = + match tag, idxs with + | t, [] -> t + | Struct ts, i::idxs' -> if List.length ts <= i + then failwith "effective_tag: index oob of struct" + else loop (List.nth ts i) idxs' + | Array (n, t), i::idxs' -> loop t idxs' (* Don't check if OOB! *) + | Namedt id, _ -> loop (nt id) idxs + | _, _::_ -> failwith "effective_tag: index into non-aggregate" + in + loop tag @@ try List.tl idxs + with Failure _ -> failwith "effective_tag: invalid pointer missing first index" + + +let rec gep_idxs (p:idx list) (idxs:idx list) : idx list = + match p, idxs with + | [], _ | _, [] -> failwith "gep_idxs: invalid indices" + | [i], j::idxs' -> i+j::idxs' + | i::p', _ -> i::gep_idxs p' idxs + + +let legal_gep (nt:tid -> ty) (sty:ty) (tag:ty) : bool = + let rec ptrtoi8 : ty -> ty = function + | Ptr _ -> Ptr I8 + | Struct ts -> Struct (List.map ptrtoi8 ts) + | Array (n, t) -> Array (n, ptrtoi8 t) + | Namedt id -> ptrtoi8 (nt id) + | t -> t + in + let rec flatten_ty : ty -> ty list = function + | Struct ts -> List.(concat @@ map flatten_ty ts) + | t -> [t] + in + is_prefix (flatten_ty @@ ptrtoi8 sty) (flatten_ty @@ ptrtoi8 tag) + +let gep_ptr (nt:tid -> ty) (ot:ty) (p:ptr) (idxs':idx list) : sval = + if not (legal_gep nt ot @@ effective_tag nt p) then VUndef else + match p with + | t, NullId, idxs -> VUndef + | t, bid, idxs -> + VPtr (t, bid, gep_idxs idxs idxs') + + +(* LLVMlite reference interpreter *) +let interp_prog {tdecls; gdecls; fdecls} (args:string list) : sval = + + let globals = List.map (fun (g,gd) -> g,mval_of_gdecl gd) gdecls in + + let nt (id:tid) : ty = + try List.assoc id tdecls + with Not_found -> failwith @@ "interp_prog: undefined named type " ^ id + in + + let interp_op = interp_operand nt in + + let next_id : unit -> fid = + let c = ref 0 in + fun () -> c := succ !c; !c + in + + (* Global identifiers that will be interpreted as external functions *) + let runtime_fns = [ "ll_puts"; "ll_strcat"; "ll_ltoa" ] + in + + (* External function implementation *) + let runtime_call (t:ty) (fn:gid) (args:sval list) (c:config) : config * sval = + let load_strptr p = match load_ptr c p with + | MStr s -> s + | _ -> failwith "runtime_call: non string-ptr arg" + in + match t, fn, args with + | Void, "ll_puts", [VPtr p] -> + let s = load_strptr p in + print_endline s; + c, VUndef + | Ptr t, "ll_strcat", [VPtr ps1; VPtr ps2] -> + let s1 = load_strptr ps1 in + let s2 = load_strptr ps2 in + let mid = next_id () in + let mv = [MStr (s1 ^ s2)] in + let heap = (mid, mv)::c.heap in + {c with heap}, VPtr (t, HeapId mid, [0]) + | I64, "ll_ltoa", [VInt i; VPtr dst] -> + let mid = next_id () in + let mv = [MStr (Int64.to_string i)] in + let heap = (mid, mv)::c.heap in + {c with heap}, VPtr (t, HeapId mid, [0]) + | _ -> failwith @@ "runtime_call: invalid call to " ^ fn + in + + + (* Interprety the body of a function *) + let rec interp_cfg (k, blocks:cfg) (locs:locals) (c:config) : config * sval = + match k.insns, k.term with + + | (u, Binop (b, t, o1, o2))::insns, _ -> + let v1 = interp_op locs t o1 in + let v2 = interp_op locs t o2 in + let vr = interp_bop b v1 v2 in + let locs' = update locs u vr in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Icmp (cnd, t, o1, o2))::insns, _ -> + let v1 = interp_op locs t o1 in + let v2 = interp_op locs t o2 in + let vr = interp_cnd cnd v1 v2 in + let locs' = update locs u vr in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Alloca ty)::insns, _ -> + begin match c.stack with + | [] -> failwith "stack empty" + | (fid,frame)::stack' -> + let ptr = VPtr (ty, StckId fid, [List.length frame]) in + let stack = (fid, frame @ [MWord VUndef])::stack' in + let locs' = update locs u ptr in + interp_cfg ({k with insns}, blocks) locs' {c with stack} + end + + | (u, Load (Ptr t, o))::insns, _ -> + let mt = match interp_op locs (Ptr t) o with + | VPtr p -> + if effective_tag nt p <> t + then raise IncompatTagDeref + else load_ptr c p + | VUndef -> raise UndefPtrDeref + | VInt _ -> failwith "non-ptr arg for load" + in + let v = match mt with + | MWord VUndef -> raise UninitMemLoad + | MWord v -> v + | _ -> failwith "load: returned aggregate" + in + let locs' = update locs u v in + interp_cfg ({k with insns}, blocks) locs' c + + | (_, Store (t, os, od))::insns, _ -> + let vs = interp_op locs t os in + let vd = interp_op locs (Ptr t) od in + let c' = match vd with + | VPtr p -> + if effective_tag nt p <> t + then raise IncompatTagDeref + else store_ptr c p (MWord vs) + | VUndef -> raise UndefPtrDeref + | VInt _ -> failwith "non-vptr arg for load" + in + interp_cfg ({k with insns}, blocks) locs c' + + | (u, Call (t, ofn, ato))::insns, _ -> + let ats, aos = List.split ato in + let ft = Ptr (Fun (ats, t)) in + let g = match interp_op locs ft ofn with + | VPtr (_, GlobId g, [0]) -> g + | _ -> failwith "bad call arg" + in + let args = List.map2 (interp_op locs) ats aos in + let c', r = interp_call t g args c in + let locs' = update locs u r in + interp_cfg ({k with insns}, blocks) locs' c' + + | (u, Bitcast (t1, o, _))::insns, _ -> + let v = interp_op locs t1 o in + let locs' = update locs u v in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Gep (Ptr t, o, os))::insns, _ -> + let idx_of_sval : sval -> idx = function + | VInt i -> Int64.to_int i + | _ -> failwith "idx_of_sval: non-integer value" + in + let vs = List.map (interp_op locs I64) os in + let idxs' = List.map idx_of_sval vs in + let v' = match interp_op locs (Ptr t) o with + | VPtr p -> gep_ptr nt t p idxs' + | VUndef -> VUndef + | VInt _ -> failwith "non-ptr arg for gep" + in + let locs' = update locs u v' in + interp_cfg ({k with insns}, blocks) locs' c + + | [], (_, Ret (_, None)) -> + {c with stack = List.tl c.stack}, VUndef + + | [], (_, Ret (t, Some o)) -> + {c with stack = List.tl c.stack}, interp_op locs t o + + | [], (_, Br l) -> + let k' = List.assoc l blocks in + interp_cfg (k', blocks) locs c + + | [], (_, Cbr (o, l1, l2)) -> + let v = interp_op locs I1 o in + let l' = if interp_i1 v then l1 else l2 in + let k' = List.assoc l' blocks in + interp_cfg (k', blocks) locs c + + | (u,i)::_, _ -> failwith @@ "interp_cfg: invalid instruction \"" + ^ string_of_insn i ^ "\" at %" ^ u + + and interp_call (ty:ty) (fn:gid) (args:sval list) (c:config) : config * sval = + if List.mem fn runtime_fns + then runtime_call ty fn args c + else + let {f_param; f_cfg} = try List.assoc fn fdecls + with Not_found -> failwith @@ "interp_call: undefined function " ^ fn + in + if List.(length f_param <> length args) then + failwith @@ "interp_call: wrong no. arguments for " ^ fn; + let init_locs l = failwith @@ "interp_call: undefined local " ^ l in + let locs = List.fold_left2 update init_locs f_param args in + let stack = (next_id(), [])::c.stack in + interp_cfg f_cfg locs {c with stack} + in + + let mkarg a (p,h) = + let id = next_id () in + VPtr (I8, HeapId id, [0])::p, (id, [MStr a])::h + in + let ptrs, heap = List.fold_right mkarg ("LLINTERP"::args) ([],[]) in + + let narg = List.length args + 1 in + let argc = VInt (Int64.of_int @@ narg) in + let aid = next_id () in + let argv = VPtr (Array (narg, Ptr I8), HeapId aid, [0; 0]) in + let amval = List.map (fun p -> MWord p) ptrs in + let heap = (aid, [MNode amval])::heap in + + let _, r = interp_call I64 "main" [argc; argv] {globals; heap; stack=[]} in + r + + diff --git a/hw3/ll/lllexer.mll b/hw3/ll/lllexer.mll new file mode 100644 index 0000000..2fbacba --- /dev/null +++ b/hw3/ll/lllexer.mll @@ -0,0 +1,83 @@ +{ open Lexing + open Llparser + + exception SyntaxError of string +} + +let newline = '\n' | ('\r' '\n') | '\r' +let whitespace = ['\t' ' '] +let lowercase = ['a'-'z'] +let uppercase = ['A'-'Z'] +let character = lowercase | uppercase +let digit = '-'? ['0'-'9'] +let identifier = (character | digit | '_' ) (character | digit | '_' | '.')* + +rule token = parse + | eof { EOF } + | whitespace+ { token lexbuf } + | newline+ { token lexbuf } + | "c\"" { read_string (Buffer.create 17) lexbuf } + | '*' { STAR } + | ',' { COMMA } + | ':' { COLON } + | '=' { EQUALS } + | '(' { LPAREN } + | ')' { RPAREN } + | '{' { LBRACE } + | '}' { RBRACE } + | '[' { LBRACKET } + | ']' { RBRACKET } + | "i1" { I1 } + | "i8" { I8 } + | "i32" { I32 } + | "i64" { I64 } + | "to" { TO } + | "br" { BR } + | "eq" { EQ } + | "ne" { NE } + | "or" { OR } + | "and" { AND } + | "add" { ADD } + | "sub" { SUB } + | "mul" { MUL } + | "xor" { XOR } + | "slt" { SLT } + | "sle" { SLE } + | "sgt" { SGT } + | "sge" { SGE } + | "shl" { SHL } + | "ret" { RET } + | "getelementptr" { GEP } + | "type" { TYPE } + | "null" { NULL } + | "lshr" { LSHR } + | "ashr" { ASHR } + | "call" { CALL } + | "icmp" { ICMP } + | "void" { VOID } + | "load" { LOAD } + | "entry" { ENTRY } + | "store" { STORE } + | "label" { LABEL } + | "global" { GLOBAL } + | "define" { DEFINE } + | "declare" { DECLARE } + | "external" { EXTERNAL } + | "alloca" { ALLOCA } + | "bitcast" { BITCAST } + | '%' ('.' ?) (identifier as i) { UID i } + | '@' ('.' ?) (identifier as i) { GID i } + | "x" { CROSS } (* for Array types *) + | digit+ as d { INT (int_of_string d) } + | identifier as i { LBL i } + | ";" ([^ '\n' '\r'])* newline { token lexbuf } (* comments *) + | "declare" ([^ '\n' '\r'])* newline { token lexbuf } (* declare acts as a comment for our IR *) + | _ as c { raise @@ SyntaxError ("Unexpected character: " ^ Char.escaped c) } + +and read_string buf = parse + | '\\' "00" '"' { STRING (Buffer.contents buf) } + | '\\' { Buffer.add_char buf '\\'; read_string buf lexbuf } + | [^ '"' '\\']+ { Buffer.add_string buf (Lexing.lexeme lexbuf) + ; read_string buf lexbuf } + | _ { raise (SyntaxError ("Illegal string character: " ^ Lexing.lexeme lexbuf)) } + | eof { raise (SyntaxError ("String is not terminated")) } diff --git a/hw3/ll/llparser.mly b/hw3/ll/llparser.mly new file mode 100644 index 0000000..ca28340 --- /dev/null +++ b/hw3/ll/llparser.mly @@ -0,0 +1,298 @@ +%{ open Ll + open Llutil.Parsing + +%} + +(* Symbols *) +%token STAR (* * *) +%token COMMA (* , *) +%token COLON (* : *) +%token EQUALS (* = *) +%token LPAREN (* ( *) +%token RPAREN (* ) *) +%token LBRACE (* { *) +%token RBRACE (* } *) +%token LBRACKET (* [ *) +%token RBRACKET (* ] *) +%token EOF + +(* Reserved Words *) +%token CROSS (* x *) +%token I1 (* i1 *) +%token I8 (* i8 *) +%token I32 (* i32 *) +%token I64 (* i64 *) +%token TO (* to *) +%token BR (* br *) +%token EQ (* eq *) +%token NE (* ne *) +%token OR (* or *) +%token AND (* and *) +%token ADD (* add *) +%token SUB (* sub *) +%token MUL (* mul *) +%token XOR (* xor *) +%token SLT (* slt *) +%token SLE (* sle *) +%token SGT (* sgt *) +%token SGE (* sge *) +%token SHL (* shl *) +%token RET (* ret *) +%token TYPE (* type *) +%token NULL (* null *) +%token LSHR (* lshr *) +%token ASHR (* ashr *) +%token CALL (* call *) +%token ICMP (* icmp *) +%token VOID (* void *) +%token LOAD (* load *) +%token STORE (* store *) +%token LABEL (* label *) +%token ENTRY (* entry *) +%token GLOBAL (* global *) +%token DEFINE (* define *) +%token DECLARE (* define *) +%token EXTERNAL (* external *) +%token ALLOCA (* alloca *) +%token BITCAST (* bitcast *) +%token GEP (* getelementptr *) + +%token INT (* int64 values *) +%token LBL (* labels *) +%token GID (* global identifier *) +%token UID (* local identifier *) +%token STRING (* string literals *) + +%start prog +%% + +prog: + | ds=decls EOF + { ds } + +decls: + | ds = decls_rev + { { tdecls = List.rev ds.tdecls + ; gdecls = List.rev ds.gdecls + ; fdecls = List.rev ds.fdecls + ; edecls = List.rev ds.edecls + } } + +decls_rev: + | (* empty *) + { { tdecls = [] ; gdecls = [] ; fdecls = [] ; edecls = [] } } + | ds=decls_rev f=fdecl + { { ds with fdecls = f :: ds.fdecls } } + | ds=decls_rev g=gdecl + { { ds with gdecls = g :: ds.gdecls } } + | ds=decls_rev t=tdecl + { { ds with tdecls = t :: ds.tdecls } } + | ds=decls_rev e=edecl + { { ds with edecls = e :: ds.edecls } } + +fdecl: + | DEFINE t=ty l=GID LPAREN a=arg_list RPAREN + LBRACE eb=entry_block bs=block_list RBRACE + { (l, { f_ty = (List.map fst a, t) + ; f_param = List.map snd a + ; f_cfg = (eb, bs) + } + ) } + +gdecl: + | g=GID EQUALS GLOBAL t=ty gi=ginit + { (g, (t,gi)) } + +tdecl: + | tid=UID EQUALS TYPE t=ty + { (tid, t) } + +edecl: + | DECLARE rt=ty g=GID LPAREN ts=separated_list(COMMA, ty) RPAREN + { (g, Fun (ts,rt)) } + | g=GID EQUALS EXTERNAL GLOBAL t=ty + { (g, t) } + +nonptr_ty: + | VOID { Void } + | I1 { I1 } + | I8 { I8 } + | I64 { I64 } + | LBRACE ts=ty_list RBRACE + { Struct ts } + | LBRACKET i=INT CROSS t=ty RBRACKET + { Array (i,t) } + | rt=ty LPAREN ts=ty_list RPAREN + { Fun (ts, rt) } + | t=UID + { Namedt t } + +ty: + | t=ty STAR + { Ptr t } + | t=nonptr_ty + { t } + +ty_list_rev: + | t=ty + { [t] } + | ts=ty_list_rev COMMA t=ty + { t::ts } + +ty_list: + | ts=ty_list_rev + { List.rev ts } + +arg: + | t=ty u=UID { (t,u) } + +arg_list_rev: + | (* empty *) + { [] } + | a=arg + { [a] } + | args=arg_list_rev COMMA a=arg + { a::args } + +arg_list: + | a=arg_list_rev + { List.rev a } + +operand: + | NULL + { Null } + | i=INT + { Const (Int64.of_int i) } + | g=GID + { Gid g } + | u=UID + { Id u } + +ty_operand_list_rev: + | (* empty *) + { [] } + | t=ty o=operand + { [(t,o)] } + | tos=ty_operand_list_rev COMMA t=ty o=operand + { (t,o)::tos } + +ty_operand_list: + | tos=ty_operand_list_rev + { List.rev tos } + +i_operand_list_rev: + | (* empty *) + { [] } + | I64 o=operand + { [o] } + | I32 o=operand + { [o] } + | os=i_operand_list_rev COMMA I64 o=operand + { o::os } + | os=i_operand_list_rev COMMA I32 o=operand + { o::os } + +i_operand_list: + | os=i_operand_list_rev + { List.rev os } + +terminator: + | RET t=ty o=operand + { Ret (t, Some o) } + | RET t=ty + { Ret (t, None) } + | BR LABEL l=UID + { Br l } + | BR I1 o=operand COMMA LABEL l1=UID COMMA LABEL l2=UID + { Cbr (o,l1,l2) } + +block: + | is=insn_list t=terminator + { { insns = is; term=(gensym "tmn", t) } } + +block_list_rev: + | (* empty *) + { [] } + | bs=block_list_rev l=LBL COLON b=block + { (l,b) :: bs } + +block_list: + | bs=block_list_rev + { List.rev bs } + +entry_block: + | ENTRY COLON b=block + { b } + | b=block + { b } + +bop: + | OR { Or } + | ADD { Add } + | SUB { Sub } + | MUL { Mul } + | SHL { Shl } + | XOR { Xor } + | AND { And } + | LSHR { Lshr } + | ASHR { Ashr } + +cnd: + | EQ { Eq } + | NE { Ne } + | SLT { Slt } + | SLE { Sle } + | SGT { Sgt } + | SGE { Sge } + +insn: + | u=UID EQUALS b=bop t=ty o1=operand COMMA o2=operand + { (u, Binop (b,t,o1,o2)) } + | u=UID EQUALS ALLOCA t=ty + { (u, Alloca t) } + | u=UID EQUALS LOAD ty COMMA t=ty o=operand + { (u, Load (t,o)) } + | STORE t1=ty o1=operand COMMA t2=ty o2=operand + { (gensym "store", Store (t1,o1,o2)) } + | u=UID EQUALS ICMP c=cnd t=ty o1=operand COMMA o2=operand + { (u, Icmp (c,t,o1,o2)) } + | CALL t=ty o=operand LPAREN args=ty_operand_list RPAREN + { (gensym "call", Call (t, o, args)) } + | u=UID EQUALS CALL t=ty o=operand LPAREN args=ty_operand_list RPAREN + { (u, Call (t, o, args)) } + | u=UID EQUALS BITCAST t1=ty o=operand TO t2=ty + { (u, Bitcast (t1,o,t2)) } + | u=UID EQUALS GEP ty COMMA t=ty o=operand COMMA os=i_operand_list + { (u, Gep (t,o,os)) } + +insn_list: + | is=list(insn) + { is } + +gdecl_list_rev: + | (* empty *) + { [] } + | t=ty g=ginit + { [(t,g)] } + | gs=gdecl_list_rev COMMA t=ty g=ginit + { (t,g)::gs } + +gdecl_list: + | gs=gdecl_list_rev + { List.rev gs } + +ginit: + | NULL + { GNull } + | g=GID + { GGid g } + | i=INT + { GInt (Int64.of_int i) } + | s=STRING + { GString s } + | LBRACKET gs=gdecl_list RBRACKET + { GArray gs } + | LBRACE gs=gdecl_list RBRACE + { GStruct gs } + | BITCAST LPAREN t1=ty g=ginit TO t2=ty RPAREN + { GBitcast (t1, g, t2) } diff --git a/hw3/ll/llutil.ml b/hw3/ll/llutil.ml new file mode 100644 index 0000000..f7bba0f --- /dev/null +++ b/hw3/ll/llutil.ml @@ -0,0 +1,170 @@ +;; open Ll + +(* serializing --------------------------------------------------------------- *) + +let mapcat s f l = String.concat s @@ List.map f l +let prefix p f a = p ^ f a +let ( ^. ) s t = if s = "" || t = "" then "" else s ^ t +let pp = Printf.sprintf + +let rec string_of_ty : ty -> string = function + | Void -> "void" + | I1 -> "i1" + | I8 -> "i8" + | I64 -> "i64" + | Ptr ty -> pp "%s*" (string_of_ty ty) + | Struct ts -> pp "{ %s }" (mapcat ", " string_of_ty ts) + | Array (n, t) -> pp "[%s x %s]" (string_of_int n) (string_of_ty t) + | Fun (ts,t) -> pp "%s (%s)" (string_of_ty t) (mapcat ", " string_of_ty ts) + | Namedt s -> pp "%%%s" s + +let sot = string_of_ty + +let dptr = function + | Ptr t -> t + | _ -> failwith "PP: expected pointer type" + +let string_of_operand : operand -> string = function + | Null -> "null" + | Const i -> Int64.to_string i + | Gid g -> "@" ^ g + | Id u -> "%" ^ u + +let soo = string_of_operand + +let soop (t,v:ty * operand) : string = + pp "%s %s" (sot t) (soo v) + +let string_of_bop : bop -> string = function + | Add -> "add" | Sub -> "sub" | Mul -> "mul" + | Shl -> "shl" | Lshr -> "lshr" | Ashr -> "ashr" + | And -> "and" | Or -> "or" | Xor -> "xor" + +let string_of_cnd : cnd -> string = function + | Eq -> "eq" | Ne -> "ne" | Slt -> "slt" + | Sle -> "sle" | Sgt -> "sgt" | Sge -> "sge" + +let string_of_gep_index : operand -> string = function + | Const i -> "i32 " ^ Int64.to_string i + | o -> "i64 " ^ soo o + +let string_of_insn : insn -> string = function + | Binop (b, t, o1, o2) -> pp "%s %s %s, %s" + (string_of_bop b) (sot t) (soo o1) (soo o2) + | Alloca t -> pp "alloca %s" (sot t) + | Load (t, o) -> pp "load %s, %s %s" (sot (dptr t)) (sot t) (soo o) + | Store (t, os, od) -> pp "store %s %s, %s %s" + (sot t) (soo os) (sot (Ptr t)) (soo od) + | Icmp (c, t, o1, o2) -> pp "icmp %s %s %s, %s" + (string_of_cnd c) (sot t) (soo o1) (soo o2) + | Call (t, o, oa) -> pp "call %s %s(%s)" + (sot t) (soo o) (mapcat ", " soop oa) + | Bitcast (t1, o, t2) -> pp "bitcast %s %s to %s" (sot t1) (soo o) (sot t2) + | Gep (t, o, oi) -> pp "getelementptr %s, %s %s, %s" (sot (dptr t)) (sot t) (soo o) + (mapcat ", " string_of_gep_index oi) + +let string_of_named_insn (u,i:uid * insn) : string = + match i with + | Store _ | Call (Void, _, _) -> string_of_insn i + | _ -> pp "%%%s = %s" u (string_of_insn i) + +let string_of_terminator : terminator -> string = function + | Ret (_, None) -> "ret void" + | Ret (t, Some o) -> pp "ret %s %s" (sot t) (soo o) + | Br l -> pp "br label %%%s" l + | Cbr (o, l, m) -> pp "br i1 %s, label %%%s, label %%%s" (soo o) l m + +let string_of_block (b:block) : string = + (mapcat "\n" (prefix " " string_of_named_insn) b.insns ^. "\n") + ^ (prefix " " string_of_terminator) (snd b.term) + +let string_of_cfg (e,bs:cfg) : string = + let string_of_named_block (l,b) = l ^ ":\n" ^ string_of_block b in + string_of_block e ^ "\n" ^. mapcat "\n" string_of_named_block bs + +let string_of_named_fdecl (g,f:gid * fdecl) : string = + let string_of_arg (t,u) = pp "%s %%%s" (sot t) u in + let ts, t = f.f_ty in + pp "define %s @%s(%s) {\n%s\n}\n" (sot t) g + (mapcat ", " string_of_arg List.(combine ts f.f_param)) + (string_of_cfg f.f_cfg) + +let rec string_of_ginit : ginit -> string = function + | GNull -> "null" + | GGid g -> pp "@%s" g + | GInt i -> Int64.to_string i + | GString s -> pp "c\"%s\\00\"" s + | GArray gis -> pp "[ %s ]" (mapcat ", " string_of_gdecl gis) + | GStruct gis -> pp "{ %s }" (mapcat ", " string_of_gdecl gis) + | GBitcast (t1,g,t2) -> pp "bitcast (%s %s to %s)" (sot t1) (string_of_ginit g) (sot t2) + +and string_of_gdecl (t,gi:gdecl) : string = + pp "%s %s" (sot t) (string_of_ginit gi) + +let string_of_named_gdecl (g,gd:gid * gdecl) : string = + pp "@%s = global %s" g (string_of_gdecl gd) + +let string_of_named_tdecl (n,t:tid * ty) : string = + pp "%%%s = type %s" n (sot t) + +let string_of_named_edecl (g,t:gid * ty) : string = + match t with + | Fun (ts, rt) -> pp "declare %s @%s(%s)" (string_of_ty rt) g + (mapcat ", " string_of_ty ts) + | _ -> pp "@%s = external global %s" g (string_of_ty t) + +let string_of_prog (p:prog) : string = + (mapcat "\n" string_of_named_tdecl p.tdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_gdecl p.gdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_fdecl p.fdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_edecl p.edecls) + +(* comparison for testing ----------------------------------------------------- *) + +(* delete dummy uids before comparison *) +let compare_block (b:block) (c:block) : int = + let del_dummy (u,i) = + match i with + | Store (_, _, _) -> "", i + | Call (Void, _, _) -> "", i + | _ -> u, i + in + let del_term (u,t) = ("", t) + in + Pervasives.compare + {insns=List.map del_dummy b.insns; term=del_term b.term} + {insns=List.map del_dummy c.insns; term=del_term c.term} + + + +(* helper module for AST ------------------------------------------------------ *) + +module IR = struct + let define t gid args f_cfg = + let ats, f_param = List.split args in + gid, { f_ty=ats,t; f_param; f_cfg} + + (* ignore first label *) + let cfg (lbs:(lbl * block) list) : cfg = + match lbs with + | [] -> failwith "cfg: no blocks!" + | (_,b)::lbs -> b, lbs + + let entry insns term : (lbl * block) = "", { insns; term } + let label lbl insns term = lbl, { insns; term } + + (* terminators *) + let ret_void = Ret (Void, None) + let ret t op = Ret (t, Some op) + let br l = Br l + let cbr op l1 l2 = Cbr (op, l1, l2) +end + +module Parsing = struct + +let gensym, reset = + let c = ref 0 in + ( fun (s:string) -> incr c; Printf.sprintf "_%s__%d" s (!c) ) + , ( fun () -> c := 0 ) + +end diff --git a/hw3/llprograms/add.ll b/hw3/llprograms/add.ll new file mode 100644 index 0000000..d756f0a --- /dev/null +++ b/hw3/llprograms/add.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + ret i64 %1 +} + diff --git a/hw3/llprograms/add_twice.ll b/hw3/llprograms/add_twice.ll new file mode 100644 index 0000000..221ebe8 --- /dev/null +++ b/hw3/llprograms/add_twice.ll @@ -0,0 +1,6 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = add i64 %1, 15 + ret i64 %2 +} + diff --git a/hw3/llprograms/alloca1.ll b/hw3/llprograms/alloca1.ll new file mode 100644 index 0000000..094ddb6 --- /dev/null +++ b/hw3/llprograms/alloca1.ll @@ -0,0 +1,7 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 17, i64* %1 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/alloca2.ll b/hw3/llprograms/alloca2.ll new file mode 100644 index 0000000..a2504c3 --- /dev/null +++ b/hw3/llprograms/alloca2.ll @@ -0,0 +1,10 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 17, i64* %1 + %2 = alloca i64* + store i64* %1, i64** %2 + %3 = load i64*, i64** %2 + %4 = load i64, i64* %3 + ret i64 %4 +} + diff --git a/hw3/llprograms/analysis1.ll b/hw3/llprograms/analysis1.ll new file mode 100644 index 0000000..647ab45 --- /dev/null +++ b/hw3/llprograms/analysis1.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + br label %l1 +l1: + %4 = bitcast i64* %3 to i8* + ret i64 %1 +} + diff --git a/hw3/llprograms/analysis10.ll b/hw3/llprograms/analysis10.ll new file mode 100644 index 0000000..81f1936 --- /dev/null +++ b/hw3/llprograms/analysis10.ll @@ -0,0 +1,29 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 30, 0 + %2 = sub i64 %1, 24 + %3 = sub i64 9, %2 + %4 = alloca i64 + store i64 %3, i64* %4 + %5 = load i64, i64* %4 + %6 = mul i64 %3, 4 + %7 = alloca i64 + store i64 %6, i64* %7 + %8 = load i64, i64* %7 + %9 = icmp sgt i64 %6, 10 + br i1 %9, label %then, label %else +then: + %10 = load i64, i64* %7 + %11 = sub i64 %10, 10 + store i64 %11, i64* %7 + br label %merge +else: + %12 = load i64, i64* %7 + %13 = add i64 %12, 10 + store i64 %13, i64* %7 + br label %merge +merge: + %14 = load i64, i64* %7 + %15 = sub i64 60, %1 + %16 = mul i64 %14, %15 + ret i64 %16 +} diff --git a/hw3/llprograms/analysis10_cf_opt.ll b/hw3/llprograms/analysis10_cf_opt.ll new file mode 100644 index 0000000..b609b9d --- /dev/null +++ b/hw3/llprograms/analysis10_cf_opt.ll @@ -0,0 +1,30 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 30, 0 + %2 = sub i64 30, 24 + %3 = sub i64 9, 6 + %4 = alloca i64 + store i64 3, i64* %4 + %5 = load i64, i64* %4 + %6 = mul i64 3, 4 + %7 = alloca i64 + store i64 12, i64* %7 + %8 = load i64, i64* %7 + %9 = icmp sgt i64 12, 10 + br i1 1, label %then, label %else +else: + %12 = load i64, i64* %7 + %13 = add i64 %12, 10 + store i64 %13, i64* %7 + br label %merge +merge: + %14 = load i64, i64* %7 + %15 = sub i64 60, 30 + %16 = mul i64 %14, 30 + ret i64 %16 +then: + %10 = load i64, i64* %7 + %11 = sub i64 %10, 10 + store i64 %11, i64* %7 + br label %merge +} + diff --git a/hw3/llprograms/analysis10_dce_opt.ll b/hw3/llprograms/analysis10_dce_opt.ll new file mode 100644 index 0000000..d04dcb3 --- /dev/null +++ b/hw3/llprograms/analysis10_dce_opt.ll @@ -0,0 +1,22 @@ +define i64 @program(i64 %argc, i8** %argv) { + %4 = alloca i64 + store i64 3, i64* %4 + %7 = alloca i64 + store i64 12, i64* %7 + br i1 1, label %then, label %else +else: + %12 = load i64, i64* %7 + %13 = add i64 %12, 10 + store i64 %13, i64* %7 + br label %merge +merge: + %14 = load i64, i64* %7 + %16 = mul i64 %14, 30 + ret i64 %16 +then: + %10 = load i64, i64* %7 + %11 = sub i64 %10, 10 + store i64 %11, i64* %7 + br label %merge +} + diff --git a/hw3/llprograms/analysis11.ll b/hw3/llprograms/analysis11.ll new file mode 100644 index 0000000..e2dd5c9 --- /dev/null +++ b/hw3/llprograms/analysis11.ll @@ -0,0 +1,18 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 0, 1 + %2 = add i64 0, 2 + %3 = add i64 %1, %2 + ret i64 %3 + +foo: + %4 = alloca i64 + store i64 1, i64* %4 + %5 = alloca i64 + store i64 2, i64* %5 + %6 = load i64, i64* %4 + %7 = load i64, i64* %5 + %8 = add i64 %6, %7 + %9 = add i64 %8, 10 + ret i64 %9 +} + diff --git a/hw3/llprograms/analysis11_cf_opt.ll b/hw3/llprograms/analysis11_cf_opt.ll new file mode 100644 index 0000000..27a4c3f --- /dev/null +++ b/hw3/llprograms/analysis11_cf_opt.ll @@ -0,0 +1,17 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 0, 1 + %2 = add i64 0, 2 + %3 = add i64 1, 2 + ret i64 3 +foo: + %4 = alloca i64 + store i64 1, i64* %4 + %5 = alloca i64 + store i64 2, i64* %5 + %6 = load i64, i64* %4 + %7 = load i64, i64* %5 + %8 = add i64 %6, %7 + %9 = add i64 %8, 10 + ret i64 %9 +} + diff --git a/hw3/llprograms/analysis11_dce_opt.ll b/hw3/llprograms/analysis11_dce_opt.ll new file mode 100644 index 0000000..d507937 --- /dev/null +++ b/hw3/llprograms/analysis11_dce_opt.ll @@ -0,0 +1,14 @@ +define i64 @program(i64 %argc, i8** %argv) { + ret i64 3 +foo: + %4 = alloca i64 + store i64 1, i64* %4 + %5 = alloca i64 + store i64 2, i64* %5 + %6 = load i64, i64* %4 + %7 = load i64, i64* %5 + %8 = add i64 %6, %7 + %9 = add i64 %8, 10 + ret i64 %9 +} + diff --git a/hw3/llprograms/analysis12.ll b/hw3/llprograms/analysis12.ll new file mode 100644 index 0000000..6644bbb --- /dev/null +++ b/hw3/llprograms/analysis12.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = sub i64 %1, 15 + %3 = mul i64 %2, %2 + %4 = shl i64 %3, 1 + %5 = lshr i64 %4, %1 + %6 = ashr i64 %5, 3 + %7 = and i64 %2, %1 + %8 = or i64 %5, %7 + %9 = xor i64 %1, %5 + ret i64 %9 +} + diff --git a/hw3/llprograms/analysis12_cf_opt.ll b/hw3/llprograms/analysis12_cf_opt.ll new file mode 100644 index 0000000..d81a195 --- /dev/null +++ b/hw3/llprograms/analysis12_cf_opt.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = sub i64 14, 15 + %3 = mul i64 -1, -1 + %4 = shl i64 1, 1 + %5 = lshr i64 2, 14 + %6 = ashr i64 0, 3 + %7 = and i64 -1, 14 + %8 = or i64 0, 14 + %9 = xor i64 14, 0 + ret i64 14 +} + diff --git a/hw3/llprograms/analysis12_dce_opt.ll b/hw3/llprograms/analysis12_dce_opt.ll new file mode 100644 index 0000000..23cdedb --- /dev/null +++ b/hw3/llprograms/analysis12_dce_opt.ll @@ -0,0 +1,4 @@ +define i64 @program(i64 %argc, i8** %arcv) { + ret i64 14 +} + diff --git a/hw3/llprograms/analysis13.ll b/hw3/llprograms/analysis13.ll new file mode 100644 index 0000000..c1417ab --- /dev/null +++ b/hw3/llprograms/analysis13.ll @@ -0,0 +1,31 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 0, 0 + %2 = add i64 0, 1 + %3 = add i64 0, 2 + %4 = add i64 0, 3 + %5 = add i64 0, 4 + %6 = add i64 0, 5 + %7 = add i64 0, 7 + %cmp1 = icmp sgt i64 3, 0 + br i1 %cmp1, label %one, label %wrong +one: + %cmp2 = icmp eq i64 1, %2 + br i1 %cmp2, label %two, label %wrong +two: + %cmp3 = icmp ne i64 %3, 3 + br i1 %cmp3, label %three, label %wrong +three: + %cmp4 = icmp slt i64 %4, 4 + br i1 %cmp4, label %four, label %wrong +four: + %cmp5 = icmp sle i64 %5, 10 + br i1 %cmp5, label %five, label %wrong +five: + %cmp6 = icmp sge i64 10, %6 + br i1 %cmp6, label %correct, label %wrong +correct: + ret i64 %7 +wrong: + ret i64 %1 +} + diff --git a/hw3/llprograms/analysis13_cf_opt.ll b/hw3/llprograms/analysis13_cf_opt.ll new file mode 100644 index 0000000..f79b7db --- /dev/null +++ b/hw3/llprograms/analysis13_cf_opt.ll @@ -0,0 +1,31 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 0, 0 + %2 = add i64 0, 1 + %3 = add i64 0, 2 + %4 = add i64 0, 3 + %5 = add i64 0, 4 + %6 = add i64 0, 5 + %7 = add i64 0, 7 + %cmp1 = icmp sgt i64 3, 0 + br i1 1, label %one, label %wrong +correct: + ret i64 7 +five: + %cmp6 = icmp sge i64 10, 5 + br i1 1, label %correct, label %wrong +four: + %cmp5 = icmp sle i64 4, 10 + br i1 1, label %five, label %wrong +one: + %cmp2 = icmp eq i64 1, 1 + br i1 1, label %two, label %wrong +three: + %cmp4 = icmp slt i64 3, 4 + br i1 1, label %four, label %wrong +two: + %cmp3 = icmp ne i64 2, 3 + br i1 1, label %three, label %wrong +wrong: + ret i64 0 +} + diff --git a/hw3/llprograms/analysis13_dce_opt.ll b/hw3/llprograms/analysis13_dce_opt.ll new file mode 100644 index 0000000..069f538 --- /dev/null +++ b/hw3/llprograms/analysis13_dce_opt.ll @@ -0,0 +1,18 @@ +define i64 @program(i64 %argc, i8** %arcv) { + br i1 1, label %one, label %wrong +correct: + ret i64 7 +five: + br i1 1, label %correct, label %wrong +four: + br i1 1, label %five, label %wrong +one: + br i1 1, label %two, label %wrong +three: + br i1 1, label %four, label %wrong +two: + br i1 1, label %three, label %wrong +wrong: + ret i64 0 +} + diff --git a/hw3/llprograms/analysis14.ll b/hw3/llprograms/analysis14.ll new file mode 100644 index 0000000..5758d8b --- /dev/null +++ b/hw3/llprograms/analysis14.ll @@ -0,0 +1,8 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = bitcast i64* %1 to i8* + %3 = mul i64 1, 2 + %4 = icmp slt i64 2, %3 + ret i64 42 +} + diff --git a/hw3/llprograms/analysis14_cf_opt.ll b/hw3/llprograms/analysis14_cf_opt.ll new file mode 100644 index 0000000..edc56e6 --- /dev/null +++ b/hw3/llprograms/analysis14_cf_opt.ll @@ -0,0 +1,8 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = bitcast i64* %1 to i8* + %3 = mul i64 1, 2 + %4 = icmp slt i64 2, 2 + ret i64 42 +} + diff --git a/hw3/llprograms/analysis14_dce_opt.ll b/hw3/llprograms/analysis14_dce_opt.ll new file mode 100644 index 0000000..fa93007 --- /dev/null +++ b/hw3/llprograms/analysis14_dce_opt.ll @@ -0,0 +1,5 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + ret i64 42 +} + diff --git a/hw3/llprograms/analysis15.ll b/hw3/llprograms/analysis15.ll new file mode 100644 index 0000000..34828a2 --- /dev/null +++ b/hw3/llprograms/analysis15.ll @@ -0,0 +1,18 @@ +%node = type { i64, %node* } + +@hd = global %node { i64 1, %node* @md } +@md = global %node { i64 2, %node* @tl } +@tl = global %node { i64 3, %node* null } + +define i64 @program(i64 %argc, i8** %arcv) { + %head = getelementptr %node, %node* @hd, i32 0, i32 0 + %link = getelementptr %node, %node* @hd, i32 0, i32 1 + %next = load %node*, %node** %link + %val = getelementptr %node, %node* %next, i32 0, i32 0 + %link2 = getelementptr %node, %node* %next, i32 0, i32 1 + %next2 = load %node*, %node** %link2 + %val2 = getelementptr %node, %node* %next2, i32 0, i32 0 + %1 = load i64, i64* %val + ret i64 %1 +} + diff --git a/hw3/llprograms/analysis15_cf_opt.ll b/hw3/llprograms/analysis15_cf_opt.ll new file mode 100644 index 0000000..34828a2 --- /dev/null +++ b/hw3/llprograms/analysis15_cf_opt.ll @@ -0,0 +1,18 @@ +%node = type { i64, %node* } + +@hd = global %node { i64 1, %node* @md } +@md = global %node { i64 2, %node* @tl } +@tl = global %node { i64 3, %node* null } + +define i64 @program(i64 %argc, i8** %arcv) { + %head = getelementptr %node, %node* @hd, i32 0, i32 0 + %link = getelementptr %node, %node* @hd, i32 0, i32 1 + %next = load %node*, %node** %link + %val = getelementptr %node, %node* %next, i32 0, i32 0 + %link2 = getelementptr %node, %node* %next, i32 0, i32 1 + %next2 = load %node*, %node** %link2 + %val2 = getelementptr %node, %node* %next2, i32 0, i32 0 + %1 = load i64, i64* %val + ret i64 %1 +} + diff --git a/hw3/llprograms/analysis15_dce_opt.ll b/hw3/llprograms/analysis15_dce_opt.ll new file mode 100644 index 0000000..cd7139a --- /dev/null +++ b/hw3/llprograms/analysis15_dce_opt.ll @@ -0,0 +1,16 @@ +%node = type { i64, %node* } + +@hd = global %node { i64 1, %node* @md } +@md = global %node { i64 2, %node* @tl } +@tl = global %node { i64 3, %node* null } + +define i64 @program(i64 %argc, i8** %arcv) { + %link = getelementptr %node, %node* @hd, i32 0, i32 1 + %next = load %node*, %node** %link + %val = getelementptr %node, %node* %next, i32 0, i32 0 + %link2 = getelementptr %node, %node* %next, i32 0, i32 1 + %next2 = load %node*, %node** %link2 + %1 = load i64, i64* %val + ret i64 %1 +} + diff --git a/hw3/llprograms/analysis16.ll b/hw3/llprograms/analysis16.ll new file mode 100644 index 0000000..57c77cd --- /dev/null +++ b/hw3/llprograms/analysis16.ll @@ -0,0 +1,40 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = alloca i64 + store i64 6, i64* %1 + store i64 7, i64* %2 + br label %foo + +foo: + %3 = load i64, i64* %1 + %4 = icmp eq i64 0, %3 + br i1 %4, label %retb, label %loop + +loop: + %5 = load i64, i64* %2 + %6 = icmp eq i64 0, %5 + br i1 %6, label %reta, label %continue_loop + +continue_loop: + %7 = load i64, i64* %1 + %8 = icmp sgt i64 %7, %5 + br i1 %8, label %if, label %else + +if: + %9 = sub i64 %7, %5 + store i64 %9, i64* %1 + br label %loop + +else: + %10 = sub i64 %5, %7 + store i64 %10, i64* %2 + br label %loop + +reta: + %11 = load i64, i64* %1 + ret i64 %11 + +retb: + %12 = load i64, i64* %2 + ret i64 %12 +} diff --git a/hw3/llprograms/analysis16_cf_opt.ll b/hw3/llprograms/analysis16_cf_opt.ll new file mode 100644 index 0000000..17f23b4 --- /dev/null +++ b/hw3/llprograms/analysis16_cf_opt.ll @@ -0,0 +1,34 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = alloca i64 + store i64 6, i64* %1 + store i64 7, i64* %2 + br label %foo +continue_loop: + %7 = load i64, i64* %1 + %8 = icmp sgt i64 %7, %5 + br i1 %8, label %if, label %else +else: + %10 = sub i64 %5, %7 + store i64 %10, i64* %2 + br label %loop +foo: + %3 = load i64, i64* %1 + %4 = icmp eq i64 0, %3 + br i1 %4, label %retb, label %loop +if: + %9 = sub i64 %7, %5 + store i64 %9, i64* %1 + br label %loop +loop: + %5 = load i64, i64* %2 + %6 = icmp eq i64 0, %5 + br i1 %6, label %reta, label %continue_loop +reta: + %11 = load i64, i64* %1 + ret i64 %11 +retb: + %12 = load i64, i64* %2 + ret i64 %12 +} + diff --git a/hw3/llprograms/analysis16_dce_opt.ll b/hw3/llprograms/analysis16_dce_opt.ll new file mode 100644 index 0000000..17f23b4 --- /dev/null +++ b/hw3/llprograms/analysis16_dce_opt.ll @@ -0,0 +1,34 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = alloca i64 + store i64 6, i64* %1 + store i64 7, i64* %2 + br label %foo +continue_loop: + %7 = load i64, i64* %1 + %8 = icmp sgt i64 %7, %5 + br i1 %8, label %if, label %else +else: + %10 = sub i64 %5, %7 + store i64 %10, i64* %2 + br label %loop +foo: + %3 = load i64, i64* %1 + %4 = icmp eq i64 0, %3 + br i1 %4, label %retb, label %loop +if: + %9 = sub i64 %7, %5 + store i64 %9, i64* %1 + br label %loop +loop: + %5 = load i64, i64* %2 + %6 = icmp eq i64 0, %5 + br i1 %6, label %reta, label %continue_loop +reta: + %11 = load i64, i64* %1 + ret i64 %11 +retb: + %12 = load i64, i64* %2 + ret i64 %12 +} + diff --git a/hw3/llprograms/analysis17.ll b/hw3/llprograms/analysis17.ll new file mode 100644 index 0000000..af31436 --- /dev/null +++ b/hw3/llprograms/analysis17.ll @@ -0,0 +1,19 @@ +define i64 @program(i64 %x, i64 %y) { + %sx = alloca i64 + store i64 %x, i64* %sx + %sy = alloca i64 + store i64 %y, i64* %sy + %i1 = add i64 0, 2 + %i2 = add i64 0, 3 + %v1 = add i64 %x, %y + %v2 = sub i64 %v1, %i1 + %v3 = mul i64 %v2, %i2 + br label %l1 + +l1: + %a1 = alloca i64 + store i64 0, i64* %a1 + %arg1 = add i64 0, 12 + %v4 = call i64 @foo(i64 %arg1, i64 2) + ret i64 %v3 +} diff --git a/hw3/llprograms/analysis17_cf_opt.ll b/hw3/llprograms/analysis17_cf_opt.ll new file mode 100644 index 0000000..6a4c124 --- /dev/null +++ b/hw3/llprograms/analysis17_cf_opt.ll @@ -0,0 +1,19 @@ +define i64 @program(i64 %x, i64 %y) { + %sx = alloca i64 + store i64 %x, i64* %sx + %sy = alloca i64 + store i64 %y, i64* %sy + %i1 = add i64 0, 2 + %i2 = add i64 0, 3 + %v1 = add i64 %x, %y + %v2 = sub i64 %v1, 2 + %v3 = mul i64 %v2, 3 + br label %l1 +l1: + %a1 = alloca i64 + store i64 0, i64* %a1 + %arg1 = add i64 0, 12 + %v4 = call i64 @foo(i64 12, i64 2) + ret i64 %v3 +} + diff --git a/hw3/llprograms/analysis17_dce_opt.ll b/hw3/llprograms/analysis17_dce_opt.ll new file mode 100644 index 0000000..189147b --- /dev/null +++ b/hw3/llprograms/analysis17_dce_opt.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %x, i64 %y) { + %sx = alloca i64 + %sy = alloca i64 + %v1 = add i64 %x, %y + %v2 = sub i64 %v1, 2 + %v3 = mul i64 %v2, 3 + br label %l1 +l1: + %a1 = alloca i64 + %v4 = call i64 @foo(i64 12, i64 2) + ret i64 %v3 +} + diff --git a/hw3/llprograms/analysis18.ll b/hw3/llprograms/analysis18.ll new file mode 100644 index 0000000..b457be7 --- /dev/null +++ b/hw3/llprograms/analysis18.ll @@ -0,0 +1,24 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = add i64 5, 9 + %3 = mul i64 3, %2 + %4 = sub i64 %3, 2 + br label %bar +bar: + %sa = alloca i64 + %sb = alloca i64 + %sc = alloca i64 + store i64 %2, i64* %sa + store i64 %3, i64* %sb + store i64 %4, i64* %sb + br label %foo +foo: + %v1 = load i64, i64* %sa + %v2 = load i64, i64* %sa + %v3 = load i64, i64* %sa + %v4 = add i64 %v1, %v2 + %res = add i64 %v4, %v3 + store i64 %res, i64* %1 + ret i64 %res +} + diff --git a/hw3/llprograms/analysis18_cf_opt.ll b/hw3/llprograms/analysis18_cf_opt.ll new file mode 100644 index 0000000..5564a61 --- /dev/null +++ b/hw3/llprograms/analysis18_cf_opt.ll @@ -0,0 +1,24 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = add i64 5, 9 + %3 = mul i64 3, 14 + %4 = sub i64 42, 2 + br label %bar +bar: + %sa = alloca i64 + %sb = alloca i64 + %sc = alloca i64 + store i64 14, i64* %sa + store i64 42, i64* %sb + store i64 40, i64* %sb + br label %foo +foo: + %v1 = load i64, i64* %sa + %v2 = load i64, i64* %sa + %v3 = load i64, i64* %sa + %v4 = add i64 %v1, %v2 + %res = add i64 %v4, %v3 + store i64 %res, i64* %1 + ret i64 %res +} + diff --git a/hw3/llprograms/analysis18_dce_opt.ll b/hw3/llprograms/analysis18_dce_opt.ll new file mode 100644 index 0000000..9a09371 --- /dev/null +++ b/hw3/llprograms/analysis18_dce_opt.ll @@ -0,0 +1,18 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + br label %bar +bar: + %sa = alloca i64 + %sb = alloca i64 + store i64 14, i64* %sa + store i64 42, i64* %sb + br label %foo +foo: + %v1 = load i64, i64* %sa + %v2 = load i64, i64* %sa + %v3 = load i64, i64* %sa + %v4 = add i64 %v1, %v2 + %res = add i64 %v4, %v3 + ret i64 %res +} + diff --git a/hw3/llprograms/analysis19.ll b/hw3/llprograms/analysis19.ll new file mode 100644 index 0000000..e00f40f --- /dev/null +++ b/hw3/llprograms/analysis19.ll @@ -0,0 +1,11 @@ +%arr = type [5 x i64] + +@tmp = global %arr [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = getelementptr %arr, %arr* @tmp, i32 0, i32 3 + %3 = load i64, i64* %1 + ret i64 5 +} + diff --git a/hw3/llprograms/analysis19_cf_opt.ll b/hw3/llprograms/analysis19_cf_opt.ll new file mode 100644 index 0000000..e00f40f --- /dev/null +++ b/hw3/llprograms/analysis19_cf_opt.ll @@ -0,0 +1,11 @@ +%arr = type [5 x i64] + +@tmp = global %arr [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = getelementptr %arr, %arr* @tmp, i32 0, i32 3 + %3 = load i64, i64* %1 + ret i64 5 +} + diff --git a/hw3/llprograms/analysis19_dce_opt.ll b/hw3/llprograms/analysis19_dce_opt.ll new file mode 100644 index 0000000..572127c --- /dev/null +++ b/hw3/llprograms/analysis19_dce_opt.ll @@ -0,0 +1,9 @@ +%arr = type [5 x i64] + +@tmp = global %arr [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + ret i64 5 +} + diff --git a/hw3/llprograms/analysis1_cf_opt.ll b/hw3/llprograms/analysis1_cf_opt.ll new file mode 100644 index 0000000..39d9d9a --- /dev/null +++ b/hw3/llprograms/analysis1_cf_opt.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + br label %l1 +l1: + %4 = bitcast i64* %3 to i8* + ret i64 49 +} + diff --git a/hw3/llprograms/analysis1_dce_opt.ll b/hw3/llprograms/analysis1_dce_opt.ll new file mode 100644 index 0000000..2b8c08c --- /dev/null +++ b/hw3/llprograms/analysis1_dce_opt.ll @@ -0,0 +1,7 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %3 = alloca i64 + br label %l1 +l1: + ret i64 49 +} + diff --git a/hw3/llprograms/analysis2.ll b/hw3/llprograms/analysis2.ll new file mode 100644 index 0000000..28107a7 --- /dev/null +++ b/hw3/llprograms/analysis2.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + %4 = icmp eq i64 0, %1 + br i1 %4, label %l1, label %l2 +l1: + %5 = bitcast i64* %3 to i8* + ret i64 %1 +l2: + ret i64 8 +} + diff --git a/hw3/llprograms/analysis2_cf_opt.ll b/hw3/llprograms/analysis2_cf_opt.ll new file mode 100644 index 0000000..8612b3b --- /dev/null +++ b/hw3/llprograms/analysis2_cf_opt.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + %4 = icmp eq i64 0, 49 + br i1 0, label %l1, label %l2 +l1: + %5 = bitcast i64* %3 to i8* + ret i64 49 +l2: + ret i64 8 +} + diff --git a/hw3/llprograms/analysis2_dce_opt.ll b/hw3/llprograms/analysis2_dce_opt.ll new file mode 100644 index 0000000..a61d6b6 --- /dev/null +++ b/hw3/llprograms/analysis2_dce_opt.ll @@ -0,0 +1,9 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %3 = alloca i64 + br i1 0, label %l1, label %l2 +l1: + ret i64 49 +l2: + ret i64 8 +} + diff --git a/hw3/llprograms/analysis3.ll b/hw3/llprograms/analysis3.ll new file mode 100644 index 0000000..0cfbf69 --- /dev/null +++ b/hw3/llprograms/analysis3.ll @@ -0,0 +1,31 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 7, 7 + br label %l2 +l2: + %2 = mul i64 2, %1 + br label %l3 +l3: + %3 = sub i64 %2, 32 + br label %l4 +l4: + %4 = shl i64 %3, 1 + br label %l5 +l5: + %5 = lshr i64 %4, 60 + br label %l6 +l6: + %6 = ashr i64 %5, 2 + br label %l7 +l7: + %7 = and i64 255, %6 + br label %l8 +l8: + %8 = or i64 64, %7 + br label %l9 +l9: + %9 = xor i64 %8, 255 + br label %lexit +lexit: + ret i64 %9 +} + diff --git a/hw3/llprograms/analysis3_cf_opt.ll b/hw3/llprograms/analysis3_cf_opt.ll new file mode 100644 index 0000000..9e77cce --- /dev/null +++ b/hw3/llprograms/analysis3_cf_opt.ll @@ -0,0 +1,31 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 7, 7 + br label %l2 +l2: + %2 = mul i64 2, 14 + br label %l3 +l3: + %3 = sub i64 28, 32 + br label %l4 +l4: + %4 = shl i64 -4, 1 + br label %l5 +l5: + %5 = lshr i64 -8, 60 + br label %l6 +l6: + %6 = ashr i64 15, 2 + br label %l7 +l7: + %7 = and i64 255, 3 + br label %l8 +l8: + %8 = or i64 64, 3 + br label %l9 +l9: + %9 = xor i64 67, 255 + br label %lexit +lexit: + ret i64 188 +} + diff --git a/hw3/llprograms/analysis3_dce_opt.ll b/hw3/llprograms/analysis3_dce_opt.ll new file mode 100644 index 0000000..bb98a0a --- /dev/null +++ b/hw3/llprograms/analysis3_dce_opt.ll @@ -0,0 +1,22 @@ +define i64 @program(i64 %argc, i8** %arcv) { + br label %l2 +l2: + br label %l3 +l3: + br label %l4 +l4: + br label %l5 +l5: + br label %l6 +l6: + br label %l7 +l7: + br label %l8 +l8: + br label %l9 +l9: + br label %lexit +lexit: + ret i64 188 +} + diff --git a/hw3/llprograms/analysis4.ll b/hw3/llprograms/analysis4.ll new file mode 100644 index 0000000..9b97230 --- /dev/null +++ b/hw3/llprograms/analysis4.ll @@ -0,0 +1,20 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + store i64 %1, i64* %3 + br label %l1 +l1: + %4 = icmp sle i64 64, %2 + %5 = load i64, i64* %3 + %6 = bitcast i64* %3 to i8* + %7 = getelementptr i8, i8* %6, i32 0 + %8 = sub i64 %5, 3 + store i64 %8, i64* %3 + %9 = icmp sgt i64 %8, 0 + br i1 %9, label %l1, label %l2 +l2: + %10 = load i64, i64* %3 + ret i64 %10 +} + diff --git a/hw3/llprograms/analysis4_cf_opt.ll b/hw3/llprograms/analysis4_cf_opt.ll new file mode 100644 index 0000000..89fe0a1 --- /dev/null +++ b/hw3/llprograms/analysis4_cf_opt.ll @@ -0,0 +1,20 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + store i64 49, i64* %3 + br label %l1 +l1: + %4 = icmp sle i64 64, %2 + %5 = load i64, i64* %3 + %6 = bitcast i64* %3 to i8* + %7 = getelementptr i8, i8* %6, i32 0 + %8 = sub i64 %5, 3 + store i64 %8, i64* %3 + %9 = icmp sgt i64 %8, 0 + br i1 %9, label %l1, label %l2 +l2: + %10 = load i64, i64* %3 + ret i64 %10 +} + diff --git a/hw3/llprograms/analysis4_dce_opt.ll b/hw3/llprograms/analysis4_dce_opt.ll new file mode 100644 index 0000000..570d406 --- /dev/null +++ b/hw3/llprograms/analysis4_dce_opt.ll @@ -0,0 +1,17 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %2 = add i64 42, %argc + %3 = alloca i64 + store i64 49, i64* %3 + br label %l1 +l1: + %5 = load i64, i64* %3 + %6 = bitcast i64* %3 to i8* + %8 = sub i64 %5, 3 + store i64 %8, i64* %3 + %9 = icmp sgt i64 %8, 0 + br i1 %9, label %l1, label %l2 +l2: + %10 = load i64, i64* %3 + ret i64 %10 +} + diff --git a/hw3/llprograms/analysis5.ll b/hw3/llprograms/analysis5.ll new file mode 100644 index 0000000..e6a57d5 --- /dev/null +++ b/hw3/llprograms/analysis5.ll @@ -0,0 +1,7 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 5, 2 + %2 = add i64 2, 5 + %3 = mul i64 %1, 2 + ret i64 %3 +} + diff --git a/hw3/llprograms/analysis5_cf_opt.ll b/hw3/llprograms/analysis5_cf_opt.ll new file mode 100644 index 0000000..eb0adae --- /dev/null +++ b/hw3/llprograms/analysis5_cf_opt.ll @@ -0,0 +1,7 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 5, 2 + %2 = add i64 2, 5 + %3 = mul i64 7, 2 + ret i64 14 +} + diff --git a/hw3/llprograms/analysis5_dce_opt.ll b/hw3/llprograms/analysis5_dce_opt.ll new file mode 100644 index 0000000..a704f22 --- /dev/null +++ b/hw3/llprograms/analysis5_dce_opt.ll @@ -0,0 +1,4 @@ +define i64 @program(i64 %argc, i8** %argv) { + ret i64 14 +} + diff --git a/hw3/llprograms/analysis6.ll b/hw3/llprograms/analysis6.ll new file mode 100644 index 0000000..efd68c3 --- /dev/null +++ b/hw3/llprograms/analysis6.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 2, 0 + %2 = add i64 3, 0 + %3 = add i64 4, 0 + br i1 0, label %then, label %else +then: + ret i64 %1 +else: + %4 = sub i64 %3, %2 + br i1 %4, label %then, label %merge +merge: + ret i64 %3 +} diff --git a/hw3/llprograms/analysis6_cf_opt.ll b/hw3/llprograms/analysis6_cf_opt.ll new file mode 100644 index 0000000..2c65ca2 --- /dev/null +++ b/hw3/llprograms/analysis6_cf_opt.ll @@ -0,0 +1,14 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 2, 0 + %2 = add i64 3, 0 + %3 = add i64 4, 0 + br i1 0, label %then, label %else +else: + %4 = sub i64 4, 3 + br i1 1, label %then, label %merge +merge: + ret i64 4 +then: + ret i64 2 +} + diff --git a/hw3/llprograms/analysis6_dce_opt.ll b/hw3/llprograms/analysis6_dce_opt.ll new file mode 100644 index 0000000..d85fe9f --- /dev/null +++ b/hw3/llprograms/analysis6_dce_opt.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %argv) { + br i1 0, label %then, label %else +else: + br i1 1, label %then, label %merge +merge: + ret i64 4 +then: + ret i64 2 +} + diff --git a/hw3/llprograms/analysis7.ll b/hw3/llprograms/analysis7.ll new file mode 100644 index 0000000..2778021 --- /dev/null +++ b/hw3/llprograms/analysis7.ll @@ -0,0 +1,21 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 10, 0 + %2 = alloca i64 + store i64 %1, i64* %2 + %3 = add i64 1, 0 + %4 = alloca i64 + store i64 %3, i64* %4 + br label %guard +guard: + %5 = load i64, i64* %4 + %6 = icmp slt i64 %5, %1 + br i1 %6, label %body, label %end +body: + %7 = load i64, i64* %4 + %8 = mul i64 %7, 2 + store i64 %8, i64* %4 + br label %guard +end: + ret i64 %1 +} + diff --git a/hw3/llprograms/analysis7_cf_opt.ll b/hw3/llprograms/analysis7_cf_opt.ll new file mode 100644 index 0000000..c074c9d --- /dev/null +++ b/hw3/llprograms/analysis7_cf_opt.ll @@ -0,0 +1,21 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 10, 0 + %2 = alloca i64 + store i64 10, i64* %2 + %3 = add i64 1, 0 + %4 = alloca i64 + store i64 1, i64* %4 + br label %guard +body: + %7 = load i64, i64* %4 + %8 = mul i64 %7, 2 + store i64 %8, i64* %4 + br label %guard +end: + ret i64 10 +guard: + %5 = load i64, i64* %4 + %6 = icmp slt i64 %5, 10 + br i1 %6, label %body, label %end +} + diff --git a/hw3/llprograms/analysis7_dce_opt.ll b/hw3/llprograms/analysis7_dce_opt.ll new file mode 100644 index 0000000..b26f4c1 --- /dev/null +++ b/hw3/llprograms/analysis7_dce_opt.ll @@ -0,0 +1,18 @@ +define i64 @program(i64 %argc, i8** %argv) { + %2 = alloca i64 + %4 = alloca i64 + store i64 1, i64* %4 + br label %guard +body: + %7 = load i64, i64* %4 + %8 = mul i64 %7, 2 + store i64 %8, i64* %4 + br label %guard +end: + ret i64 10 +guard: + %5 = load i64, i64* %4 + %6 = icmp slt i64 %5, 10 + br i1 %6, label %body, label %end +} + diff --git a/hw3/llprograms/analysis8.ll b/hw3/llprograms/analysis8.ll new file mode 100644 index 0000000..abc9f0b --- /dev/null +++ b/hw3/llprograms/analysis8.ll @@ -0,0 +1,33 @@ +define i64 @program(i64 %argc, i8** %argv) { + %a = add i64 1, 0 + %b = add i64 2, %a + %c = add i64 3, %b + %d = add i64 4, %c + %e = add i64 5, %d + %f = add i64 6, %e + %g = add i64 7, %f + %h = add i64 8, %g + %i = add i64 9, %h + %j = add i64 10, %i + %k = add i64 11, %j + %l = add i64 12, %k + %m = add i64 13, %l + %tmp1 = alloca i64 + store i64 %m, i64* %tmp1 + %tmp2 = load i64, i64* %tmp1 + %n = add i64 14, %tmp2 + %o = add i64 15, %n + %p = add i64 16, %o + %q = add i64 17, %p + %r = add i64 18, %q + %s = add i64 19, %r + %t = add i64 20, %s + %u = add i64 21, %t + %v = add i64 22, %u + %w = add i64 23, %v + %x = add i64 24, %w + %y = add i64 25, %x + %z = add i64 26, %y + ret i64 %z +} + diff --git a/hw3/llprograms/analysis8_cf_opt.ll b/hw3/llprograms/analysis8_cf_opt.ll new file mode 100644 index 0000000..48171fc --- /dev/null +++ b/hw3/llprograms/analysis8_cf_opt.ll @@ -0,0 +1,33 @@ +define i64 @program(i64 %argc, i8** %argv) { + %a = add i64 1, 0 + %b = add i64 2, 1 + %c = add i64 3, 3 + %d = add i64 4, 6 + %e = add i64 5, 10 + %f = add i64 6, 15 + %g = add i64 7, 21 + %h = add i64 8, 28 + %i = add i64 9, 36 + %j = add i64 10, 45 + %k = add i64 11, 55 + %l = add i64 12, 66 + %m = add i64 13, 78 + %tmp1 = alloca i64 + store i64 91, i64* %tmp1 + %tmp2 = load i64, i64* %tmp1 + %n = add i64 14, %tmp2 + %o = add i64 15, %n + %p = add i64 16, %o + %q = add i64 17, %p + %r = add i64 18, %q + %s = add i64 19, %r + %t = add i64 20, %s + %u = add i64 21, %t + %v = add i64 22, %u + %w = add i64 23, %v + %x = add i64 24, %w + %y = add i64 25, %x + %z = add i64 26, %y + ret i64 %z +} + diff --git a/hw3/llprograms/analysis8_dce_opt.ll b/hw3/llprograms/analysis8_dce_opt.ll new file mode 100644 index 0000000..6e47a26 --- /dev/null +++ b/hw3/llprograms/analysis8_dce_opt.ll @@ -0,0 +1,20 @@ +define i64 @program(i64 %argc, i8** %argv) { + %tmp1 = alloca i64 + store i64 91, i64* %tmp1 + %tmp2 = load i64, i64* %tmp1 + %n = add i64 14, %tmp2 + %o = add i64 15, %n + %p = add i64 16, %o + %q = add i64 17, %p + %r = add i64 18, %q + %s = add i64 19, %r + %t = add i64 20, %s + %u = add i64 21, %t + %v = add i64 22, %u + %w = add i64 23, %v + %x = add i64 24, %w + %y = add i64 25, %x + %z = add i64 26, %y + ret i64 %z +} + diff --git a/hw3/llprograms/analysis9.ll b/hw3/llprograms/analysis9.ll new file mode 100644 index 0000000..b642407 --- /dev/null +++ b/hw3/llprograms/analysis9.ll @@ -0,0 +1,27 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = alloca i64 + store i64 5, i64* %1 + %2 = alloca i64 + store i64 1, i64* %2 + %d0 = add i64 0, 1 + br label %guard +guard: + %3 = load i64, i64* %2 + %4 = icmp sle i64 %3, 10 + %d1 = add i64 %d0, 4 + br i1 %4, label %body, label %end +body: + %5 = load i64, i64* %2 + %6 = load i64, i64* %1 + %d2 = add i64 %d1, 6 + %7 = mul i64 %5, %6 + store i64 %7, i64* %1 + %8 = load i64, i64* %2 + %9 = add i64 %8, 1 + store i64 %9, i64* %2 + br label %guard +end: + %10 = load i64, i64* %1 + ret i64 %10 +} + diff --git a/hw3/llprograms/analysis9_cf_opt.ll b/hw3/llprograms/analysis9_cf_opt.ll new file mode 100644 index 0000000..60f889e --- /dev/null +++ b/hw3/llprograms/analysis9_cf_opt.ll @@ -0,0 +1,27 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = alloca i64 + store i64 5, i64* %1 + %2 = alloca i64 + store i64 1, i64* %2 + %d0 = add i64 0, 1 + br label %guard +body: + %5 = load i64, i64* %2 + %6 = load i64, i64* %1 + %d2 = add i64 5, 6 + %7 = mul i64 %5, %6 + store i64 %7, i64* %1 + %8 = load i64, i64* %2 + %9 = add i64 %8, 1 + store i64 %9, i64* %2 + br label %guard +end: + %10 = load i64, i64* %1 + ret i64 %10 +guard: + %3 = load i64, i64* %2 + %4 = icmp sle i64 %3, 10 + %d1 = add i64 1, 4 + br i1 %4, label %body, label %end +} + diff --git a/hw3/llprograms/analysis9_dce_opt.ll b/hw3/llprograms/analysis9_dce_opt.ll new file mode 100644 index 0000000..b61e5b5 --- /dev/null +++ b/hw3/llprograms/analysis9_dce_opt.ll @@ -0,0 +1,24 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = alloca i64 + store i64 5, i64* %1 + %2 = alloca i64 + store i64 1, i64* %2 + br label %guard +body: + %5 = load i64, i64* %2 + %6 = load i64, i64* %1 + %7 = mul i64 %5, %6 + store i64 %7, i64* %1 + %8 = load i64, i64* %2 + %9 = add i64 %8, 1 + store i64 %9, i64* %2 + br label %guard +end: + %10 = load i64, i64* %1 + ret i64 %10 +guard: + %3 = load i64, i64* %2 + %4 = icmp sle i64 %3, 10 + br i1 %4, label %body, label %end +} + diff --git a/hw3/llprograms/and.ll b/hw3/llprograms/and.ll new file mode 100644 index 0000000..a0a9db3 --- /dev/null +++ b/hw3/llprograms/and.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = and i64 1, 0 + ret i64 %1 +} diff --git a/hw3/llprograms/args1.ll b/hw3/llprograms/args1.ll new file mode 100644 index 0000000..0adae1b --- /dev/null +++ b/hw3/llprograms/args1.ll @@ -0,0 +1,29 @@ +declare void @ll_puts(i8*) +declare i8* @ll_strcat(i8*, i8*) + +@toofew = global [9 x i8] c"argc < 3\00" +@toomany = global [9 x i8] c"argc > 3\00" + +define i64 @main(i64 %argc, i8** %argv) { + %lt = icmp slt i64 %argc, 3 + br i1 %lt, label %few, label %else +few: + %1 = getelementptr [9 x i8], [9 x i8]* @toofew, i32 0, i32 0 + call void @ll_puts(i8* %1) + ret i64 0 +else: + %gt = icmp sgt i64 %argc, 3 + br i1 %gt, label %many, label %right +many: + %2 = getelementptr [9 x i8], [9 x i8]* @toomany, i32 0, i32 0 + call void @ll_puts(i8* %2) + ret i64 0 +right: + %3 = getelementptr i8*, i8** %argv, i32 1 + %4 = load i8*, i8** %3 + %5 = getelementptr i8*, i8** %argv, i32 2 + %6 = load i8*, i8** %5 + %7 = call i8* @ll_strcat(i8* %4, i8* %6) + call void @ll_puts(i8* %7) + ret i64 0 +} diff --git a/hw3/llprograms/arith_combo.ll b/hw3/llprograms/arith_combo.ll new file mode 100644 index 0000000..bc2db51 --- /dev/null +++ b/hw3/llprograms/arith_combo.ll @@ -0,0 +1,7 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = mul i64 3, 6 + %3 = sub i64 %2, %1 + ret i64 %3 +} + diff --git a/hw3/llprograms/arith_combo_dce.ll b/hw3/llprograms/arith_combo_dce.ll new file mode 100644 index 0000000..7d3690a --- /dev/null +++ b/hw3/llprograms/arith_combo_dce.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + ret i64 4 +} + diff --git a/hw3/llprograms/arith_combo_fold.ll b/hw3/llprograms/arith_combo_fold.ll new file mode 100644 index 0000000..a3fef90 --- /dev/null +++ b/hw3/llprograms/arith_combo_fold.ll @@ -0,0 +1,7 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = mul i64 3, 6 + %3 = sub i64 18, 14 + ret i64 4 +} + diff --git a/hw3/llprograms/ashr.ll b/hw3/llprograms/ashr.ll new file mode 100644 index 0000000..11bdee3 --- /dev/null +++ b/hw3/llprograms/ashr.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = ashr i64 42, 3 + ret i64 %1 +} + diff --git a/hw3/llprograms/ashu_ian_opt.ll b/hw3/llprograms/ashu_ian_opt.ll new file mode 100644 index 0000000..dcbadf3 --- /dev/null +++ b/hw3/llprograms/ashu_ian_opt.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %arcv) { + br i1 1, label %then22, label %else21 +else21: + br label %merge20 +merge20: + ret i64 -1 +then22: + ret i64 5 +} + diff --git a/hw3/llprograms/binary_gcd.ll b/hw3/llprograms/binary_gcd.ll new file mode 100644 index 0000000..1b9e155 --- /dev/null +++ b/hw3/llprograms/binary_gcd.ll @@ -0,0 +1,62 @@ +define i64 @binary_gcd(i64 %u, i64 %v) { + %u_eq_v = icmp eq i64 %u, %v + br i1 %u_eq_v, label %ret_u, label %term1 +term1: + %u_0 = icmp eq i64 0, %u + br i1 %u_0, label %ret_v, label %term2 +term2: + %v_0 = icmp eq i64 0, %v + br i1 %v_0, label %ret_u, label %gcd +gcd: + %neg1 = sub i64 0, 1 + %1 = xor i64 %neg1, %u + %2 = and i64 1, %1 + %3 = icmp ne i64 0, %2 + br i1 %3, label %u_even, label %u_odd +u_odd: + %4 = xor i64 %neg1, %v + %5 = and i64 1, %4 + %6 = icmp ne i64 0, %5 + br i1 %6, label %v_even, label %v_odd +v_odd: + %7 = icmp sgt i64 %u, %v + br i1 %7, label %u_gt, label %v_gt +v_gt: + %8 = sub i64 %v, %u + %9 = lshr i64 %8, 1 + %10 = call i64 @binary_gcd(i64 %9, i64 %u) + ret i64 %10 +u_gt: + %11 = sub i64 %u, %v + %12 = lshr i64 %11, 1 + %13 = call i64 @binary_gcd(i64 %12, i64 %v) + ret i64 %13 +v_even: + %14 = lshr i64 %v, 1 + %15 = call i64 @binary_gcd(i64 %u, i64 %14) + ret i64 %15 +u_even: + %16 = and i64 %v, 1 + %17 = icmp ne i64 0, %16 + br i1 %17, label %ue_vo, label %both_even +ue_vo: + %18 = lshr i64 %u, 1 + %19 = call i64 @binary_gcd(i64 %18, i64 %v) + ret i64 %19 +both_even: + %20 = lshr i64 %u, 1 + %21 = lshr i64 %v, 1 + %22 = call i64 @binary_gcd(i64 %20, i64 %21) + %23 = shl i64 %22, 1 + ret i64 %23 +ret_u: + ret i64 %u +ret_v: + ret i64 %v +} + +define i64 @main(i64 %argc, i8** %argv) { + %1 = call i64 @binary_gcd(i64 21, i64 15) + ret i64 %1 +} + diff --git a/hw3/llprograms/binarysearch.ll b/hw3/llprograms/binarysearch.ll new file mode 100644 index 0000000..7fd7d58 --- /dev/null +++ b/hw3/llprograms/binarysearch.ll @@ -0,0 +1,74 @@ +%struct.Node = type { %struct.Node*, %struct.Node*, i64 } + +@node1 = global %struct.Node { %struct.Node* @node2, %struct.Node* @node3, i64 50 } +@node2 = global %struct.Node { %struct.Node* @node4, %struct.Node* @node5, i64 25 } +@node3 = global %struct.Node { %struct.Node* @node6, %struct.Node* @node7, i64 75 } +@node4 = global %struct.Node { %struct.Node* @node8, %struct.Node* null, i64 10 } +@node5 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 30 } +@node6 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 60 } +@node7 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 80 } +@node8 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 1 } + +define i64 @contains(%struct.Node* %root, i64 %value) { + %1 = getelementptr %struct.Node, %struct.Node* %root, i32 0, i32 2 + %2 = load i64, i64* %1 + %3 = icmp eq i64 %2, %value + br i1 %3, label %equal, label %notequal +equal: + ret i64 1 +notequal: + %4 = icmp sgt i64 %2, %value + br i1 %4, label %left, label %right +left: + %5 = getelementptr %struct.Node, %struct.Node* %root, i32 0, i32 0 + %6 = load %struct.Node*, %struct.Node** %5 + %7 = icmp eq %struct.Node* %6, null + br i1 %7, label %none, label %left_next +left_next: + %8 = call i64 @contains(%struct.Node* %6, i64 %value) + ret i64 %8 +right: + %9 = getelementptr %struct.Node, %struct.Node* %root, i32 0, i32 1 + %10 = load %struct.Node*, %struct.Node** %9 + %11 = icmp eq %struct.Node* %10, null + br i1 %11, label %none, label %right_next +right_next: + %12 = call i64 @contains(%struct.Node* %10, i64 %value) + ret i64 %12 +none: + ret i64 0 +} + +define i64 @main(i64 %argc, i8** %argv) { + %1 = add i64 50, 0 + %2 = add i64 25, 0 + %3 = add i64 75, 0 + %4 = add i64 10, 0 + %5 = add i64 30, 0 + %6 = add i64 60, 0 + %7 = add i64 80, 0 + %8 = add i64 1, 0 + %9 = add i64 100, 0 + %10 = add i64 120, 0 + %11 = call i64 @contains(%struct.Node* @node1, i64 %1) + %12 = call i64 @contains(%struct.Node* @node1, i64 %2) + %13 = call i64 @contains(%struct.Node* @node1, i64 %3) + %14 = call i64 @contains(%struct.Node* @node1, i64 %4) + %15 = call i64 @contains(%struct.Node* @node1, i64 %5) + %16 = call i64 @contains(%struct.Node* @node1, i64 %6) + %17 = call i64 @contains(%struct.Node* @node1, i64 %7) + %18 = call i64 @contains(%struct.Node* @node1, i64 %8) + %19 = call i64 @contains(%struct.Node* @node1, i64 %9) + %20 = call i64 @contains(%struct.Node* @node1, i64 %10) + %21 = add i64 %11, %12 + %22 = add i64 %13, %14 + %23 = add i64 %15, %16 + %24 = add i64 %17, %18 + %25 = add i64 %19, %20 + %26 = add i64 %21, %22 + %27 = add i64 %23, %24 + %28 = add i64 %26, %27 + %29 = add i64 %28, %25 + ret i64 %29 +} + diff --git a/hw3/llprograms/bitcast1.ll b/hw3/llprograms/bitcast1.ll new file mode 100644 index 0000000..b508167 --- /dev/null +++ b/hw3/llprograms/bitcast1.ll @@ -0,0 +1,9 @@ +define i64 @main(i64 %argc, i8** %argv) { + %1 = alloca i64 + store i64 3, i64* %1 + %2 = bitcast i64* %1 to [10 x i64]* + %3 = bitcast [10 x i64]* %2 to i64* + %4 = load i64, i64* %3 + ret i64 %4 +} + diff --git a/hw3/llprograms/br1.ll b/hw3/llprograms/br1.ll new file mode 100644 index 0000000..d3a81c8 --- /dev/null +++ b/hw3/llprograms/br1.ll @@ -0,0 +1,6 @@ +define i64 @main(i64 %argc, i8** %arcv) { + br label %end +end: + ret i64 9 +} + diff --git a/hw3/llprograms/br2.ll b/hw3/llprograms/br2.ll new file mode 100644 index 0000000..159e478 --- /dev/null +++ b/hw3/llprograms/br2.ll @@ -0,0 +1,9 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 12 + br label %next +next: + br label %end +end: + ret i64 %1 +} + diff --git a/hw3/llprograms/call.ll b/hw3/llprograms/call.ll new file mode 100644 index 0000000..92e025f --- /dev/null +++ b/hw3/llprograms/call.ll @@ -0,0 +1,9 @@ +define i64 @foo() { + ret i64 42 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo() + ret i64 %1 +} + diff --git a/hw3/llprograms/call1.ll b/hw3/llprograms/call1.ll new file mode 100644 index 0000000..e2785ee --- /dev/null +++ b/hw3/llprograms/call1.ll @@ -0,0 +1,9 @@ +define i64 @foo(i64 %x) { + ret i64 %x +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 17) + ret i64 %1 +} + diff --git a/hw3/llprograms/call2.ll b/hw3/llprograms/call2.ll new file mode 100644 index 0000000..10226cc --- /dev/null +++ b/hw3/llprograms/call2.ll @@ -0,0 +1,10 @@ +define i64 @foo(i64 %x) { + ret i64 %x +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 17) + %2 = call i64 @foo(i64 19) + ret i64 %2 +} + diff --git a/hw3/llprograms/call3.ll b/hw3/llprograms/call3.ll new file mode 100644 index 0000000..e0dd5a0 --- /dev/null +++ b/hw3/llprograms/call3.ll @@ -0,0 +1,10 @@ +define i64 @foo(i64 %x) { + %1 = add i64 %x, %x + ret i64 %1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 17) + ret i64 %1 +} + diff --git a/hw3/llprograms/call4.ll b/hw3/llprograms/call4.ll new file mode 100644 index 0000000..20511e6 --- /dev/null +++ b/hw3/llprograms/call4.ll @@ -0,0 +1,15 @@ +define i64 @bar(i64 %x, i64 %y) { + %1 = add i64 %x, %y + ret i64 %1 +} + +define i64 @foo(i64 %x) { + %1 = call i64 @bar(i64 %x, i64 %x) + ret i64 %1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 17) + ret i64 %1 +} + diff --git a/hw3/llprograms/call5.ll b/hw3/llprograms/call5.ll new file mode 100644 index 0000000..3d6ad68 --- /dev/null +++ b/hw3/llprograms/call5.ll @@ -0,0 +1,21 @@ +define i64 @bar(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + %1 = add i64 %x1, %x2 + %2 = add i64 %1, %x3 + %3 = add i64 %2, %x4 + %4 = add i64 %3, %x5 + %5 = add i64 %4, %x6 + %6 = add i64 %5, %x7 + %7 = add i64 %6, %x8 + ret i64 %7 +} + +define i64 @foo(i64 %x) { + %1 = call i64 @bar(i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x) + ret i64 %1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 3) + ret i64 %1 +} + diff --git a/hw3/llprograms/call6.ll b/hw3/llprograms/call6.ll new file mode 100644 index 0000000..4194e2f --- /dev/null +++ b/hw3/llprograms/call6.ll @@ -0,0 +1,34 @@ +define i64 @baz(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + %1 = add i64 %x1, %x2 + %2 = add i64 %1, %x3 + %3 = add i64 %2, %x4 + %4 = add i64 %3, %x5 + %5 = add i64 %4, %x6 + %6 = add i64 %5, %x7 + %7 = add i64 %6, %x8 + ret i64 %7 +} + +define i64 @bar(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + %1 = add i64 %x1, %x2 + %2 = add i64 %1, %x3 + %3 = add i64 %2, %x4 + %4 = add i64 %3, %x5 + %tmp = call i64 @baz(i64 %1, i64 %2, i64 %3, i64 %4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) + %5 = add i64 %4, %x6 + %6 = add i64 %5, %x7 + %7 = add i64 %6, %x8 + %8 = add i64 %7, %tmp + ret i64 %8 +} + +define i64 @foo(i64 %x) { + %1 = call i64 @bar(i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x) + ret i64 %1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 1) + ret i64 %1 +} + diff --git a/hw3/llprograms/call7.ll b/hw3/llprograms/call7.ll new file mode 100644 index 0000000..38a594e --- /dev/null +++ b/hw3/llprograms/call7.ll @@ -0,0 +1,9 @@ +define i64 @bar(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + ret i64 %x7 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @bar(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8) + ret i64 %1 +} + diff --git a/hw3/llprograms/call8.ll b/hw3/llprograms/call8.ll new file mode 100644 index 0000000..bf26331 --- /dev/null +++ b/hw3/llprograms/call8.ll @@ -0,0 +1,21 @@ +define i64 @foo(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + ret i64 %x6 +} + +define i64 @bar(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + ret i64 %x7 +} + +define i64 @baz(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + ret i64 %x8 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8) + %2 = call i64 @bar(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8) + %3 = call i64 @baz(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8) + %4 = add i64 %1, %2 + %5 = add i64 %4, %3 + ret i64 %5 +} + diff --git a/hw3/llprograms/callback1.ll b/hw3/llprograms/callback1.ll new file mode 100644 index 0000000..1e62dc6 --- /dev/null +++ b/hw3/llprograms/callback1.ll @@ -0,0 +1,20 @@ +%fty = type i64 (i64, i64) + +declare i64 @ll_callback(%fty*) +declare i8* @ll_ltoa(i64) +declare void @ll_puts(i8*) + +define i64 @foo(i64 %x, i64 %y) { + %1 = alloca i64 + %2 = add i64 %x, %y + store i64 %2, i64* %1 + %3 = load i64, i64* %1 + ret i64 %3 +} + +define i64 @main(i64 %argc, i8** %argv) { + %1 = call i64 @ll_callback(%fty* @foo) + %2 = call i8* @ll_ltoa(i64 %1) + call void @ll_puts(i8* %2) + ret i64 0 +} diff --git a/hw3/llprograms/cbr.ll b/hw3/llprograms/cbr.ll new file mode 100644 index 0000000..0038776 --- /dev/null +++ b/hw3/llprograms/cbr.ll @@ -0,0 +1,29 @@ +define i64 @foo() { + ret i64 42 +} + +define i64 @bar() { + ret i64 0 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %y = alloca i64 + store i64 0, i64* %1 + store i64 100, i64* %y + %2 = load i64, i64* %y + %3 = icmp ne i64 %2, 0 + br i1 %3, label %then, label %else +then: + %4 = call i64 @foo() + store i64 %4, i64* %1 + br label %end +else: + %5 = call i64 @bar() + store i64 %5, i64* %1 + br label %end +end: + %6 = load i64, i64* %1 + ret i64 %6 +} + diff --git a/hw3/llprograms/cbr1.ll b/hw3/llprograms/cbr1.ll new file mode 100644 index 0000000..f27e509 --- /dev/null +++ b/hw3/llprograms/cbr1.ll @@ -0,0 +1,9 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %cmp = icmp sgt i64 3, 0 + br i1 %cmp, label %then, label %else +then: + ret i64 7 +else: + ret i64 9 +} + diff --git a/hw3/llprograms/cbr2.ll b/hw3/llprograms/cbr2.ll new file mode 100644 index 0000000..e52e9f0 --- /dev/null +++ b/hw3/llprograms/cbr2.ll @@ -0,0 +1,9 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %cmp = icmp slt i64 3, 0 + br i1 %cmp, label %then, label %else +then: + ret i64 7 +else: + ret i64 9 +} + diff --git a/hw3/llprograms/cbr3.ll b/hw3/llprograms/cbr3.ll new file mode 100644 index 0000000..89a8496 --- /dev/null +++ b/hw3/llprograms/cbr3.ll @@ -0,0 +1,8 @@ +define i64 @main(i64 %argc, i8** %arcv) { + br i1 0, label %then, label %else +then: + ret i64 7 +else: + ret i64 9 +} + diff --git a/hw3/llprograms/certified_random_number_generator.ll b/hw3/llprograms/certified_random_number_generator.ll new file mode 100644 index 0000000..42aeb61 --- /dev/null +++ b/hw3/llprograms/certified_random_number_generator.ll @@ -0,0 +1,29 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %p_lfsr = alloca i64 + %start = add i64 8, 0 + store i64 %start, i64* %p_lfsr + br label %loop +loop: + %iter = load i64, i64* %p_lfsr + %inc = add i64 %iter, 1 + store i64 %inc, i64* %p_lfsr + br label %lfsr_step +lfsr_step: + %x15 = lshr i64 46421, 0 + %x13 = lshr i64 46421, 2 + %x12 = lshr i64 46421, 3 + %x10 = lshr i64 46421, 5 + %bit1 = xor i64 %x15, %x13 + %bit2 = xor i64 %bit1, %x12 + %bit3 = xor i64 %bit2, %x10 + %bit4 = and i64 %bit3, 1 + %lfsr1 = lshr i64 8, 1 + %lfsr2 = shl i64 %bit4, 15 + %lfsr3 = or i64 %lfsr1, %lfsr2 + store i64 %lfsr3, i64* %p_lfsr + br label %loop_end +loop_end: + %lfsr = load i64, i64* %p_lfsr + ret i64 %lfsr +} + diff --git a/hw3/llprograms/certified_random_number_generator_soln.ll b/hw3/llprograms/certified_random_number_generator_soln.ll new file mode 100644 index 0000000..35ecea5 --- /dev/null +++ b/hw3/llprograms/certified_random_number_generator_soln.ll @@ -0,0 +1,17 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %p_lfsr = alloca i64 + store i64 8, i64* %p_lfsr + br label %loop +loop: + %iter = load i64, i64* %p_lfsr + %inc = add i64 %iter, 1 + store i64 %inc, i64* %p_lfsr + br label %lfsr_step +lfsr_step: + store i64 4, i64* %p_lfsr + br label %loop_end +loop_end: + %lfsr = load i64, i64* %p_lfsr + ret i64 %lfsr +} + diff --git a/hw3/llprograms/duplicate_factorial.ll b/hw3/llprograms/duplicate_factorial.ll new file mode 100644 index 0000000..cbe1d9c --- /dev/null +++ b/hw3/llprograms/duplicate_factorial.ll @@ -0,0 +1,56 @@ +define i64 @factorial(i64 %n) { + %1 = alloca i64 + %acc = alloca i64 + store i64 %n, i64* %1 + store i64 1, i64* %acc + br label %start +start: + %2 = load i64, i64* %1 + %3 = icmp sgt i64 %2, 0 + br i1 %3, label %then, label %end +then: + %4 = load i64, i64* %acc + %5 = load i64, i64* %1 + %6 = mul i64 %4, %5 + store i64 %6, i64* %acc + %7 = load i64, i64* %1 + %8 = sub i64 %7, 1 + store i64 %8, i64* %1 + br label %start +end: + %9 = load i64, i64* %acc + ret i64 %9 +} + +define i64 @factorial2(i64 %n) { + %1 = alloca i64 + %acc = alloca i64 + store i64 %n, i64* %1 + store i64 1, i64* %acc + br label %start +start: + %2 = load i64, i64* %1 + %3 = icmp sgt i64 %2, 0 + br i1 %3, label %then, label %end +then: + %4 = load i64, i64* %acc + %5 = load i64, i64* %1 + %6 = mul i64 %4, %5 + store i64 %6, i64* %acc + %7 = load i64, i64* %1 + %8 = sub i64 %7, 1 + store i64 %8, i64* %1 + br label %start +end: + %9 = load i64, i64* %acc + ret i64 %9 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 0, i64* %1 + %2 = call i64 @factorial(i64 5) + %3 = call i64 @factorial2(i64 5) + %4 = add i64 %2, %3 + ret i64 %4 +} diff --git a/hw3/llprograms/duplicate_lbl.ll b/hw3/llprograms/duplicate_lbl.ll new file mode 100644 index 0000000..5012c08 --- /dev/null +++ b/hw3/llprograms/duplicate_lbl.ll @@ -0,0 +1,28 @@ +define i64 @f1(i64 %a) { + br label %start +start: + %b = icmp sgt i64 %a, 10 + br i1 %b, label %then, label %end +then: + ret i64 1 +end: + ret i64 0 +} + +define i64 @f2(i64 %a) { + br label %start +start: + %b = icmp sgt i64 %a, 10 + br i1 %b, label %then, label %end +then: + ret i64 1 +end: + ret i64 0 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %a = call i64 @f1(i64 0) + %b = call i64 @f2(i64 15) + %c = add i64 %a, %b + ret i64 %c +} diff --git a/hw3/llprograms/euclid.ll b/hw3/llprograms/euclid.ll new file mode 100644 index 0000000..e668ae9 --- /dev/null +++ b/hw3/llprograms/euclid.ll @@ -0,0 +1,23 @@ +define i64 @gcd_rec(i64 %a, i64 %b) { + %1 = alloca i64 + store i64 %a, i64* %1 + %cmp = icmp ne i64 %b, 0 + br i1 %cmp, label %neq0, label %eq0 +eq0: + ret i64 %a +neq0: + %2 = load i64, i64* %1 + %3 = sub i64 %2, %b + store i64 %3, i64* %1 + %cmp1 = icmp sgt i64 %3, %b + br i1 %cmp1, label %neq0, label %recurse +recurse: + %4 = call i64 @gcd_rec(i64 %b, i64 %3) + ret i64 %4 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @gcd_rec(i64 424, i64 34) + ret i64 %1 +} + diff --git a/hw3/llprograms/factorial.ll b/hw3/llprograms/factorial.ll new file mode 100644 index 0000000..a6d0199 --- /dev/null +++ b/hw3/llprograms/factorial.ll @@ -0,0 +1,31 @@ +define i64 @factorial(i64 %n) { + %1 = alloca i64 + %acc = alloca i64 + store i64 %n, i64* %1 + store i64 1, i64* %acc + br label %start +start: + %2 = load i64, i64* %1 + %3 = icmp sgt i64 %2, 0 + br i1 %3, label %then, label %end +then: + %4 = load i64, i64* %acc + %5 = load i64, i64* %1 + %6 = mul i64 %4, %5 + store i64 %6, i64* %acc + %7 = load i64, i64* %1 + %8 = sub i64 %7, 1 + store i64 %8, i64* %1 + br label %start +end: + %9 = load i64, i64* %acc + ret i64 %9 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 0, i64* %1 + %2 = call i64 @factorial(i64 5) + ret i64 %2 +} + diff --git a/hw3/llprograms/factrect.ll b/hw3/llprograms/factrect.ll new file mode 100644 index 0000000..cec349c --- /dev/null +++ b/hw3/llprograms/factrect.ll @@ -0,0 +1,17 @@ +define i64 @factorial(i64 %n) { + %cmp = icmp eq i64 %n, 0 + br i1 %cmp, label %ret1, label %recurse +ret1: + ret i64 1 +recurse: + %1 = sub i64 %n, 1 + %2 = call i64 @factorial(i64 %1) + %3 = mul i64 %n, %2 + ret i64 %3 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @factorial(i64 5) + ret i64 %1 +} + diff --git a/hw3/llprograms/gcd_euclidian.ll b/hw3/llprograms/gcd_euclidian.ll new file mode 100644 index 0000000..078db71 --- /dev/null +++ b/hw3/llprograms/gcd_euclidian.ll @@ -0,0 +1,34 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = alloca i64 + store i64 8, i64* %1 + store i64 10, i64* %2 + br label %gcd +gcd: + %3 = load i64, i64* %1 + %4 = icmp eq i64 0, %3 + br i1 %4, label %ret_b, label %loop +loop: + %5 = load i64, i64* %2 + %6 = icmp eq i64 0, %5 + br i1 %6, label %ret_a, label %continue_loop +continue_loop: + %7 = load i64, i64* %1 + %8 = icmp sgt i64 %7, %5 + br i1 %8, label %if, label %else +if: + %9 = sub i64 %7, %5 + store i64 %9, i64* %1 + br label %loop +else: + %10 = sub i64 %5, %7 + store i64 %10, i64* %2 + br label %loop +ret_a: + %11 = load i64, i64* %1 + ret i64 %11 +ret_b: + %12 = load i64, i64* %2 + ret i64 %12 +} + diff --git a/hw3/llprograms/gep1.ll b/hw3/llprograms/gep1.ll new file mode 100644 index 0000000..f152480 --- /dev/null +++ b/hw3/llprograms/gep1.ll @@ -0,0 +1,27 @@ +%disju = type { i64, i8* } +%var1 = type { i64, i64* } +%var2 = type { i64, i8** } + +@gint = global i64 42 +@v1 = global %var1 { i64 0, i64* @gint } +@v2 = global %var2 { i64 1, i8** null } +@gstr = global [14 x i8] c"hello, world!\00" + + +define i64 @main(i64 %argc, i8** %argv) { + %p0 = alloca i64 + %p1 = getelementptr %var2, %var2* @v2, i32 0, i32 0 + store i64 5, i64* %p1 + %vb = bitcast %var2* @v2 to %disju* + call void @foo(%disju* %vb) + %n1 = load i64, i64* %p1 + ret i64 %n1 +} + +define void @foo(%disju* %pu) { + %p1 = getelementptr %disju, %disju* %pu, i32 0, i32 0 + store i64 6, i64* %p1 + %n1 = load i64, i64* %p1 + ret void +} + diff --git a/hw3/llprograms/gep10.ll b/hw3/llprograms/gep10.ll new file mode 100644 index 0000000..8879abc --- /dev/null +++ b/hw3/llprograms/gep10.ll @@ -0,0 +1,11 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 0, %argc + %2 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i64 %1 + %3 = load i64, i64* %2 + ret i64 %3 +} + diff --git a/hw3/llprograms/gep2.ll b/hw3/llprograms/gep2.ll new file mode 100644 index 0000000..3a63b46 --- /dev/null +++ b/hw3/llprograms/gep2.ll @@ -0,0 +1,11 @@ +%arr = type [5 x i64] + +@tmp = global %arr [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = getelementptr %arr, %arr* @tmp, i32 0, i32 3 + %3 = load i64, i64* %2 + ret i64 %3 +} + diff --git a/hw3/llprograms/gep3.ll b/hw3/llprograms/gep3.ll new file mode 100644 index 0000000..56b822d --- /dev/null +++ b/hw3/llprograms/gep3.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 0 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/gep4.ll b/hw3/llprograms/gep4.ll new file mode 100644 index 0000000..db1a688 --- /dev/null +++ b/hw3/llprograms/gep4.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i32 0 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/gep5.ll b/hw3/llprograms/gep5.ll new file mode 100644 index 0000000..621ee23 --- /dev/null +++ b/hw3/llprograms/gep5.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i32 2 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/gep6.ll b/hw3/llprograms/gep6.ll new file mode 100644 index 0000000..f7ad620 --- /dev/null +++ b/hw3/llprograms/gep6.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 2 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/gep7.ll b/hw3/llprograms/gep7.ll new file mode 100644 index 0000000..6e5870f --- /dev/null +++ b/hw3/llprograms/gep7.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i32 5 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/gep8.ll b/hw3/llprograms/gep8.ll new file mode 100644 index 0000000..c85ad27 --- /dev/null +++ b/hw3/llprograms/gep8.ll @@ -0,0 +1,11 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 0, 0 + %2 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i64 %1 + %3 = load i64, i64* %2 + ret i64 %3 +} + diff --git a/hw3/llprograms/gep9.ll b/hw3/llprograms/gep9.ll new file mode 100644 index 0000000..287e0a2 --- /dev/null +++ b/hw3/llprograms/gep9.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i32 3 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/global1.ll b/hw3/llprograms/global1.ll new file mode 100644 index 0000000..f1f1d38 --- /dev/null +++ b/hw3/llprograms/global1.ll @@ -0,0 +1,7 @@ +@gbl = global i64 12 + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = load i64, i64* @gbl + ret i64 %1 +} + diff --git a/hw3/llprograms/helloworld.ll b/hw3/llprograms/helloworld.ll new file mode 100644 index 0000000..639f8c5 --- /dev/null +++ b/hw3/llprograms/helloworld.ll @@ -0,0 +1,9 @@ +declare void @ll_puts(i8*) + +@gstr = global [14 x i8] c"hello, world!\00" + +define i64 @main(i64 %argc, i8** %argv) { + %1 = getelementptr [14 x i8], [14 x i8]* @gstr, i32 0, i32 0 + call void @ll_puts(i8* %1) + ret i64 0 +} diff --git a/hw3/llprograms/kaiterry_pi.ll b/hw3/llprograms/kaiterry_pi.ll new file mode 100644 index 0000000..98c447d --- /dev/null +++ b/hw3/llprograms/kaiterry_pi.ll @@ -0,0 +1,2011 @@ +define i64 @main(i64 %argc, i8** %argv) { + %x0 = add i64 0, 0 + %x1 = add i64 %x0, 1000000000000 + %x2 = sub i64 %x1, 333333333333 + %x3 = add i64 %x2, 200000000000 + %x4 = sub i64 %x3, 142857142857 + %x5 = add i64 %x4, 111111111111 + %x6 = sub i64 %x5, 90909090909 + %x7 = add i64 %x6, 76923076923 + %x8 = sub i64 %x7, 66666666666 + %x9 = add i64 %x8, 58823529411 + %x10 = sub i64 %x9, 52631578947 + %x11 = add i64 %x10, 47619047619 + %x12 = sub i64 %x11, 43478260869 + %x13 = add i64 %x12, 40000000000 + %x14 = sub i64 %x13, 37037037037 + %x15 = add i64 %x14, 34482758620 + %x16 = sub i64 %x15, 32258064516 + %x17 = add i64 %x16, 30303030303 + %x18 = sub i64 %x17, 28571428571 + %x19 = add i64 %x18, 27027027027 + %x20 = sub i64 %x19, 25641025641 + %x21 = add i64 %x20, 24390243902 + %x22 = sub i64 %x21, 23255813953 + %x23 = add i64 %x22, 22222222222 + %x24 = sub i64 %x23, 21276595744 + %x25 = add i64 %x24, 20408163265 + %x26 = sub i64 %x25, 19607843137 + %x27 = add i64 %x26, 18867924528 + %x28 = sub i64 %x27, 18181818181 + %x29 = add i64 %x28, 17543859649 + %x30 = sub i64 %x29, 16949152542 + %x31 = add i64 %x30, 16393442622 + %x32 = sub i64 %x31, 15873015873 + %x33 = add i64 %x32, 15384615384 + %x34 = sub i64 %x33, 14925373134 + %x35 = add i64 %x34, 14492753623 + %x36 = sub i64 %x35, 14084507042 + %x37 = add i64 %x36, 13698630136 + %x38 = sub i64 %x37, 13333333333 + %x39 = add i64 %x38, 12987012987 + %x40 = sub i64 %x39, 12658227848 + %x41 = add i64 %x40, 12345679012 + %x42 = sub i64 %x41, 12048192771 + %x43 = add i64 %x42, 11764705882 + %x44 = sub i64 %x43, 11494252873 + %x45 = add i64 %x44, 11235955056 + %x46 = sub i64 %x45, 10989010989 + %x47 = add i64 %x46, 10752688172 + %x48 = sub i64 %x47, 10526315789 + %x49 = add i64 %x48, 10309278350 + %x50 = sub i64 %x49, 10101010101 + %x51 = add i64 %x50, 9900990099 + %x52 = sub i64 %x51, 9708737864 + %x53 = add i64 %x52, 9523809523 + %x54 = sub i64 %x53, 9345794392 + %x55 = add i64 %x54, 9174311926 + %x56 = sub i64 %x55, 9009009009 + %x57 = add i64 %x56, 8849557522 + %x58 = sub i64 %x57, 8695652173 + %x59 = add i64 %x58, 8547008547 + %x60 = sub i64 %x59, 8403361344 + %x61 = add i64 %x60, 8264462809 + %x62 = sub i64 %x61, 8130081300 + %x63 = add i64 %x62, 8000000000 + %x64 = sub i64 %x63, 7874015748 + %x65 = add i64 %x64, 7751937984 + %x66 = sub i64 %x65, 7633587786 + %x67 = add i64 %x66, 7518796992 + %x68 = sub i64 %x67, 7407407407 + %x69 = add i64 %x68, 7299270072 + %x70 = sub i64 %x69, 7194244604 + %x71 = add i64 %x70, 7092198581 + %x72 = sub i64 %x71, 6993006993 + %x73 = add i64 %x72, 6896551724 + %x74 = sub i64 %x73, 6802721088 + %x75 = add i64 %x74, 6711409395 + %x76 = sub i64 %x75, 6622516556 + %x77 = add i64 %x76, 6535947712 + %x78 = sub i64 %x77, 6451612903 + %x79 = add i64 %x78, 6369426751 + %x80 = sub i64 %x79, 6289308176 + %x81 = add i64 %x80, 6211180124 + %x82 = sub i64 %x81, 6134969325 + %x83 = add i64 %x82, 6060606060 + %x84 = sub i64 %x83, 5988023952 + %x85 = add i64 %x84, 5917159763 + %x86 = sub i64 %x85, 5847953216 + %x87 = add i64 %x86, 5780346820 + %x88 = sub i64 %x87, 5714285714 + %x89 = add i64 %x88, 5649717514 + %x90 = sub i64 %x89, 5586592178 + %x91 = add i64 %x90, 5524861878 + %x92 = sub i64 %x91, 5464480874 + %x93 = add i64 %x92, 5405405405 + %x94 = sub i64 %x93, 5347593582 + %x95 = add i64 %x94, 5291005291 + %x96 = sub i64 %x95, 5235602094 + %x97 = add i64 %x96, 5181347150 + %x98 = sub i64 %x97, 5128205128 + %x99 = add i64 %x98, 5076142131 + %x100 = sub i64 %x99, 5025125628 + %x101 = add i64 %x100, 4975124378 + %x102 = sub i64 %x101, 4926108374 + %x103 = add i64 %x102, 4878048780 + %x104 = sub i64 %x103, 4830917874 + %x105 = add i64 %x104, 4784688995 + %x106 = sub i64 %x105, 4739336492 + %x107 = add i64 %x106, 4694835680 + %x108 = sub i64 %x107, 4651162790 + %x109 = add i64 %x108, 4608294930 + %x110 = sub i64 %x109, 4566210045 + %x111 = add i64 %x110, 4524886877 + %x112 = sub i64 %x111, 4484304932 + %x113 = add i64 %x112, 4444444444 + %x114 = sub i64 %x113, 4405286343 + %x115 = add i64 %x114, 4366812227 + %x116 = sub i64 %x115, 4329004329 + %x117 = add i64 %x116, 4291845493 + %x118 = sub i64 %x117, 4255319148 + %x119 = add i64 %x118, 4219409282 + %x120 = sub i64 %x119, 4184100418 + %x121 = add i64 %x120, 4149377593 + %x122 = sub i64 %x121, 4115226337 + %x123 = add i64 %x122, 4081632653 + %x124 = sub i64 %x123, 4048582995 + %x125 = add i64 %x124, 4016064257 + %x126 = sub i64 %x125, 3984063745 + %x127 = add i64 %x126, 3952569169 + %x128 = sub i64 %x127, 3921568627 + %x129 = add i64 %x128, 3891050583 + %x130 = sub i64 %x129, 3861003861 + %x131 = add i64 %x130, 3831417624 + %x132 = sub i64 %x131, 3802281368 + %x133 = add i64 %x132, 3773584905 + %x134 = sub i64 %x133, 3745318352 + %x135 = add i64 %x134, 3717472118 + %x136 = sub i64 %x135, 3690036900 + %x137 = add i64 %x136, 3663003663 + %x138 = sub i64 %x137, 3636363636 + %x139 = add i64 %x138, 3610108303 + %x140 = sub i64 %x139, 3584229390 + %x141 = add i64 %x140, 3558718861 + %x142 = sub i64 %x141, 3533568904 + %x143 = add i64 %x142, 3508771929 + %x144 = sub i64 %x143, 3484320557 + %x145 = add i64 %x144, 3460207612 + %x146 = sub i64 %x145, 3436426116 + %x147 = add i64 %x146, 3412969283 + %x148 = sub i64 %x147, 3389830508 + %x149 = add i64 %x148, 3367003367 + %x150 = sub i64 %x149, 3344481605 + %x151 = add i64 %x150, 3322259136 + %x152 = sub i64 %x151, 3300330033 + %x153 = add i64 %x152, 3278688524 + %x154 = sub i64 %x153, 3257328990 + %x155 = add i64 %x154, 3236245954 + %x156 = sub i64 %x155, 3215434083 + %x157 = add i64 %x156, 3194888178 + %x158 = sub i64 %x157, 3174603174 + %x159 = add i64 %x158, 3154574132 + %x160 = sub i64 %x159, 3134796238 + %x161 = add i64 %x160, 3115264797 + %x162 = sub i64 %x161, 3095975232 + %x163 = add i64 %x162, 3076923076 + %x164 = sub i64 %x163, 3058103975 + %x165 = add i64 %x164, 3039513677 + %x166 = sub i64 %x165, 3021148036 + %x167 = add i64 %x166, 3003003003 + %x168 = sub i64 %x167, 2985074626 + %x169 = add i64 %x168, 2967359050 + %x170 = sub i64 %x169, 2949852507 + %x171 = add i64 %x170, 2932551319 + %x172 = sub i64 %x171, 2915451895 + %x173 = add i64 %x172, 2898550724 + %x174 = sub i64 %x173, 2881844380 + %x175 = add i64 %x174, 2865329512 + %x176 = sub i64 %x175, 2849002849 + %x177 = add i64 %x176, 2832861189 + %x178 = sub i64 %x177, 2816901408 + %x179 = add i64 %x178, 2801120448 + %x180 = sub i64 %x179, 2785515320 + %x181 = add i64 %x180, 2770083102 + %x182 = sub i64 %x181, 2754820936 + %x183 = add i64 %x182, 2739726027 + %x184 = sub i64 %x183, 2724795640 + %x185 = add i64 %x184, 2710027100 + %x186 = sub i64 %x185, 2695417789 + %x187 = add i64 %x186, 2680965147 + %x188 = sub i64 %x187, 2666666666 + %x189 = add i64 %x188, 2652519893 + %x190 = sub i64 %x189, 2638522427 + %x191 = add i64 %x190, 2624671916 + %x192 = sub i64 %x191, 2610966057 + %x193 = add i64 %x192, 2597402597 + %x194 = sub i64 %x193, 2583979328 + %x195 = add i64 %x194, 2570694087 + %x196 = sub i64 %x195, 2557544757 + %x197 = add i64 %x196, 2544529262 + %x198 = sub i64 %x197, 2531645569 + %x199 = add i64 %x198, 2518891687 + %x200 = sub i64 %x199, 2506265664 + %x201 = add i64 %x200, 2493765586 + %x202 = sub i64 %x201, 2481389578 + %x203 = add i64 %x202, 2469135802 + %x204 = sub i64 %x203, 2457002457 + %x205 = add i64 %x204, 2444987775 + %x206 = sub i64 %x205, 2433090024 + %x207 = add i64 %x206, 2421307506 + %x208 = sub i64 %x207, 2409638554 + %x209 = add i64 %x208, 2398081534 + %x210 = sub i64 %x209, 2386634844 + %x211 = add i64 %x210, 2375296912 + %x212 = sub i64 %x211, 2364066193 + %x213 = add i64 %x212, 2352941176 + %x214 = sub i64 %x213, 2341920374 + %x215 = add i64 %x214, 2331002331 + %x216 = sub i64 %x215, 2320185614 + %x217 = add i64 %x216, 2309468822 + %x218 = sub i64 %x217, 2298850574 + %x219 = add i64 %x218, 2288329519 + %x220 = sub i64 %x219, 2277904328 + %x221 = add i64 %x220, 2267573696 + %x222 = sub i64 %x221, 2257336343 + %x223 = add i64 %x222, 2247191011 + %x224 = sub i64 %x223, 2237136465 + %x225 = add i64 %x224, 2227171492 + %x226 = sub i64 %x225, 2217294900 + %x227 = add i64 %x226, 2207505518 + %x228 = sub i64 %x227, 2197802197 + %x229 = add i64 %x228, 2188183807 + %x230 = sub i64 %x229, 2178649237 + %x231 = add i64 %x230, 2169197396 + %x232 = sub i64 %x231, 2159827213 + %x233 = add i64 %x232, 2150537634 + %x234 = sub i64 %x233, 2141327623 + %x235 = add i64 %x234, 2132196162 + %x236 = sub i64 %x235, 2123142250 + %x237 = add i64 %x236, 2114164904 + %x238 = sub i64 %x237, 2105263157 + %x239 = add i64 %x238, 2096436058 + %x240 = sub i64 %x239, 2087682672 + %x241 = add i64 %x240, 2079002079 + %x242 = sub i64 %x241, 2070393374 + %x243 = add i64 %x242, 2061855670 + %x244 = sub i64 %x243, 2053388090 + %x245 = add i64 %x244, 2044989775 + %x246 = sub i64 %x245, 2036659877 + %x247 = add i64 %x246, 2028397565 + %x248 = sub i64 %x247, 2020202020 + %x249 = add i64 %x248, 2012072434 + %x250 = sub i64 %x249, 2004008016 + %x251 = add i64 %x250, 1996007984 + %x252 = sub i64 %x251, 1988071570 + %x253 = add i64 %x252, 1980198019 + %x254 = sub i64 %x253, 1972386587 + %x255 = add i64 %x254, 1964636542 + %x256 = sub i64 %x255, 1956947162 + %x257 = add i64 %x256, 1949317738 + %x258 = sub i64 %x257, 1941747572 + %x259 = add i64 %x258, 1934235976 + %x260 = sub i64 %x259, 1926782273 + %x261 = add i64 %x260, 1919385796 + %x262 = sub i64 %x261, 1912045889 + %x263 = add i64 %x262, 1904761904 + %x264 = sub i64 %x263, 1897533206 + %x265 = add i64 %x264, 1890359168 + %x266 = sub i64 %x265, 1883239171 + %x267 = add i64 %x266, 1876172607 + %x268 = sub i64 %x267, 1869158878 + %x269 = add i64 %x268, 1862197392 + %x270 = sub i64 %x269, 1855287569 + %x271 = add i64 %x270, 1848428835 + %x272 = sub i64 %x271, 1841620626 + %x273 = add i64 %x272, 1834862385 + %x274 = sub i64 %x273, 1828153564 + %x275 = add i64 %x274, 1821493624 + %x276 = sub i64 %x275, 1814882032 + %x277 = add i64 %x276, 1808318264 + %x278 = sub i64 %x277, 1801801801 + %x279 = add i64 %x278, 1795332136 + %x280 = sub i64 %x279, 1788908765 + %x281 = add i64 %x280, 1782531194 + %x282 = sub i64 %x281, 1776198934 + %x283 = add i64 %x282, 1769911504 + %x284 = sub i64 %x283, 1763668430 + %x285 = add i64 %x284, 1757469244 + %x286 = sub i64 %x285, 1751313485 + %x287 = add i64 %x286, 1745200698 + %x288 = sub i64 %x287, 1739130434 + %x289 = add i64 %x288, 1733102253 + %x290 = sub i64 %x289, 1727115716 + %x291 = add i64 %x290, 1721170395 + %x292 = sub i64 %x291, 1715265866 + %x293 = add i64 %x292, 1709401709 + %x294 = sub i64 %x293, 1703577512 + %x295 = add i64 %x294, 1697792869 + %x296 = sub i64 %x295, 1692047377 + %x297 = add i64 %x296, 1686340640 + %x298 = sub i64 %x297, 1680672268 + %x299 = add i64 %x298, 1675041876 + %x300 = sub i64 %x299, 1669449081 + %x301 = add i64 %x300, 1663893510 + %x302 = sub i64 %x301, 1658374792 + %x303 = add i64 %x302, 1652892561 + %x304 = sub i64 %x303, 1647446457 + %x305 = add i64 %x304, 1642036124 + %x306 = sub i64 %x305, 1636661211 + %x307 = add i64 %x306, 1631321370 + %x308 = sub i64 %x307, 1626016260 + %x309 = add i64 %x308, 1620745542 + %x310 = sub i64 %x309, 1615508885 + %x311 = add i64 %x310, 1610305958 + %x312 = sub i64 %x311, 1605136436 + %x313 = add i64 %x312, 1600000000 + %x314 = sub i64 %x313, 1594896331 + %x315 = add i64 %x314, 1589825119 + %x316 = sub i64 %x315, 1584786053 + %x317 = add i64 %x316, 1579778830 + %x318 = sub i64 %x317, 1574803149 + %x319 = add i64 %x318, 1569858712 + %x320 = sub i64 %x319, 1564945226 + %x321 = add i64 %x320, 1560062402 + %x322 = sub i64 %x321, 1555209953 + %x323 = add i64 %x322, 1550387596 + %x324 = sub i64 %x323, 1545595054 + %x325 = add i64 %x324, 1540832049 + %x326 = sub i64 %x325, 1536098310 + %x327 = add i64 %x326, 1531393568 + %x328 = sub i64 %x327, 1526717557 + %x329 = add i64 %x328, 1522070015 + %x330 = sub i64 %x329, 1517450682 + %x331 = add i64 %x330, 1512859304 + %x332 = sub i64 %x331, 1508295625 + %x333 = add i64 %x332, 1503759398 + %x334 = sub i64 %x333, 1499250374 + %x335 = add i64 %x334, 1494768310 + %x336 = sub i64 %x335, 1490312965 + %x337 = add i64 %x336, 1485884101 + %x338 = sub i64 %x337, 1481481481 + %x339 = add i64 %x338, 1477104874 + %x340 = sub i64 %x339, 1472754050 + %x341 = add i64 %x340, 1468428781 + %x342 = sub i64 %x341, 1464128843 + %x343 = add i64 %x342, 1459854014 + %x344 = sub i64 %x343, 1455604075 + %x345 = add i64 %x344, 1451378809 + %x346 = sub i64 %x345, 1447178002 + %x347 = add i64 %x346, 1443001443 + %x348 = sub i64 %x347, 1438848920 + %x349 = add i64 %x348, 1434720229 + %x350 = sub i64 %x349, 1430615164 + %x351 = add i64 %x350, 1426533523 + %x352 = sub i64 %x351, 1422475106 + %x353 = add i64 %x352, 1418439716 + %x354 = sub i64 %x353, 1414427157 + %x355 = add i64 %x354, 1410437235 + %x356 = sub i64 %x355, 1406469760 + %x357 = add i64 %x356, 1402524544 + %x358 = sub i64 %x357, 1398601398 + %x359 = add i64 %x358, 1394700139 + %x360 = sub i64 %x359, 1390820584 + %x361 = add i64 %x360, 1386962552 + %x362 = sub i64 %x361, 1383125864 + %x363 = add i64 %x362, 1379310344 + %x364 = sub i64 %x363, 1375515818 + %x365 = add i64 %x364, 1371742112 + %x366 = sub i64 %x365, 1367989056 + %x367 = add i64 %x366, 1364256480 + %x368 = sub i64 %x367, 1360544217 + %x369 = add i64 %x368, 1356852103 + %x370 = sub i64 %x369, 1353179972 + %x371 = add i64 %x370, 1349527665 + %x372 = sub i64 %x371, 1345895020 + %x373 = add i64 %x372, 1342281879 + %x374 = sub i64 %x373, 1338688085 + %x375 = add i64 %x374, 1335113484 + %x376 = sub i64 %x375, 1331557922 + %x377 = add i64 %x376, 1328021248 + %x378 = sub i64 %x377, 1324503311 + %x379 = add i64 %x378, 1321003963 + %x380 = sub i64 %x379, 1317523056 + %x381 = add i64 %x380, 1314060446 + %x382 = sub i64 %x381, 1310615989 + %x383 = add i64 %x382, 1307189542 + %x384 = sub i64 %x383, 1303780964 + %x385 = add i64 %x384, 1300390117 + %x386 = sub i64 %x385, 1297016861 + %x387 = add i64 %x386, 1293661060 + %x388 = sub i64 %x387, 1290322580 + %x389 = add i64 %x388, 1287001287 + %x390 = sub i64 %x389, 1283697047 + %x391 = add i64 %x390, 1280409731 + %x392 = sub i64 %x391, 1277139208 + %x393 = add i64 %x392, 1273885350 + %x394 = sub i64 %x393, 1270648030 + %x395 = add i64 %x394, 1267427122 + %x396 = sub i64 %x395, 1264222503 + %x397 = add i64 %x396, 1261034047 + %x398 = sub i64 %x397, 1257861635 + %x399 = add i64 %x398, 1254705144 + %x400 = sub i64 %x399, 1251564455 + %x401 = add i64 %x400, 1248439450 + %x402 = sub i64 %x401, 1245330012 + %x403 = add i64 %x402, 1242236024 + %x404 = sub i64 %x403, 1239157372 + %x405 = add i64 %x404, 1236093943 + %x406 = sub i64 %x405, 1233045622 + %x407 = add i64 %x406, 1230012300 + %x408 = sub i64 %x407, 1226993865 + %x409 = add i64 %x408, 1223990208 + %x410 = sub i64 %x409, 1221001221 + %x411 = add i64 %x410, 1218026796 + %x412 = sub i64 %x411, 1215066828 + %x413 = add i64 %x412, 1212121212 + %x414 = sub i64 %x413, 1209189842 + %x415 = add i64 %x414, 1206272617 + %x416 = sub i64 %x415, 1203369434 + %x417 = add i64 %x416, 1200480192 + %x418 = sub i64 %x417, 1197604790 + %x419 = add i64 %x418, 1194743130 + %x420 = sub i64 %x419, 1191895113 + %x421 = add i64 %x420, 1189060642 + %x422 = sub i64 %x421, 1186239620 + %x423 = add i64 %x422, 1183431952 + %x424 = sub i64 %x423, 1180637544 + %x425 = add i64 %x424, 1177856301 + %x426 = sub i64 %x425, 1175088131 + %x427 = add i64 %x426, 1172332942 + %x428 = sub i64 %x427, 1169590643 + %x429 = add i64 %x428, 1166861143 + %x430 = sub i64 %x429, 1164144353 + %x431 = add i64 %x430, 1161440185 + %x432 = sub i64 %x431, 1158748551 + %x433 = add i64 %x432, 1156069364 + %x434 = sub i64 %x433, 1153402537 + %x435 = add i64 %x434, 1150747986 + %x436 = sub i64 %x435, 1148105625 + %x437 = add i64 %x436, 1145475372 + %x438 = sub i64 %x437, 1142857142 + %x439 = add i64 %x438, 1140250855 + %x440 = sub i64 %x439, 1137656427 + %x441 = add i64 %x440, 1135073779 + %x442 = sub i64 %x441, 1132502831 + %x443 = add i64 %x442, 1129943502 + %x444 = sub i64 %x443, 1127395715 + %x445 = add i64 %x444, 1124859392 + %x446 = sub i64 %x445, 1122334455 + %x447 = add i64 %x446, 1119820828 + %x448 = sub i64 %x447, 1117318435 + %x449 = add i64 %x448, 1114827201 + %x450 = sub i64 %x449, 1112347052 + %x451 = add i64 %x450, 1109877913 + %x452 = sub i64 %x451, 1107419712 + %x453 = add i64 %x452, 1104972375 + %x454 = sub i64 %x453, 1102535832 + %x455 = add i64 %x454, 1100110011 + %x456 = sub i64 %x455, 1097694840 + %x457 = add i64 %x456, 1095290251 + %x458 = sub i64 %x457, 1092896174 + %x459 = add i64 %x458, 1090512540 + %x460 = sub i64 %x459, 1088139281 + %x461 = add i64 %x460, 1085776330 + %x462 = sub i64 %x461, 1083423618 + %x463 = add i64 %x462, 1081081081 + %x464 = sub i64 %x463, 1078748651 + %x465 = add i64 %x464, 1076426264 + %x466 = sub i64 %x465, 1074113856 + %x467 = add i64 %x466, 1071811361 + %x468 = sub i64 %x467, 1069518716 + %x469 = add i64 %x468, 1067235859 + %x470 = sub i64 %x469, 1064962726 + %x471 = add i64 %x470, 1062699256 + %x472 = sub i64 %x471, 1060445387 + %x473 = add i64 %x472, 1058201058 + %x474 = sub i64 %x473, 1055966209 + %x475 = add i64 %x474, 1053740779 + %x476 = sub i64 %x475, 1051524710 + %x477 = add i64 %x476, 1049317943 + %x478 = sub i64 %x477, 1047120418 + %x479 = add i64 %x478, 1044932079 + %x480 = sub i64 %x479, 1042752867 + %x481 = add i64 %x480, 1040582726 + %x482 = sub i64 %x481, 1038421599 + %x483 = add i64 %x482, 1036269430 + %x484 = sub i64 %x483, 1034126163 + %x485 = add i64 %x484, 1031991744 + %x486 = sub i64 %x485, 1029866117 + %x487 = add i64 %x486, 1027749229 + %x488 = sub i64 %x487, 1025641025 + %x489 = add i64 %x488, 1023541453 + %x490 = sub i64 %x489, 1021450459 + %x491 = add i64 %x490, 1019367991 + %x492 = sub i64 %x491, 1017293997 + %x493 = add i64 %x492, 1015228426 + %x494 = sub i64 %x493, 1013171225 + %x495 = add i64 %x494, 1011122345 + %x496 = sub i64 %x495, 1009081735 + %x497 = add i64 %x496, 1007049345 + %x498 = sub i64 %x497, 1005025125 + %x499 = add i64 %x498, 1003009027 + %x500 = sub i64 %x499, 1001001001 + %x501 = add i64 %x500, 999000999 + %x502 = sub i64 %x501, 997008973 + %x503 = add i64 %x502, 995024875 + %x504 = sub i64 %x503, 993048659 + %x505 = add i64 %x504, 991080277 + %x506 = sub i64 %x505, 989119683 + %x507 = add i64 %x506, 987166831 + %x508 = sub i64 %x507, 985221674 + %x509 = add i64 %x508, 983284169 + %x510 = sub i64 %x509, 981354268 + %x511 = add i64 %x510, 979431929 + %x512 = sub i64 %x511, 977517106 + %x513 = add i64 %x512, 975609756 + %x514 = sub i64 %x513, 973709834 + %x515 = add i64 %x514, 971817298 + %x516 = sub i64 %x515, 969932104 + %x517 = add i64 %x516, 968054211 + %x518 = sub i64 %x517, 966183574 + %x519 = add i64 %x518, 964320154 + %x520 = sub i64 %x519, 962463907 + %x521 = add i64 %x520, 960614793 + %x522 = sub i64 %x521, 958772770 + %x523 = add i64 %x522, 956937799 + %x524 = sub i64 %x523, 955109837 + %x525 = add i64 %x524, 953288846 + %x526 = sub i64 %x525, 951474785 + %x527 = add i64 %x526, 949667616 + %x528 = sub i64 %x527, 947867298 + %x529 = add i64 %x528, 946073793 + %x530 = sub i64 %x529, 944287063 + %x531 = add i64 %x530, 942507068 + %x532 = sub i64 %x531, 940733772 + %x533 = add i64 %x532, 938967136 + %x534 = sub i64 %x533, 937207122 + %x535 = add i64 %x534, 935453695 + %x536 = sub i64 %x535, 933706816 + %x537 = add i64 %x536, 931966449 + %x538 = sub i64 %x537, 930232558 + %x539 = add i64 %x538, 928505106 + %x540 = sub i64 %x539, 926784059 + %x541 = add i64 %x540, 925069380 + %x542 = sub i64 %x541, 923361034 + %x543 = add i64 %x542, 921658986 + %x544 = sub i64 %x543, 919963201 + %x545 = add i64 %x544, 918273645 + %x546 = sub i64 %x545, 916590284 + %x547 = add i64 %x546, 914913083 + %x548 = sub i64 %x547, 913242009 + %x549 = add i64 %x548, 911577028 + %x550 = sub i64 %x549, 909918107 + %x551 = add i64 %x550, 908265213 + %x552 = sub i64 %x551, 906618313 + %x553 = add i64 %x552, 904977375 + %x554 = sub i64 %x553, 903342366 + %x555 = add i64 %x554, 901713255 + %x556 = sub i64 %x555, 900090009 + %x557 = add i64 %x556, 898472596 + %x558 = sub i64 %x557, 896860986 + %x559 = add i64 %x558, 895255147 + %x560 = sub i64 %x559, 893655049 + %x561 = add i64 %x560, 892060660 + %x562 = sub i64 %x561, 890471950 + %x563 = add i64 %x562, 888888888 + %x564 = sub i64 %x563, 887311446 + %x565 = add i64 %x564, 885739592 + %x566 = sub i64 %x565, 884173297 + %x567 = add i64 %x566, 882612533 + %x568 = sub i64 %x567, 881057268 + %x569 = add i64 %x568, 879507475 + %x570 = sub i64 %x569, 877963125 + %x571 = add i64 %x570, 876424189 + %x572 = sub i64 %x571, 874890638 + %x573 = add i64 %x572, 873362445 + %x574 = sub i64 %x573, 871839581 + %x575 = add i64 %x574, 870322019 + %x576 = sub i64 %x575, 868809730 + %x577 = add i64 %x576, 867302688 + %x578 = sub i64 %x577, 865800865 + %x579 = add i64 %x578, 864304235 + %x580 = sub i64 %x579, 862812769 + %x581 = add i64 %x580, 861326442 + %x582 = sub i64 %x581, 859845227 + %x583 = add i64 %x582, 858369098 + %x584 = sub i64 %x583, 856898029 + %x585 = add i64 %x584, 855431993 + %x586 = sub i64 %x585, 853970964 + %x587 = add i64 %x586, 852514919 + %x588 = sub i64 %x587, 851063829 + %x589 = add i64 %x588, 849617672 + %x590 = sub i64 %x589, 848176420 + %x591 = add i64 %x590, 846740050 + %x592 = sub i64 %x591, 845308537 + %x593 = add i64 %x592, 843881856 + %x594 = sub i64 %x593, 842459983 + %x595 = add i64 %x594, 841042893 + %x596 = sub i64 %x595, 839630562 + %x597 = add i64 %x596, 838222967 + %x598 = sub i64 %x597, 836820083 + %x599 = add i64 %x598, 835421888 + %x600 = sub i64 %x599, 834028356 + %x601 = add i64 %x600, 832639467 + %x602 = sub i64 %x601, 831255195 + %x603 = add i64 %x602, 829875518 + %x604 = sub i64 %x603, 828500414 + %x605 = add i64 %x604, 827129859 + %x606 = sub i64 %x605, 825763831 + %x607 = add i64 %x606, 824402308 + %x608 = sub i64 %x607, 823045267 + %x609 = add i64 %x608, 821692686 + %x610 = sub i64 %x609, 820344544 + %x611 = add i64 %x610, 819000819 + %x612 = sub i64 %x611, 817661488 + %x613 = add i64 %x612, 816326530 + %x614 = sub i64 %x613, 814995925 + %x615 = add i64 %x614, 813669650 + %x616 = sub i64 %x615, 812347684 + %x617 = add i64 %x616, 811030008 + %x618 = sub i64 %x617, 809716599 + %x619 = add i64 %x618, 808407437 + %x620 = sub i64 %x619, 807102502 + %x621 = add i64 %x620, 805801772 + %x622 = sub i64 %x621, 804505229 + %x623 = add i64 %x622, 803212851 + %x624 = sub i64 %x623, 801924619 + %x625 = add i64 %x624, 800640512 + %x626 = sub i64 %x625, 799360511 + %x627 = add i64 %x626, 798084596 + %x628 = sub i64 %x627, 796812749 + %x629 = add i64 %x628, 795544948 + %x630 = sub i64 %x629, 794281175 + %x631 = add i64 %x630, 793021411 + %x632 = sub i64 %x631, 791765637 + %x633 = add i64 %x632, 790513833 + %x634 = sub i64 %x633, 789265982 + %x635 = add i64 %x634, 788022064 + %x636 = sub i64 %x635, 786782061 + %x637 = add i64 %x636, 785545954 + %x638 = sub i64 %x637, 784313725 + %x639 = add i64 %x638, 783085356 + %x640 = sub i64 %x639, 781860828 + %x641 = add i64 %x640, 780640124 + %x642 = sub i64 %x641, 779423226 + %x643 = add i64 %x642, 778210116 + %x644 = sub i64 %x643, 777000777 + %x645 = add i64 %x644, 775795190 + %x646 = sub i64 %x645, 774593338 + %x647 = add i64 %x646, 773395204 + %x648 = sub i64 %x647, 772200772 + %x649 = add i64 %x648, 771010023 + %x650 = sub i64 %x649, 769822940 + %x651 = add i64 %x650, 768639508 + %x652 = sub i64 %x651, 767459708 + %x653 = add i64 %x652, 766283524 + %x654 = sub i64 %x653, 765110941 + %x655 = add i64 %x654, 763941940 + %x656 = sub i64 %x655, 762776506 + %x657 = add i64 %x656, 761614623 + %x658 = sub i64 %x657, 760456273 + %x659 = add i64 %x658, 759301442 + %x660 = sub i64 %x659, 758150113 + %x661 = add i64 %x660, 757002271 + %x662 = sub i64 %x661, 755857898 + %x663 = add i64 %x662, 754716981 + %x664 = sub i64 %x663, 753579502 + %x665 = add i64 %x664, 752445447 + %x666 = sub i64 %x665, 751314800 + %x667 = add i64 %x666, 750187546 + %x668 = sub i64 %x667, 749063670 + %x669 = add i64 %x668, 747943156 + %x670 = sub i64 %x669, 746825989 + %x671 = add i64 %x670, 745712155 + %x672 = sub i64 %x671, 744601638 + %x673 = add i64 %x672, 743494423 + %x674 = sub i64 %x673, 742390497 + %x675 = add i64 %x674, 741289844 + %x676 = sub i64 %x675, 740192450 + %x677 = add i64 %x676, 739098300 + %x678 = sub i64 %x677, 738007380 + %x679 = add i64 %x678, 736919675 + %x680 = sub i64 %x679, 735835172 + %x681 = add i64 %x680, 734753857 + %x682 = sub i64 %x681, 733675715 + %x683 = add i64 %x682, 732600732 + %x684 = sub i64 %x683, 731528895 + %x685 = add i64 %x684, 730460189 + %x686 = sub i64 %x685, 729394602 + %x687 = add i64 %x686, 728332119 + %x688 = sub i64 %x687, 727272727 + %x689 = add i64 %x688, 726216412 + %x690 = sub i64 %x689, 725163161 + %x691 = add i64 %x690, 724112961 + %x692 = sub i64 %x691, 723065798 + %x693 = add i64 %x692, 722021660 + %x694 = sub i64 %x693, 720980533 + %x695 = add i64 %x694, 719942404 + %x696 = sub i64 %x695, 718907260 + %x697 = add i64 %x696, 717875089 + %x698 = sub i64 %x697, 716845878 + %x699 = add i64 %x698, 715819613 + %x700 = sub i64 %x699, 714796283 + %x701 = add i64 %x700, 713775874 + %x702 = sub i64 %x701, 712758374 + %x703 = add i64 %x702, 711743772 + %x704 = sub i64 %x703, 710732054 + %x705 = add i64 %x704, 709723207 + %x706 = sub i64 %x705, 708717221 + %x707 = add i64 %x706, 707714083 + %x708 = sub i64 %x707, 706713780 + %x709 = add i64 %x708, 705716302 + %x710 = sub i64 %x709, 704721634 + %x711 = add i64 %x710, 703729767 + %x712 = sub i64 %x711, 702740688 + %x713 = add i64 %x712, 701754385 + %x714 = sub i64 %x713, 700770847 + %x715 = add i64 %x714, 699790062 + %x716 = sub i64 %x715, 698812019 + %x717 = add i64 %x716, 697836706 + %x718 = sub i64 %x717, 696864111 + %x719 = add i64 %x718, 695894224 + %x720 = sub i64 %x719, 694927032 + %x721 = add i64 %x720, 693962526 + %x722 = sub i64 %x721, 693000693 + %x723 = add i64 %x722, 692041522 + %x724 = sub i64 %x723, 691085003 + %x725 = add i64 %x724, 690131124 + %x726 = sub i64 %x725, 689179875 + %x727 = add i64 %x726, 688231245 + %x728 = sub i64 %x727, 687285223 + %x729 = add i64 %x728, 686341798 + %x730 = sub i64 %x729, 685400959 + %x731 = add i64 %x730, 684462696 + %x732 = sub i64 %x731, 683526999 + %x733 = add i64 %x732, 682593856 + %x734 = sub i64 %x733, 681663258 + %x735 = add i64 %x734, 680735194 + %x736 = sub i64 %x735, 679809653 + %x737 = add i64 %x736, 678886625 + %x738 = sub i64 %x737, 677966101 + %x739 = add i64 %x738, 677048070 + %x740 = sub i64 %x739, 676132521 + %x741 = add i64 %x740, 675219446 + %x742 = sub i64 %x741, 674308833 + %x743 = add i64 %x742, 673400673 + %x744 = sub i64 %x743, 672494956 + %x745 = add i64 %x744, 671591672 + %x746 = sub i64 %x745, 670690811 + %x747 = add i64 %x746, 669792364 + %x748 = sub i64 %x747, 668896321 + %x749 = add i64 %x748, 668002672 + %x750 = sub i64 %x749, 667111407 + %x751 = add i64 %x750, 666222518 + %x752 = sub i64 %x751, 665335994 + %x753 = add i64 %x752, 664451827 + %x754 = sub i64 %x753, 663570006 + %x755 = add i64 %x754, 662690523 + %x756 = sub i64 %x755, 661813368 + %x757 = add i64 %x756, 660938532 + %x758 = sub i64 %x757, 660066006 + %x759 = add i64 %x758, 659195781 + %x760 = sub i64 %x759, 658327847 + %x761 = add i64 %x760, 657462195 + %x762 = sub i64 %x761, 656598818 + %x763 = add i64 %x762, 655737704 + %x764 = sub i64 %x763, 654878847 + %x765 = add i64 %x764, 654022236 + %x766 = sub i64 %x765, 653167864 + %x767 = add i64 %x766, 652315720 + %x768 = sub i64 %x767, 651465798 + %x769 = add i64 %x768, 650618087 + %x770 = sub i64 %x769, 649772579 + %x771 = add i64 %x770, 648929266 + %x772 = sub i64 %x771, 648088139 + %x773 = add i64 %x772, 647249190 + %x774 = sub i64 %x773, 646412411 + %x775 = add i64 %x774, 645577792 + %x776 = sub i64 %x775, 644745325 + %x777 = add i64 %x776, 643915003 + %x778 = sub i64 %x777, 643086816 + %x779 = add i64 %x778, 642260757 + %x780 = sub i64 %x779, 641436818 + %x781 = add i64 %x780, 640614990 + %x782 = sub i64 %x781, 639795265 + %x783 = add i64 %x782, 638977635 + %x784 = sub i64 %x783, 638162093 + %x785 = add i64 %x784, 637348629 + %x786 = sub i64 %x785, 636537237 + %x787 = add i64 %x786, 635727908 + %x788 = sub i64 %x787, 634920634 + %x789 = add i64 %x788, 634115409 + %x790 = sub i64 %x789, 633312222 + %x791 = add i64 %x790, 632511068 + %x792 = sub i64 %x791, 631711939 + %x793 = add i64 %x792, 630914826 + %x794 = sub i64 %x793, 630119722 + %x795 = add i64 %x794, 629326620 + %x796 = sub i64 %x795, 628535512 + %x797 = add i64 %x796, 627746390 + %x798 = sub i64 %x797, 626959247 + %x799 = add i64 %x798, 626174076 + %x800 = sub i64 %x799, 625390869 + %x801 = add i64 %x800, 624609618 + %x802 = sub i64 %x801, 623830318 + %x803 = add i64 %x802, 623052959 + %x804 = sub i64 %x803, 622277535 + %x805 = add i64 %x804, 621504039 + %x806 = sub i64 %x805, 620732464 + %x807 = add i64 %x806, 619962802 + %x808 = sub i64 %x807, 619195046 + %x809 = add i64 %x808, 618429189 + %x810 = sub i64 %x809, 617665225 + %x811 = add i64 %x810, 616903146 + %x812 = sub i64 %x811, 616142945 + %x813 = add i64 %x812, 615384615 + %x814 = sub i64 %x813, 614628149 + %x815 = add i64 %x814, 613873542 + %x816 = sub i64 %x815, 613120784 + %x817 = add i64 %x816, 612369871 + %x818 = sub i64 %x817, 611620795 + %x819 = add i64 %x818, 610873549 + %x820 = sub i64 %x819, 610128126 + %x821 = add i64 %x820, 609384521 + %x822 = sub i64 %x821, 608642726 + %x823 = add i64 %x822, 607902735 + %x824 = sub i64 %x823, 607164541 + %x825 = add i64 %x824, 606428138 + %x826 = sub i64 %x825, 605693519 + %x827 = add i64 %x826, 604960677 + %x828 = sub i64 %x827, 604229607 + %x829 = add i64 %x828, 603500301 + %x830 = sub i64 %x829, 602772754 + %x831 = add i64 %x830, 602046959 + %x832 = sub i64 %x831, 601322910 + %x833 = add i64 %x832, 600600600 + %x834 = sub i64 %x833, 599880023 + %x835 = add i64 %x834, 599161174 + %x836 = sub i64 %x835, 598444045 + %x837 = add i64 %x836, 597728631 + %x838 = sub i64 %x837, 597014925 + %x839 = add i64 %x838, 596302921 + %x840 = sub i64 %x839, 595592614 + %x841 = add i64 %x840, 594883997 + %x842 = sub i64 %x841, 594177064 + %x843 = add i64 %x842, 593471810 + %x844 = sub i64 %x843, 592768227 + %x845 = add i64 %x844, 592066311 + %x846 = sub i64 %x845, 591366055 + %x847 = add i64 %x846, 590667454 + %x848 = sub i64 %x847, 589970501 + %x849 = add i64 %x848, 589275191 + %x850 = sub i64 %x849, 588581518 + %x851 = add i64 %x850, 587889476 + %x852 = sub i64 %x851, 587199060 + %x853 = add i64 %x852, 586510263 + %x854 = sub i64 %x853, 585823081 + %x855 = add i64 %x854, 585137507 + %x856 = sub i64 %x855, 584453535 + %x857 = add i64 %x856, 583771161 + %x858 = sub i64 %x857, 583090379 + %x859 = add i64 %x858, 582411182 + %x860 = sub i64 %x859, 581733566 + %x861 = add i64 %x860, 581057524 + %x862 = sub i64 %x861, 580383052 + %x863 = add i64 %x862, 579710144 + %x864 = sub i64 %x863, 579038795 + %x865 = add i64 %x864, 578368999 + %x866 = sub i64 %x865, 577700751 + %x867 = add i64 %x866, 577034045 + %x868 = sub i64 %x867, 576368876 + %x869 = add i64 %x868, 575705238 + %x870 = sub i64 %x869, 575043128 + %x871 = add i64 %x870, 574382538 + %x872 = sub i64 %x871, 573723465 + %x873 = add i64 %x872, 573065902 + %x874 = sub i64 %x873, 572409845 + %x875 = add i64 %x874, 571755288 + %x876 = sub i64 %x875, 571102227 + %x877 = add i64 %x876, 570450656 + %x878 = sub i64 %x877, 569800569 + %x879 = add i64 %x878, 569151963 + %x880 = sub i64 %x879, 568504832 + %x881 = add i64 %x880, 567859170 + %x882 = sub i64 %x881, 567214974 + %x883 = add i64 %x882, 566572237 + %x884 = sub i64 %x883, 565930956 + %x885 = add i64 %x884, 565291124 + %x886 = sub i64 %x885, 564652738 + %x887 = add i64 %x886, 564015792 + %x888 = sub i64 %x887, 563380281 + %x889 = add i64 %x888, 562746201 + %x890 = sub i64 %x889, 562113546 + %x891 = add i64 %x890, 561482313 + %x892 = sub i64 %x891, 560852495 + %x893 = add i64 %x892, 560224089 + %x894 = sub i64 %x893, 559597090 + %x895 = add i64 %x894, 558971492 + %x896 = sub i64 %x895, 558347292 + %x897 = add i64 %x896, 557724484 + %x898 = sub i64 %x897, 557103064 + %x899 = add i64 %x898, 556483027 + %x900 = sub i64 %x899, 555864369 + %x901 = add i64 %x900, 555247084 + %x902 = sub i64 %x901, 554631170 + %x903 = add i64 %x902, 554016620 + %x904 = sub i64 %x903, 553403431 + %x905 = add i64 %x904, 552791597 + %x906 = sub i64 %x905, 552181115 + %x907 = add i64 %x906, 551571980 + %x908 = sub i64 %x907, 550964187 + %x909 = add i64 %x908, 550357732 + %x910 = sub i64 %x909, 549752611 + %x911 = add i64 %x910, 549148819 + %x912 = sub i64 %x911, 548546352 + %x913 = add i64 %x912, 547945205 + %x914 = sub i64 %x913, 547345374 + %x915 = add i64 %x914, 546746856 + %x916 = sub i64 %x915, 546149645 + %x917 = add i64 %x916, 545553737 + %x918 = sub i64 %x917, 544959128 + %x919 = add i64 %x918, 544365813 + %x920 = sub i64 %x919, 543773790 + %x921 = add i64 %x920, 543183052 + %x922 = sub i64 %x921, 542593597 + %x923 = add i64 %x922, 542005420 + %x924 = sub i64 %x923, 541418516 + %x925 = add i64 %x924, 540832882 + %x926 = sub i64 %x925, 540248514 + %x927 = add i64 %x926, 539665407 + %x928 = sub i64 %x927, 539083557 + %x929 = add i64 %x928, 538502961 + %x930 = sub i64 %x929, 537923614 + %x931 = add i64 %x930, 537345513 + %x932 = sub i64 %x931, 536768652 + %x933 = add i64 %x932, 536193029 + %x934 = sub i64 %x933, 535618639 + %x935 = add i64 %x934, 535045478 + %x936 = sub i64 %x935, 534473543 + %x937 = add i64 %x936, 533902829 + %x938 = sub i64 %x937, 533333333 + %x939 = add i64 %x938, 532765050 + %x940 = sub i64 %x939, 532197977 + %x941 = add i64 %x940, 531632110 + %x942 = sub i64 %x941, 531067445 + %x943 = add i64 %x942, 530503978 + %x944 = sub i64 %x943, 529941706 + %x945 = add i64 %x944, 529380624 + %x946 = sub i64 %x945, 528820729 + %x947 = add i64 %x946, 528262017 + %x948 = sub i64 %x947, 527704485 + %x949 = add i64 %x948, 527148128 + %x950 = sub i64 %x949, 526592943 + %x951 = add i64 %x950, 526038926 + %x952 = sub i64 %x951, 525486074 + %x953 = add i64 %x952, 524934383 + %x954 = sub i64 %x953, 524383848 + %x955 = add i64 %x954, 523834468 + %x956 = sub i64 %x955, 523286237 + %x957 = add i64 %x956, 522739153 + %x958 = sub i64 %x957, 522193211 + %x959 = add i64 %x958, 521648408 + %x960 = sub i64 %x959, 521104742 + %x961 = add i64 %x960, 520562207 + %x962 = sub i64 %x961, 520020800 + %x963 = add i64 %x962, 519480519 + %x964 = sub i64 %x963, 518941359 + %x965 = add i64 %x964, 518403317 + %x966 = sub i64 %x965, 517866390 + %x967 = add i64 %x966, 517330574 + %x968 = sub i64 %x967, 516795865 + %x969 = add i64 %x968, 516262261 + %x970 = sub i64 %x969, 515729757 + %x971 = add i64 %x970, 515198351 + %x972 = sub i64 %x971, 514668039 + %x973 = add i64 %x972, 514138817 + %x974 = sub i64 %x973, 513610683 + %x975 = add i64 %x974, 513083632 + %x976 = sub i64 %x975, 512557662 + %x977 = add i64 %x976, 512032770 + %x978 = sub i64 %x977, 511508951 + %x979 = add i64 %x978, 510986203 + %x980 = sub i64 %x979, 510464522 + %x981 = add i64 %x980, 509943906 + %x982 = sub i64 %x981, 509424350 + %x983 = add i64 %x982, 508905852 + %x984 = sub i64 %x983, 508388408 + %x985 = add i64 %x984, 507872016 + %x986 = sub i64 %x985, 507356671 + %x987 = add i64 %x986, 506842372 + %x988 = sub i64 %x987, 506329113 + %x989 = add i64 %x988, 505816894 + %x990 = sub i64 %x989, 505305709 + %x991 = add i64 %x990, 504795557 + %x992 = sub i64 %x991, 504286434 + %x993 = add i64 %x992, 503778337 + %x994 = sub i64 %x993, 503271263 + %x995 = add i64 %x994, 502765208 + %x996 = sub i64 %x995, 502260170 + %x997 = add i64 %x996, 501756146 + %x998 = sub i64 %x997, 501253132 + %x999 = add i64 %x998, 500751126 + %x1000 = sub i64 %x999, 500250125 + %x1001 = add i64 %x1000, 499750124 + %x1002 = sub i64 %x1001, 499251123 + %x1003 = add i64 %x1002, 498753117 + %x1004 = sub i64 %x1003, 498256103 + %x1005 = add i64 %x1004, 497760079 + %x1006 = sub i64 %x1005, 497265042 + %x1007 = add i64 %x1006, 496770988 + %x1008 = sub i64 %x1007, 496277915 + %x1009 = add i64 %x1008, 495785820 + %x1010 = sub i64 %x1009, 495294700 + %x1011 = add i64 %x1010, 494804552 + %x1012 = sub i64 %x1011, 494315373 + %x1013 = add i64 %x1012, 493827160 + %x1014 = sub i64 %x1013, 493339911 + %x1015 = add i64 %x1014, 492853622 + %x1016 = sub i64 %x1015, 492368291 + %x1017 = add i64 %x1016, 491883915 + %x1018 = sub i64 %x1017, 491400491 + %x1019 = add i64 %x1018, 490918016 + %x1020 = sub i64 %x1019, 490436488 + %x1021 = add i64 %x1020, 489955903 + %x1022 = sub i64 %x1021, 489476260 + %x1023 = add i64 %x1022, 488997555 + %x1024 = sub i64 %x1023, 488519785 + %x1025 = add i64 %x1024, 488042947 + %x1026 = sub i64 %x1025, 487567040 + %x1027 = add i64 %x1026, 487092060 + %x1028 = sub i64 %x1027, 486618004 + %x1029 = add i64 %x1028, 486144871 + %x1030 = sub i64 %x1029, 485672656 + %x1031 = add i64 %x1030, 485201358 + %x1032 = sub i64 %x1031, 484730974 + %x1033 = add i64 %x1032, 484261501 + %x1034 = sub i64 %x1033, 483792936 + %x1035 = add i64 %x1034, 483325277 + %x1036 = sub i64 %x1035, 482858522 + %x1037 = add i64 %x1036, 482392667 + %x1038 = sub i64 %x1037, 481927710 + %x1039 = add i64 %x1038, 481463649 + %x1040 = sub i64 %x1039, 481000481 + %x1041 = add i64 %x1040, 480538202 + %x1042 = sub i64 %x1041, 480076812 + %x1043 = add i64 %x1042, 479616306 + %x1044 = sub i64 %x1043, 479156684 + %x1045 = add i64 %x1044, 478697941 + %x1046 = sub i64 %x1045, 478240076 + %x1047 = add i64 %x1046, 477783086 + %x1048 = sub i64 %x1047, 477326968 + %x1049 = add i64 %x1048, 476871721 + %x1050 = sub i64 %x1049, 476417341 + %x1051 = add i64 %x1050, 475963826 + %x1052 = sub i64 %x1051, 475511174 + %x1053 = add i64 %x1052, 475059382 + %x1054 = sub i64 %x1053, 474608448 + %x1055 = add i64 %x1054, 474158368 + %x1056 = sub i64 %x1055, 473709142 + %x1057 = add i64 %x1056, 473260766 + %x1058 = sub i64 %x1057, 472813238 + %x1059 = add i64 %x1058, 472366556 + %x1060 = sub i64 %x1059, 471920717 + %x1061 = add i64 %x1060, 471475719 + %x1062 = sub i64 %x1061, 471031559 + %x1063 = add i64 %x1062, 470588235 + %x1064 = sub i64 %x1063, 470145745 + %x1065 = add i64 %x1064, 469704086 + %x1066 = sub i64 %x1065, 469263256 + %x1067 = add i64 %x1066, 468823253 + %x1068 = sub i64 %x1067, 468384074 + %x1069 = add i64 %x1068, 467945718 + %x1070 = sub i64 %x1069, 467508181 + %x1071 = add i64 %x1070, 467071461 + %x1072 = sub i64 %x1071, 466635557 + %x1073 = add i64 %x1072, 466200466 + %x1074 = sub i64 %x1073, 465766185 + %x1075 = add i64 %x1074, 465332712 + %x1076 = sub i64 %x1075, 464900046 + %x1077 = add i64 %x1076, 464468183 + %x1078 = sub i64 %x1077, 464037122 + %x1079 = add i64 %x1078, 463606861 + %x1080 = sub i64 %x1079, 463177396 + %x1081 = add i64 %x1080, 462748727 + %x1082 = sub i64 %x1081, 462320850 + %x1083 = add i64 %x1082, 461893764 + %x1084 = sub i64 %x1083, 461467466 + %x1085 = add i64 %x1084, 461041954 + %x1086 = sub i64 %x1085, 460617227 + %x1087 = add i64 %x1086, 460193281 + %x1088 = sub i64 %x1087, 459770114 + %x1089 = add i64 %x1088, 459347726 + %x1090 = sub i64 %x1089, 458926112 + %x1091 = add i64 %x1090, 458505272 + %x1092 = sub i64 %x1091, 458085203 + %x1093 = add i64 %x1092, 457665903 + %x1094 = sub i64 %x1093, 457247370 + %x1095 = add i64 %x1094, 456829602 + %x1096 = sub i64 %x1095, 456412596 + %x1097 = add i64 %x1096, 455996352 + %x1098 = sub i64 %x1097, 455580865 + %x1099 = add i64 %x1098, 455166135 + %x1100 = sub i64 %x1099, 454752160 + %x1101 = add i64 %x1100, 454338936 + %x1102 = sub i64 %x1101, 453926463 + %x1103 = add i64 %x1102, 453514739 + %x1104 = sub i64 %x1103, 453103760 + %x1105 = add i64 %x1104, 452693526 + %x1106 = sub i64 %x1105, 452284034 + %x1107 = add i64 %x1106, 451875282 + %x1108 = sub i64 %x1107, 451467268 + %x1109 = add i64 %x1108, 451059990 + %x1110 = sub i64 %x1109, 450653447 + %x1111 = add i64 %x1110, 450247636 + %x1112 = sub i64 %x1111, 449842555 + %x1113 = add i64 %x1112, 449438202 + %x1114 = sub i64 %x1113, 449034575 + %x1115 = add i64 %x1114, 448631673 + %x1116 = sub i64 %x1115, 448229493 + %x1117 = add i64 %x1116, 447828034 + %x1118 = sub i64 %x1117, 447427293 + %x1119 = add i64 %x1118, 447027268 + %x1120 = sub i64 %x1119, 446627958 + %x1121 = add i64 %x1120, 446229361 + %x1122 = sub i64 %x1121, 445831475 + %x1123 = add i64 %x1122, 445434298 + %x1124 = sub i64 %x1123, 445037828 + %x1125 = add i64 %x1124, 444642063 + %x1126 = sub i64 %x1125, 444247001 + %x1127 = add i64 %x1126, 443852640 + %x1128 = sub i64 %x1127, 443458980 + %x1129 = add i64 %x1128, 443066016 + %x1130 = sub i64 %x1129, 442673749 + %x1131 = add i64 %x1130, 442282176 + %x1132 = sub i64 %x1131, 441891294 + %x1133 = add i64 %x1132, 441501103 + %x1134 = sub i64 %x1133, 441111601 + %x1135 = add i64 %x1134, 440722785 + %x1136 = sub i64 %x1135, 440334654 + %x1137 = add i64 %x1136, 439947206 + %x1138 = sub i64 %x1137, 439560439 + %x1139 = add i64 %x1138, 439174352 + %x1140 = sub i64 %x1139, 438788942 + %x1141 = add i64 %x1140, 438404208 + %x1142 = sub i64 %x1141, 438020148 + %x1143 = add i64 %x1142, 437636761 + %x1144 = sub i64 %x1143, 437254044 + %x1145 = add i64 %x1144, 436871996 + %x1146 = sub i64 %x1145, 436490615 + %x1147 = add i64 %x1146, 436109899 + %x1148 = sub i64 %x1147, 435729847 + %x1149 = add i64 %x1148, 435350457 + %x1150 = sub i64 %x1149, 434971726 + %x1151 = add i64 %x1150, 434593654 + %x1152 = sub i64 %x1151, 434216239 + %x1153 = add i64 %x1152, 433839479 + %x1154 = sub i64 %x1153, 433463372 + %x1155 = add i64 %x1154, 433087916 + %x1156 = sub i64 %x1155, 432713111 + %x1157 = add i64 %x1156, 432338953 + %x1158 = sub i64 %x1157, 431965442 + %x1159 = add i64 %x1158, 431592576 + %x1160 = sub i64 %x1159, 431220353 + %x1161 = add i64 %x1160, 430848772 + %x1162 = sub i64 %x1161, 430477830 + %x1163 = add i64 %x1162, 430107526 + %x1164 = sub i64 %x1163, 429737859 + %x1165 = add i64 %x1164, 429368827 + %x1166 = sub i64 %x1165, 429000429 + %x1167 = add i64 %x1166, 428632661 + %x1168 = sub i64 %x1167, 428265524 + %x1169 = add i64 %x1168, 427899015 + %x1170 = sub i64 %x1169, 427533133 + %x1171 = add i64 %x1170, 427167876 + %x1172 = sub i64 %x1171, 426803243 + %x1173 = add i64 %x1172, 426439232 + %x1174 = sub i64 %x1173, 426075841 + %x1175 = add i64 %x1174, 425713069 + %x1176 = sub i64 %x1175, 425350914 + %x1177 = add i64 %x1176, 424989375 + %x1178 = sub i64 %x1177, 424628450 + %x1179 = add i64 %x1178, 424268137 + %x1180 = sub i64 %x1179, 423908435 + %x1181 = add i64 %x1180, 423549343 + %x1182 = sub i64 %x1181, 423190859 + %x1183 = add i64 %x1182, 422832980 + %x1184 = sub i64 %x1183, 422475707 + %x1185 = add i64 %x1184, 422119037 + %x1186 = sub i64 %x1185, 421762969 + %x1187 = add i64 %x1186, 421407501 + %x1188 = sub i64 %x1187, 421052631 + %x1189 = add i64 %x1188, 420698359 + %x1190 = sub i64 %x1189, 420344682 + %x1191 = add i64 %x1190, 419991600 + %x1192 = sub i64 %x1191, 419639110 + %x1193 = add i64 %x1192, 419287211 + %x1194 = sub i64 %x1193, 418935902 + %x1195 = add i64 %x1194, 418585182 + %x1196 = sub i64 %x1195, 418235048 + %x1197 = add i64 %x1196, 417885499 + %x1198 = sub i64 %x1197, 417536534 + %x1199 = add i64 %x1198, 417188151 + %x1200 = sub i64 %x1199, 416840350 + %x1201 = add i64 %x1200, 416493127 + %x1202 = sub i64 %x1201, 416146483 + %x1203 = add i64 %x1202, 415800415 + %x1204 = sub i64 %x1203, 415454923 + %x1205 = add i64 %x1204, 415110004 + %x1206 = sub i64 %x1205, 414765657 + %x1207 = add i64 %x1206, 414421881 + %x1208 = sub i64 %x1207, 414078674 + %x1209 = add i64 %x1208, 413736036 + %x1210 = sub i64 %x1209, 413393964 + %x1211 = add i64 %x1210, 413052457 + %x1212 = sub i64 %x1211, 412711514 + %x1213 = add i64 %x1212, 412371134 + %x1214 = sub i64 %x1213, 412031314 + %x1215 = add i64 %x1214, 411692054 + %x1216 = sub i64 %x1215, 411353352 + %x1217 = add i64 %x1216, 411015207 + %x1218 = sub i64 %x1217, 410677618 + %x1219 = add i64 %x1218, 410340582 + %x1220 = sub i64 %x1219, 410004100 + %x1221 = add i64 %x1220, 409668168 + %x1222 = sub i64 %x1221, 409332787 + %x1223 = add i64 %x1222, 408997955 + %x1224 = sub i64 %x1223, 408663669 + %x1225 = add i64 %x1224, 408329930 + %x1226 = sub i64 %x1225, 407996736 + %x1227 = add i64 %x1226, 407664084 + %x1228 = sub i64 %x1227, 407331975 + %x1229 = add i64 %x1228, 407000407 + %x1230 = sub i64 %x1229, 406669377 + %x1231 = add i64 %x1230, 406338886 + %x1232 = sub i64 %x1231, 406008932 + %x1233 = add i64 %x1232, 405679513 + %x1234 = sub i64 %x1233, 405350628 + %x1235 = add i64 %x1234, 405022276 + %x1236 = sub i64 %x1235, 404694455 + %x1237 = add i64 %x1236, 404367165 + %x1238 = sub i64 %x1237, 404040404 + %x1239 = add i64 %x1238, 403714170 + %x1240 = sub i64 %x1239, 403388463 + %x1241 = add i64 %x1240, 403063280 + %x1242 = sub i64 %x1241, 402738622 + %x1243 = add i64 %x1242, 402414486 + %x1244 = sub i64 %x1243, 402090872 + %x1245 = add i64 %x1244, 401767778 + %x1246 = sub i64 %x1245, 401445202 + %x1247 = add i64 %x1246, 401123144 + %x1248 = sub i64 %x1247, 400801603 + %x1249 = add i64 %x1248, 400480576 + %x1250 = sub i64 %x1249, 400160064 + %x1251 = add i64 %x1250, 399840063 + %x1252 = sub i64 %x1251, 399520575 + %x1253 = add i64 %x1252, 399201596 + %x1254 = sub i64 %x1253, 398883127 + %x1255 = add i64 %x1254, 398565165 + %x1256 = sub i64 %x1255, 398247710 + %x1257 = add i64 %x1256, 397930760 + %x1258 = sub i64 %x1257, 397614314 + %x1259 = add i64 %x1258, 397298371 + %x1260 = sub i64 %x1259, 396982929 + %x1261 = add i64 %x1260, 396667988 + %x1262 = sub i64 %x1261, 396353547 + %x1263 = add i64 %x1262, 396039603 + %x1264 = sub i64 %x1263, 395726157 + %x1265 = add i64 %x1264, 395413206 + %x1266 = sub i64 %x1265, 395100750 + %x1267 = add i64 %x1266, 394788787 + %x1268 = sub i64 %x1267, 394477317 + %x1269 = add i64 %x1268, 394166338 + %x1270 = sub i64 %x1269, 393855848 + %x1271 = add i64 %x1270, 393545848 + %x1272 = sub i64 %x1271, 393236335 + %x1273 = add i64 %x1272, 392927308 + %x1274 = sub i64 %x1273, 392618767 + %x1275 = add i64 %x1274, 392310710 + %x1276 = sub i64 %x1275, 392003136 + %x1277 = add i64 %x1276, 391696043 + %x1278 = sub i64 %x1277, 391389432 + %x1279 = add i64 %x1278, 391083300 + %x1280 = sub i64 %x1279, 390777647 + %x1281 = add i64 %x1280, 390472471 + %x1282 = sub i64 %x1281, 390167772 + %x1283 = add i64 %x1282, 389863547 + %x1284 = sub i64 %x1283, 389559797 + %x1285 = add i64 %x1284, 389256520 + %x1286 = sub i64 %x1285, 388953714 + %x1287 = add i64 %x1286, 388651379 + %x1288 = sub i64 %x1287, 388349514 + %x1289 = add i64 %x1288, 388048117 + %x1290 = sub i64 %x1289, 387747188 + %x1291 = add i64 %x1290, 387446726 + %x1292 = sub i64 %x1291, 387146728 + %x1293 = add i64 %x1292, 386847195 + %x1294 = sub i64 %x1293, 386548125 + %x1295 = add i64 %x1294, 386249517 + %x1296 = sub i64 %x1295, 385951370 + %x1297 = add i64 %x1296, 385653682 + %x1298 = sub i64 %x1297, 385356454 + %x1299 = add i64 %x1298, 385059684 + %x1300 = sub i64 %x1299, 384763370 + %x1301 = add i64 %x1300, 384467512 + %x1302 = sub i64 %x1301, 384172109 + %x1303 = add i64 %x1302, 383877159 + %x1304 = sub i64 %x1303, 383582662 + %x1305 = add i64 %x1304, 383288616 + %x1306 = sub i64 %x1305, 382995021 + %x1307 = add i64 %x1306, 382701875 + %x1308 = sub i64 %x1307, 382409177 + %x1309 = add i64 %x1308, 382116927 + %x1310 = sub i64 %x1309, 381825124 + %x1311 = add i64 %x1310, 381533765 + %x1312 = sub i64 %x1311, 381242851 + %x1313 = add i64 %x1312, 380952380 + %x1314 = sub i64 %x1313, 380662352 + %x1315 = add i64 %x1314, 380372765 + %x1316 = sub i64 %x1315, 380083618 + %x1317 = add i64 %x1316, 379794910 + %x1318 = sub i64 %x1317, 379506641 + %x1319 = add i64 %x1318, 379218809 + %x1320 = sub i64 %x1319, 378931413 + %x1321 = add i64 %x1320, 378644452 + %x1322 = sub i64 %x1321, 378357926 + %x1323 = add i64 %x1322, 378071833 + %x1324 = sub i64 %x1323, 377786173 + %x1325 = add i64 %x1324, 377500943 + %x1326 = sub i64 %x1325, 377216144 + %x1327 = add i64 %x1326, 376931775 + %x1328 = sub i64 %x1327, 376647834 + %x1329 = add i64 %x1328, 376364320 + %x1330 = sub i64 %x1329, 376081233 + %x1331 = add i64 %x1330, 375798571 + %x1332 = sub i64 %x1331, 375516334 + %x1333 = add i64 %x1332, 375234521 + %x1334 = sub i64 %x1333, 374953130 + %x1335 = add i64 %x1334, 374672161 + %x1336 = sub i64 %x1335, 374391613 + %x1337 = add i64 %x1336, 374111485 + %x1338 = sub i64 %x1337, 373831775 + %x1339 = add i64 %x1338, 373552484 + %x1340 = sub i64 %x1339, 373273609 + %x1341 = add i64 %x1340, 372995151 + %x1342 = sub i64 %x1341, 372717107 + %x1343 = add i64 %x1342, 372439478 + %x1344 = sub i64 %x1343, 372162262 + %x1345 = add i64 %x1344, 371885459 + %x1346 = sub i64 %x1345, 371609067 + %x1347 = add i64 %x1346, 371333085 + %x1348 = sub i64 %x1347, 371057513 + %x1349 = add i64 %x1348, 370782350 + %x1350 = sub i64 %x1349, 370507595 + %x1351 = add i64 %x1350, 370233246 + %x1352 = sub i64 %x1351, 369959304 + %x1353 = add i64 %x1352, 369685767 + %x1354 = sub i64 %x1353, 369412633 + %x1355 = add i64 %x1354, 369139904 + %x1356 = sub i64 %x1355, 368867576 + %x1357 = add i64 %x1356, 368595650 + %x1358 = sub i64 %x1357, 368324125 + %x1359 = add i64 %x1358, 368052999 + %x1360 = sub i64 %x1359, 367782272 + %x1361 = add i64 %x1360, 367511944 + %x1362 = sub i64 %x1361, 367242012 + %x1363 = add i64 %x1362, 366972477 + %x1364 = sub i64 %x1363, 366703337 + %x1365 = add i64 %x1364, 366434591 + %x1366 = sub i64 %x1365, 366166239 + %x1367 = add i64 %x1366, 365898280 + %x1368 = sub i64 %x1367, 365630712 + %x1369 = add i64 %x1368, 365363536 + %x1370 = sub i64 %x1369, 365096750 + %x1371 = add i64 %x1370, 364830353 + %x1372 = sub i64 %x1371, 364564345 + %x1373 = add i64 %x1372, 364298724 + %x1374 = sub i64 %x1373, 364033491 + %x1375 = add i64 %x1374, 363768643 + %x1376 = sub i64 %x1375, 363504180 + %x1377 = add i64 %x1376, 363240101 + %x1378 = sub i64 %x1377, 362976406 + %x1379 = add i64 %x1378, 362713093 + %x1380 = sub i64 %x1379, 362450163 + %x1381 = add i64 %x1380, 362187613 + %x1382 = sub i64 %x1381, 361925443 + %x1383 = add i64 %x1382, 361663652 + %x1384 = sub i64 %x1383, 361402240 + %x1385 = add i64 %x1384, 361141206 + %x1386 = sub i64 %x1385, 360880548 + %x1387 = add i64 %x1386, 360620266 + %x1388 = sub i64 %x1387, 360360360 + %x1389 = add i64 %x1388, 360100828 + %x1390 = sub i64 %x1389, 359841669 + %x1391 = add i64 %x1390, 359582883 + %x1392 = sub i64 %x1391, 359324469 + %x1393 = add i64 %x1392, 359066427 + %x1394 = sub i64 %x1393, 358808754 + %x1395 = add i64 %x1394, 358551452 + %x1396 = sub i64 %x1395, 358294518 + %x1397 = add i64 %x1396, 358037952 + %x1398 = sub i64 %x1397, 357781753 + %x1399 = add i64 %x1398, 357525920 + %x1400 = sub i64 %x1399, 357270453 + %x1401 = add i64 %x1400, 357015351 + %x1402 = sub i64 %x1401, 356760613 + %x1403 = add i64 %x1402, 356506238 + %x1404 = sub i64 %x1403, 356252226 + %x1405 = add i64 %x1404, 355998576 + %x1406 = sub i64 %x1405, 355745286 + %x1407 = add i64 %x1406, 355492356 + %x1408 = sub i64 %x1407, 355239786 + %x1409 = add i64 %x1408, 354987575 + %x1410 = sub i64 %x1409, 354735721 + %x1411 = add i64 %x1410, 354484225 + %x1412 = sub i64 %x1411, 354233085 + %x1413 = add i64 %x1412, 353982300 + %x1414 = sub i64 %x1413, 353731871 + %x1415 = add i64 %x1414, 353481795 + %x1416 = sub i64 %x1415, 353232073 + %x1417 = add i64 %x1416, 352982703 + %x1418 = sub i64 %x1417, 352733686 + %x1419 = add i64 %x1418, 352485019 + %x1420 = sub i64 %x1419, 352236703 + %x1421 = add i64 %x1420, 351988736 + %x1422 = sub i64 %x1421, 351741118 + %x1423 = add i64 %x1422, 351493848 + %x1424 = sub i64 %x1423, 351246926 + %x1425 = add i64 %x1424, 351000351 + %x1426 = sub i64 %x1425, 350754121 + %x1427 = add i64 %x1426, 350508236 + %x1428 = sub i64 %x1427, 350262697 + %x1429 = add i64 %x1428, 350017500 + %x1430 = sub i64 %x1429, 349772647 + %x1431 = add i64 %x1430, 349528137 + %x1432 = sub i64 %x1431, 349283967 + %x1433 = add i64 %x1432, 349040139 + %x1434 = sub i64 %x1433, 348796651 + %x1435 = add i64 %x1434, 348553502 + %x1436 = sub i64 %x1435, 348310693 + %x1437 = add i64 %x1436, 348068221 + %x1438 = sub i64 %x1437, 347826086 + %x1439 = add i64 %x1438, 347584289 + %x1440 = sub i64 %x1439, 347342827 + %x1441 = add i64 %x1440, 347101700 + %x1442 = sub i64 %x1441, 346860908 + %x1443 = add i64 %x1442, 346620450 + %x1444 = sub i64 %x1443, 346380325 + %x1445 = add i64 %x1444, 346140533 + %x1446 = sub i64 %x1445, 345901072 + %x1447 = add i64 %x1446, 345661942 + %x1448 = sub i64 %x1447, 345423143 + %x1449 = add i64 %x1448, 345184673 + %x1450 = sub i64 %x1449, 344946533 + %x1451 = add i64 %x1450, 344708721 + %x1452 = sub i64 %x1451, 344471236 + %x1453 = add i64 %x1452, 344234079 + %x1454 = sub i64 %x1453, 343997248 + %x1455 = add i64 %x1454, 343760742 + %x1456 = sub i64 %x1455, 343524562 + %x1457 = add i64 %x1456, 343288705 + %x1458 = sub i64 %x1457, 343053173 + %x1459 = add i64 %x1458, 342817963 + %x1460 = sub i64 %x1459, 342583076 + %x1461 = add i64 %x1460, 342348510 + %x1462 = sub i64 %x1461, 342114266 + %x1463 = add i64 %x1462, 341880341 + %x1464 = sub i64 %x1463, 341646737 + %x1465 = add i64 %x1464, 341413451 + %x1466 = sub i64 %x1465, 341180484 + %x1467 = add i64 %x1466, 340947834 + %x1468 = sub i64 %x1467, 340715502 + %x1469 = add i64 %x1468, 340483486 + %x1470 = sub i64 %x1469, 340251786 + %x1471 = add i64 %x1470, 340020401 + %x1472 = sub i64 %x1471, 339789330 + %x1473 = add i64 %x1472, 339558573 + %x1474 = sub i64 %x1473, 339328130 + %x1475 = add i64 %x1474, 339097999 + %x1476 = sub i64 %x1475, 338868180 + %x1477 = add i64 %x1476, 338638672 + %x1478 = sub i64 %x1477, 338409475 + %x1479 = add i64 %x1478, 338180588 + %x1480 = sub i64 %x1479, 337952010 + %x1481 = add i64 %x1480, 337723741 + %x1482 = sub i64 %x1481, 337495781 + %x1483 = add i64 %x1482, 337268128 + %x1484 = sub i64 %x1483, 337040781 + %x1485 = add i64 %x1484, 336813742 + %x1486 = sub i64 %x1485, 336587007 + %x1487 = add i64 %x1486, 336360578 + %x1488 = sub i64 %x1487, 336134453 + %x1489 = add i64 %x1488, 335908632 + %x1490 = sub i64 %x1489, 335683115 + %x1491 = add i64 %x1490, 335457900 + %x1492 = sub i64 %x1491, 335232986 + %x1493 = add i64 %x1492, 335008375 + %x1494 = sub i64 %x1493, 334784064 + %x1495 = add i64 %x1494, 334560053 + %x1496 = sub i64 %x1495, 334336342 + %x1497 = add i64 %x1496, 334112930 + %x1498 = sub i64 %x1497, 333889816 + %x1499 = add i64 %x1498, 333667000 + %x1500 = sub i64 %x1499, 333444481 + %x1501 = add i64 %x1500, 333222259 + %x1502 = sub i64 %x1501, 333000333 + %x1503 = add i64 %x1502, 332778702 + %x1504 = sub i64 %x1503, 332557366 + %x1505 = add i64 %x1504, 332336324 + %x1506 = sub i64 %x1505, 332115576 + %x1507 = add i64 %x1506, 331895121 + %x1508 = sub i64 %x1507, 331674958 + %x1509 = add i64 %x1508, 331455087 + %x1510 = sub i64 %x1509, 331235508 + %x1511 = add i64 %x1510, 331016219 + %x1512 = sub i64 %x1511, 330797221 + %x1513 = add i64 %x1512, 330578512 + %x1514 = sub i64 %x1513, 330360092 + %x1515 = add i64 %x1514, 330141961 + %x1516 = sub i64 %x1515, 329924117 + %x1517 = add i64 %x1516, 329706561 + %x1518 = sub i64 %x1517, 329489291 + %x1519 = add i64 %x1518, 329272308 + %x1520 = sub i64 %x1519, 329055610 + %x1521 = add i64 %x1520, 328839197 + %x1522 = sub i64 %x1521, 328623069 + %x1523 = add i64 %x1522, 328407224 + %x1524 = sub i64 %x1523, 328191663 + %x1525 = add i64 %x1524, 327976385 + %x1526 = sub i64 %x1525, 327761389 + %x1527 = add i64 %x1526, 327546675 + %x1528 = sub i64 %x1527, 327332242 + %x1529 = add i64 %x1528, 327118089 + %x1530 = sub i64 %x1529, 326904217 + %x1531 = add i64 %x1530, 326690623 + %x1532 = sub i64 %x1531, 326477309 + %x1533 = add i64 %x1532, 326264274 + %x1534 = sub i64 %x1533, 326051516 + %x1535 = add i64 %x1534, 325839035 + %x1536 = sub i64 %x1535, 325626831 + %x1537 = add i64 %x1536, 325414904 + %x1538 = sub i64 %x1537, 325203252 + %x1539 = add i64 %x1538, 324991875 + %x1540 = sub i64 %x1539, 324780772 + %x1541 = add i64 %x1540, 324569944 + %x1542 = sub i64 %x1541, 324359390 + %x1543 = add i64 %x1542, 324149108 + %x1544 = sub i64 %x1543, 323939099 + %x1545 = add i64 %x1544, 323729362 + %x1546 = sub i64 %x1545, 323519896 + %x1547 = add i64 %x1546, 323310701 + %x1548 = sub i64 %x1547, 323101777 + %x1549 = add i64 %x1548, 322893122 + %x1550 = sub i64 %x1549, 322684737 + %x1551 = add i64 %x1550, 322476620 + %x1552 = sub i64 %x1551, 322268772 + %x1553 = add i64 %x1552, 322061191 + %x1554 = sub i64 %x1553, 321853878 + %x1555 = add i64 %x1554, 321646831 + %x1556 = sub i64 %x1555, 321440051 + %x1557 = add i64 %x1556, 321233536 + %x1558 = sub i64 %x1557, 321027287 + %x1559 = add i64 %x1558, 320821302 + %x1560 = sub i64 %x1559, 320615581 + %x1561 = add i64 %x1560, 320410124 + %x1562 = sub i64 %x1561, 320204931 + %x1563 = add i64 %x1562, 320000000 + %x1564 = sub i64 %x1563, 319795330 + %x1565 = add i64 %x1564, 319590923 + %x1566 = sub i64 %x1565, 319386777 + %x1567 = add i64 %x1566, 319182891 + %x1568 = sub i64 %x1567, 318979266 + %x1569 = add i64 %x1568, 318775900 + %x1570 = sub i64 %x1569, 318572793 + %x1571 = add i64 %x1570, 318369945 + %x1572 = sub i64 %x1571, 318167356 + %x1573 = add i64 %x1572, 317965023 + %x1574 = sub i64 %x1573, 317762948 + %x1575 = add i64 %x1574, 317561130 + %x1576 = sub i64 %x1575, 317359568 + %x1577 = add i64 %x1576, 317158261 + %x1578 = sub i64 %x1577, 316957210 + %x1579 = add i64 %x1578, 316756414 + %x1580 = sub i64 %x1579, 316555872 + %x1581 = add i64 %x1580, 316355583 + %x1582 = sub i64 %x1581, 316155548 + %x1583 = add i64 %x1582, 315955766 + %x1584 = sub i64 %x1583, 315756236 + %x1585 = add i64 %x1584, 315556958 + %x1586 = sub i64 %x1585, 315357931 + %x1587 = add i64 %x1586, 315159155 + %x1588 = sub i64 %x1587, 314960629 + %x1589 = add i64 %x1588, 314762354 + %x1590 = sub i64 %x1589, 314564328 + %x1591 = add i64 %x1590, 314366551 + %x1592 = sub i64 %x1591, 314169022 + %x1593 = add i64 %x1592, 313971742 + %x1594 = sub i64 %x1593, 313774709 + %x1595 = add i64 %x1594, 313577924 + %x1596 = sub i64 %x1595, 313381385 + %x1597 = add i64 %x1596, 313185092 + %x1598 = sub i64 %x1597, 312989045 + %x1599 = add i64 %x1598, 312793243 + %x1600 = sub i64 %x1599, 312597686 + %x1601 = add i64 %x1600, 312402374 + %x1602 = sub i64 %x1601, 312207305 + %x1603 = add i64 %x1602, 312012480 + %x1604 = sub i64 %x1603, 311817898 + %x1605 = add i64 %x1604, 311623558 + %x1606 = sub i64 %x1605, 311429461 + %x1607 = add i64 %x1606, 311235605 + %x1608 = sub i64 %x1607, 311041990 + %x1609 = add i64 %x1608, 310848616 + %x1610 = sub i64 %x1609, 310655483 + %x1611 = add i64 %x1610, 310462589 + %x1612 = sub i64 %x1611, 310269934 + %x1613 = add i64 %x1612, 310077519 + %x1614 = sub i64 %x1613, 309885342 + %x1615 = add i64 %x1614, 309693403 + %x1616 = sub i64 %x1615, 309501702 + %x1617 = add i64 %x1616, 309310238 + %x1618 = sub i64 %x1617, 309119010 + %x1619 = add i64 %x1618, 308928019 + %x1620 = sub i64 %x1619, 308737264 + %x1621 = add i64 %x1620, 308546744 + %x1622 = sub i64 %x1621, 308356460 + %x1623 = add i64 %x1622, 308166409 + %x1624 = sub i64 %x1623, 307976593 + %x1625 = add i64 %x1624, 307787011 + %x1626 = sub i64 %x1625, 307597662 + %x1627 = add i64 %x1626, 307408545 + %x1628 = sub i64 %x1627, 307219662 + %x1629 = add i64 %x1628, 307031010 + %x1630 = sub i64 %x1629, 306842589 + %x1631 = add i64 %x1630, 306654400 + %x1632 = sub i64 %x1631, 306466441 + %x1633 = add i64 %x1632, 306278713 + %x1634 = sub i64 %x1633, 306091215 + %x1635 = add i64 %x1634, 305903946 + %x1636 = sub i64 %x1635, 305716906 + %x1637 = add i64 %x1636, 305530094 + %x1638 = sub i64 %x1637, 305343511 + %x1639 = add i64 %x1638, 305157155 + %x1640 = sub i64 %x1639, 304971027 + %x1641 = add i64 %x1640, 304785126 + %x1642 = sub i64 %x1641, 304599451 + %x1643 = add i64 %x1642, 304414003 + %x1644 = sub i64 %x1643, 304228780 + %x1645 = add i64 %x1644, 304043782 + %x1646 = sub i64 %x1645, 303859009 + %x1647 = add i64 %x1646, 303674460 + %x1648 = sub i64 %x1647, 303490136 + %x1649 = add i64 %x1648, 303306035 + %x1650 = sub i64 %x1649, 303122158 + %x1651 = add i64 %x1650, 302938503 + %x1652 = sub i64 %x1651, 302755071 + %x1653 = add i64 %x1652, 302571860 + %x1654 = sub i64 %x1653, 302388872 + %x1655 = add i64 %x1654, 302206104 + %x1656 = sub i64 %x1655, 302023557 + %x1657 = add i64 %x1656, 301841231 + %x1658 = sub i64 %x1657, 301659125 + %x1659 = add i64 %x1658, 301477238 + %x1660 = sub i64 %x1659, 301295570 + %x1661 = add i64 %x1660, 301114122 + %x1662 = sub i64 %x1661, 300932891 + %x1663 = add i64 %x1662, 300751879 + %x1664 = sub i64 %x1663, 300571085 + %x1665 = add i64 %x1664, 300390507 + %x1666 = sub i64 %x1665, 300210147 + %x1667 = add i64 %x1666, 300030003 + %x1668 = sub i64 %x1667, 299850074 + %x1669 = add i64 %x1668, 299670362 + %x1670 = sub i64 %x1669, 299490865 + %x1671 = add i64 %x1670, 299311583 + %x1672 = sub i64 %x1671, 299132515 + %x1673 = add i64 %x1672, 298953662 + %x1674 = sub i64 %x1673, 298775022 + %x1675 = add i64 %x1674, 298596595 + %x1676 = sub i64 %x1675, 298418382 + %x1677 = add i64 %x1676, 298240381 + %x1678 = sub i64 %x1677, 298062593 + %x1679 = add i64 %x1678, 297885016 + %x1680 = sub i64 %x1679, 297707651 + %x1681 = add i64 %x1680, 297530496 + %x1682 = sub i64 %x1681, 297353553 + %x1683 = add i64 %x1682, 297176820 + %x1684 = sub i64 %x1683, 297000297 + %x1685 = add i64 %x1684, 296823983 + %x1686 = sub i64 %x1685, 296647878 + %x1687 = add i64 %x1686, 296471983 + %x1688 = sub i64 %x1687, 296296296 + %x1689 = add i64 %x1688, 296120817 + %x1690 = sub i64 %x1689, 295945546 + %x1691 = add i64 %x1690, 295770482 + %x1692 = sub i64 %x1691, 295595625 + %x1693 = add i64 %x1692, 295420974 + %x1694 = sub i64 %x1693, 295246530 + %x1695 = add i64 %x1694, 295072292 + %x1696 = sub i64 %x1695, 294898260 + %x1697 = add i64 %x1696, 294724432 + %x1698 = sub i64 %x1697, 294550810 + %x1699 = add i64 %x1698, 294377391 + %x1700 = sub i64 %x1699, 294204177 + %x1701 = add i64 %x1700, 294031167 + %x1702 = sub i64 %x1701, 293858360 + %x1703 = add i64 %x1702, 293685756 + %x1704 = sub i64 %x1703, 293513354 + %x1705 = add i64 %x1704, 293341155 + %x1706 = sub i64 %x1705, 293169158 + %x1707 = add i64 %x1706, 292997363 + %x1708 = sub i64 %x1707, 292825768 + %x1709 = add i64 %x1708, 292654375 + %x1710 = sub i64 %x1709, 292483182 + %x1711 = add i64 %x1710, 292312189 + %x1712 = sub i64 %x1711, 292141396 + %x1713 = add i64 %x1712, 291970802 + %x1714 = sub i64 %x1713, 291800408 + %x1715 = add i64 %x1714, 291630212 + %x1716 = sub i64 %x1715, 291460215 + %x1717 = add i64 %x1716, 291290416 + %x1718 = sub i64 %x1717, 291120815 + %x1719 = add i64 %x1718, 290951411 + %x1720 = sub i64 %x1719, 290782204 + %x1721 = add i64 %x1720, 290613193 + %x1722 = sub i64 %x1721, 290444379 + %x1723 = add i64 %x1722, 290275761 + %x1724 = sub i64 %x1723, 290107339 + %x1725 = add i64 %x1724, 289939112 + %x1726 = sub i64 %x1725, 289771080 + %x1727 = add i64 %x1726, 289603243 + %x1728 = sub i64 %x1727, 289435600 + %x1729 = add i64 %x1728, 289268151 + %x1730 = sub i64 %x1729, 289100896 + %x1731 = add i64 %x1730, 288933834 + %x1732 = sub i64 %x1731, 288766965 + %x1733 = add i64 %x1732, 288600288 + %x1734 = sub i64 %x1733, 288433804 + %x1735 = add i64 %x1734, 288267512 + %x1736 = sub i64 %x1735, 288101411 + %x1737 = add i64 %x1736, 287935502 + %x1738 = sub i64 %x1737, 287769784 + %x1739 = add i64 %x1738, 287604256 + %x1740 = sub i64 %x1739, 287438919 + %x1741 = add i64 %x1740, 287273771 + %x1742 = sub i64 %x1741, 287108814 + %x1743 = add i64 %x1742, 286944045 + %x1744 = sub i64 %x1743, 286779466 + %x1745 = add i64 %x1744, 286615075 + %x1746 = sub i64 %x1745, 286450873 + %x1747 = add i64 %x1746, 286286859 + %x1748 = sub i64 %x1747, 286123032 + %x1749 = add i64 %x1748, 285959393 + %x1750 = sub i64 %x1749, 285795941 + %x1751 = add i64 %x1750, 285632676 + %x1752 = sub i64 %x1751, 285469597 + %x1753 = add i64 %x1752, 285306704 + %x1754 = sub i64 %x1753, 285143997 + %x1755 = add i64 %x1754, 284981476 + %x1756 = sub i64 %x1755, 284819139 + %x1757 = add i64 %x1756, 284656988 + %x1758 = sub i64 %x1757, 284495021 + %x1759 = add i64 %x1758, 284333238 + %x1760 = sub i64 %x1759, 284171639 + %x1761 = add i64 %x1760, 284010224 + %x1762 = sub i64 %x1761, 283848992 + %x1763 = add i64 %x1762, 283687943 + %x1764 = sub i64 %x1763, 283527076 + %x1765 = add i64 %x1764, 283366392 + %x1766 = sub i64 %x1765, 283205890 + %x1767 = add i64 %x1766, 283045570 + %x1768 = sub i64 %x1767, 282885431 + %x1769 = add i64 %x1768, 282725473 + %x1770 = sub i64 %x1769, 282565696 + %x1771 = add i64 %x1770, 282406099 + %x1772 = sub i64 %x1771, 282246683 + %x1773 = add i64 %x1772, 282087447 + %x1774 = sub i64 %x1773, 281928390 + %x1775 = add i64 %x1774, 281769512 + %x1776 = sub i64 %x1775, 281610813 + %x1777 = add i64 %x1776, 281452293 + %x1778 = sub i64 %x1777, 281293952 + %x1779 = add i64 %x1778, 281135788 + %x1780 = sub i64 %x1779, 280977802 + %x1781 = add i64 %x1780, 280819994 + %x1782 = sub i64 %x1781, 280662363 + %x1783 = add i64 %x1782, 280504908 + %x1784 = sub i64 %x1783, 280347631 + %x1785 = add i64 %x1784, 280190529 + %x1786 = sub i64 %x1785, 280033604 + %x1787 = add i64 %x1786, 279876854 + %x1788 = sub i64 %x1787, 279720279 + %x1789 = add i64 %x1788, 279563880 + %x1790 = sub i64 %x1789, 279407655 + %x1791 = add i64 %x1790, 279251605 + %x1792 = sub i64 %x1791, 279095729 + %x1793 = add i64 %x1792, 278940027 + %x1794 = sub i64 %x1793, 278784499 + %x1795 = add i64 %x1794, 278629144 + %x1796 = sub i64 %x1795, 278473962 + %x1797 = add i64 %x1796, 278318953 + %x1798 = sub i64 %x1797, 278164116 + %x1799 = add i64 %x1798, 278009452 + %x1800 = sub i64 %x1799, 277854959 + %x1801 = add i64 %x1800, 277700638 + %x1802 = sub i64 %x1801, 277546489 + %x1803 = add i64 %x1802, 277392510 + %x1804 = sub i64 %x1803, 277238702 + %x1805 = add i64 %x1804, 277085065 + %x1806 = sub i64 %x1805, 276931597 + %x1807 = add i64 %x1806, 276778300 + %x1808 = sub i64 %x1807, 276625172 + %x1809 = add i64 %x1808, 276472214 + %x1810 = sub i64 %x1809, 276319425 + %x1811 = add i64 %x1810, 276166804 + %x1812 = sub i64 %x1811, 276014352 + %x1813 = add i64 %x1812, 275862068 + %x1814 = sub i64 %x1813, 275709953 + %x1815 = add i64 %x1814, 275558004 + %x1816 = sub i64 %x1815, 275406224 + %x1817 = add i64 %x1816, 275254610 + %x1818 = sub i64 %x1817, 275103163 + %x1819 = add i64 %x1818, 274951883 + %x1820 = sub i64 %x1819, 274800769 + %x1821 = add i64 %x1820, 274649821 + %x1822 = sub i64 %x1821, 274499039 + %x1823 = add i64 %x1822, 274348422 + %x1824 = sub i64 %x1823, 274197970 + %x1825 = add i64 %x1824, 274047684 + %x1826 = sub i64 %x1825, 273897562 + %x1827 = add i64 %x1826, 273747604 + %x1828 = sub i64 %x1827, 273597811 + %x1829 = add i64 %x1828, 273448181 + %x1830 = sub i64 %x1829, 273298715 + %x1831 = add i64 %x1830, 273149412 + %x1832 = sub i64 %x1831, 273000273 + %x1833 = add i64 %x1832, 272851296 + %x1834 = sub i64 %x1833, 272702481 + %x1835 = add i64 %x1834, 272553829 + %x1836 = sub i64 %x1835, 272405339 + %x1837 = add i64 %x1836, 272257010 + %x1838 = sub i64 %x1837, 272108843 + %x1839 = add i64 %x1838, 271960837 + %x1840 = sub i64 %x1839, 271812992 + %x1841 = add i64 %x1840, 271665308 + %x1842 = sub i64 %x1841, 271517784 + %x1843 = add i64 %x1842, 271370420 + %x1844 = sub i64 %x1843, 271223216 + %x1845 = add i64 %x1844, 271076172 + %x1846 = sub i64 %x1845, 270929287 + %x1847 = add i64 %x1846, 270782561 + %x1848 = sub i64 %x1847, 270635994 + %x1849 = add i64 %x1848, 270489586 + %x1850 = sub i64 %x1849, 270343336 + %x1851 = add i64 %x1850, 270197243 + %x1852 = sub i64 %x1851, 270051309 + %x1853 = add i64 %x1852, 269905533 + %x1854 = sub i64 %x1853, 269759913 + %x1855 = add i64 %x1854, 269614451 + %x1856 = sub i64 %x1855, 269469145 + %x1857 = add i64 %x1856, 269323996 + %x1858 = sub i64 %x1857, 269179004 + %x1859 = add i64 %x1858, 269034167 + %x1860 = sub i64 %x1859, 268889486 + %x1861 = add i64 %x1860, 268744961 + %x1862 = sub i64 %x1861, 268600590 + %x1863 = add i64 %x1862, 268456375 + %x1864 = sub i64 %x1863, 268312315 + %x1865 = add i64 %x1864, 268168409 + %x1866 = sub i64 %x1865, 268024658 + %x1867 = add i64 %x1866, 267881060 + %x1868 = sub i64 %x1867, 267737617 + %x1869 = add i64 %x1868, 267594327 + %x1870 = sub i64 %x1869, 267451190 + %x1871 = add i64 %x1870, 267308206 + %x1872 = sub i64 %x1871, 267165375 + %x1873 = add i64 %x1872, 267022696 + %x1874 = sub i64 %x1873, 266880170 + %x1875 = add i64 %x1874, 266737796 + %x1876 = sub i64 %x1875, 266595574 + %x1877 = add i64 %x1876, 266453503 + %x1878 = sub i64 %x1877, 266311584 + %x1879 = add i64 %x1878, 266169816 + %x1880 = sub i64 %x1879, 266028198 + %x1881 = add i64 %x1880, 265886732 + %x1882 = sub i64 %x1881, 265745415 + %x1883 = add i64 %x1882, 265604249 + %x1884 = sub i64 %x1883, 265463233 + %x1885 = add i64 %x1884, 265322366 + %x1886 = sub i64 %x1885, 265181649 + %x1887 = add i64 %x1886, 265041081 + %x1888 = sub i64 %x1887, 264900662 + %x1889 = add i64 %x1888, 264760391 + %x1890 = sub i64 %x1889, 264620269 + %x1891 = add i64 %x1890, 264480296 + %x1892 = sub i64 %x1891, 264340470 + %x1893 = add i64 %x1892, 264200792 + %x1894 = sub i64 %x1893, 264061262 + %x1895 = add i64 %x1894, 263921879 + %x1896 = sub i64 %x1895, 263782643 + %x1897 = add i64 %x1896, 263643553 + %x1898 = sub i64 %x1897, 263504611 + %x1899 = add i64 %x1898, 263365815 + %x1900 = sub i64 %x1899, 263227165 + %x1901 = add i64 %x1900, 263088660 + %x1902 = sub i64 %x1901, 262950302 + %x1903 = add i64 %x1902, 262812089 + %x1904 = sub i64 %x1903, 262674021 + %x1905 = add i64 %x1904, 262536098 + %x1906 = sub i64 %x1905, 262398320 + %x1907 = add i64 %x1906, 262260687 + %x1908 = sub i64 %x1907, 262123197 + %x1909 = add i64 %x1908, 261985852 + %x1910 = sub i64 %x1909, 261848651 + %x1911 = add i64 %x1910, 261711593 + %x1912 = sub i64 %x1911, 261574679 + %x1913 = add i64 %x1912, 261437908 + %x1914 = sub i64 %x1913, 261301280 + %x1915 = add i64 %x1914, 261164794 + %x1916 = sub i64 %x1915, 261028452 + %x1917 = add i64 %x1916, 260892251 + %x1918 = sub i64 %x1917, 260756192 + %x1919 = add i64 %x1918, 260620276 + %x1920 = sub i64 %x1919, 260484501 + %x1921 = add i64 %x1920, 260348867 + %x1922 = sub i64 %x1921, 260213374 + %x1923 = add i64 %x1922, 260078023 + %x1924 = sub i64 %x1923, 259942812 + %x1925 = add i64 %x1924, 259807742 + %x1926 = sub i64 %x1925, 259672812 + %x1927 = add i64 %x1926, 259538022 + %x1928 = sub i64 %x1927, 259403372 + %x1929 = add i64 %x1928, 259268861 + %x1930 = sub i64 %x1929, 259134490 + %x1931 = add i64 %x1930, 259000259 + %x1932 = sub i64 %x1931, 258866166 + %x1933 = add i64 %x1932, 258732212 + %x1934 = sub i64 %x1933, 258598396 + %x1935 = add i64 %x1934, 258464719 + %x1936 = sub i64 %x1935, 258331180 + %x1937 = add i64 %x1936, 258197779 + %x1938 = sub i64 %x1937, 258064516 + %x1939 = add i64 %x1938, 257931390 + %x1940 = sub i64 %x1939, 257798401 + %x1941 = add i64 %x1940, 257665550 + %x1942 = sub i64 %x1941, 257532835 + %x1943 = add i64 %x1942, 257400257 + %x1944 = sub i64 %x1943, 257267815 + %x1945 = add i64 %x1944, 257135510 + %x1946 = sub i64 %x1945, 257003341 + %x1947 = add i64 %x1946, 256871307 + %x1948 = sub i64 %x1947, 256739409 + %x1949 = add i64 %x1948, 256607646 + %x1950 = sub i64 %x1949, 256476019 + %x1951 = add i64 %x1950, 256344527 + %x1952 = sub i64 %x1951, 256213169 + %x1953 = add i64 %x1952, 256081946 + %x1954 = sub i64 %x1953, 255950857 + %x1955 = add i64 %x1954, 255819902 + %x1956 = sub i64 %x1955, 255689082 + %x1957 = add i64 %x1956, 255558395 + %x1958 = sub i64 %x1957, 255427841 + %x1959 = add i64 %x1958, 255297421 + %x1960 = sub i64 %x1959, 255167134 + %x1961 = add i64 %x1960, 255036980 + %x1962 = sub i64 %x1961, 254906958 + %x1963 = add i64 %x1962, 254777070 + %x1964 = sub i64 %x1963, 254647313 + %x1965 = add i64 %x1964, 254517688 + %x1966 = sub i64 %x1965, 254388196 + %x1967 = add i64 %x1966, 254258835 + %x1968 = sub i64 %x1967, 254129606 + %x1969 = add i64 %x1968, 254000508 + %x1970 = sub i64 %x1969, 253871541 + %x1971 = add i64 %x1970, 253742704 + %x1972 = sub i64 %x1971, 253613999 + %x1973 = add i64 %x1972, 253485424 + %x1974 = sub i64 %x1973, 253356979 + %x1975 = add i64 %x1974, 253228665 + %x1976 = sub i64 %x1975, 253100480 + %x1977 = add i64 %x1976, 252972426 + %x1978 = sub i64 %x1977, 252844500 + %x1979 = add i64 %x1978, 252716704 + %x1980 = sub i64 %x1979, 252589037 + %x1981 = add i64 %x1980, 252461499 + %x1982 = sub i64 %x1981, 252334090 + %x1983 = add i64 %x1982, 252206809 + %x1984 = sub i64 %x1983, 252079657 + %x1985 = add i64 %x1984, 251952632 + %x1986 = sub i64 %x1985, 251825736 + %x1987 = add i64 %x1986, 251698968 + %x1988 = sub i64 %x1987, 251572327 + %x1989 = add i64 %x1988, 251445813 + %x1990 = sub i64 %x1989, 251319426 + %x1991 = add i64 %x1990, 251193167 + %x1992 = sub i64 %x1991, 251067034 + %x1993 = add i64 %x1992, 250941028 + %x1994 = sub i64 %x1993, 250815149 + %x1995 = add i64 %x1994, 250689395 + %x1996 = sub i64 %x1995, 250563768 + %x1997 = add i64 %x1996, 250438266 + %x1998 = sub i64 %x1997, 250312891 + %x1999 = add i64 %x1998, 250187640 + %x2000 = sub i64 %x1999, 250062515 + %pi = mul i64 %x2000, 4 + %bop1 = icmp eq i64 %pi, 3141092653592 + br i1 %bop1, label %then1, label %else1 +then1: + ret i64 0 +else1: + ret i64 1 +} + diff --git a/hw3/llprograms/kaiterry_pi_opt.ll b/hw3/llprograms/kaiterry_pi_opt.ll new file mode 100644 index 0000000..50a0319 --- /dev/null +++ b/hw3/llprograms/kaiterry_pi_opt.ll @@ -0,0 +1,8 @@ +define i64 @main(i64 %argc, i8** %argv) { + br i1 1, label %then1, label %else1 +then1: + ret i64 0 +else1: + ret i64 1 +} + diff --git a/hw3/llprograms/kaiterry_units.ll b/hw3/llprograms/kaiterry_units.ll new file mode 100644 index 0000000..c4fccf7 --- /dev/null +++ b/hw3/llprograms/kaiterry_units.ll @@ -0,0 +1,54 @@ +define i64 @main(i64 %argc, i8** %argv) { + %one = add i64 0, 1 + %none = sub i64 0, %one + %five = add i64 0, 5 + %nfive = sub i64 0, %five + %ten = add i64 0, 10 + %nten = sub i64 0, %ten + %sixty = add i64 0, 60 + %1 = add i64 %ten, %five + %2 = sub i64 %ten, %five + %3 = mul i64 %ten, %five + %4 = shl i64 %ten, %one + %5 = lshr i64 %nten, %sixty + %6 = ashr i64 %nten, %one + %7 = and i64 %five, %one + %8 = or i64 %ten, %five + %9 = xor i64 %ten, %five + %t1 = icmp eq i64 %1, 15 + %t2 = icmp eq i64 %2, 5 + %t3 = icmp eq i64 %3, 50 + %t4 = icmp eq i64 %4, 20 + %t5 = icmp eq i64 %5, 15 + %t6 = icmp eq i64 %6, %nfive + %t7 = icmp eq i64 %7, 1 + %t8 = icmp eq i64 %8, 15 + %t9 = icmp eq i64 %9, 15 + %t9a = icmp ne i64 %9, 14 + %t9b = icmp slt i64 %9, 16 + %t9c = icmp sle i64 %9, 15 + %t9d = icmp sgt i64 %9, 14 + %t9e = icmp sgt i64 %9, %none + %t9f = icmp sge i64 %9, 15 + %r1 = and i1 %t1, 1 + %r2 = and i1 %t2, %r1 + %r3 = and i1 %t3, %r2 + %r4 = and i1 %t4, %r3 + %r5 = and i1 %t5, %r4 + %r6 = and i1 %t6, %r5 + %r7 = and i1 %t7, %r6 + %r8 = and i1 %t8, %r7 + %r9 = and i1 %t9, %r8 + %r9a = and i1 %t9a, %r9 + %r9b = and i1 %t9b, %r9a + %r9c = and i1 %t9c, %r9b + %r9d = and i1 %t9d, %r9c + %r9e = and i1 %t9e, %r9d + %r9f = and i1 %t9f, %r9e + br i1 %r9f, label %then1, label %else1 +then1: + ret i64 1 +else1: + ret i64 0 +} + diff --git a/hw3/llprograms/kaiterry_units_opt.ll b/hw3/llprograms/kaiterry_units_opt.ll new file mode 100644 index 0000000..984dc45 --- /dev/null +++ b/hw3/llprograms/kaiterry_units_opt.ll @@ -0,0 +1,8 @@ +define i64 @main(i64 %argc, i8** %argv) { + br i1 1, label %then1, label %else1 +then1: + ret i64 1 +else1: + ret i64 0 +} + diff --git a/hw3/llprograms/kierajmumick.ll b/hw3/llprograms/kierajmumick.ll new file mode 100644 index 0000000..1be5e0f --- /dev/null +++ b/hw3/llprograms/kierajmumick.ll @@ -0,0 +1,9 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 30, 0 + %2 = sub i64 420, 24 + %3 = add i64 24, %2 + %4 = alloca i64 + store i64 %3, i64* %4 + ret i64 420 +} + diff --git a/hw3/llprograms/kierajmumickopt.ll b/hw3/llprograms/kierajmumickopt.ll new file mode 100644 index 0000000..65d615e --- /dev/null +++ b/hw3/llprograms/kierajmumickopt.ll @@ -0,0 +1,4 @@ +define i64 @program(i64 %argc, i8** %argv) { + ret i64 420 +} + diff --git a/hw3/llprograms/lfsr.ll b/hw3/llprograms/lfsr.ll new file mode 100644 index 0000000..679bd44 --- /dev/null +++ b/hw3/llprograms/lfsr.ll @@ -0,0 +1,29 @@ +define i64 @one_iteration(i64 %n) { + %1 = shl i64 %n, 1 + %2 = xor i64 %n, %1 + %3 = shl i64 %1, 2 + %4 = xor i64 %2, %3 + %5 = shl i64 %3, 1 + %6 = xor i64 %4, %5 + %7 = lshr i64 %6, 63 + %8 = and i64 %7, 1 + %9 = or i64 %6, %8 + ret i64 %9 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %ctr = alloca i64 + store i64 1, i64* %ctr + %1 = add i64 12, 0 + br i1 1, label %loop, label %loop +loop: + %2 = load i64, i64* %ctr + %3 = add i64 %2, 1 + store i64 %3, i64* %ctr + %4 = call i64 @one_iteration(i64 %2) + %cmp = icmp eq i64 %3, 5 + br i1 %cmp, label %end, label %loop +end: + ret i64 %4 +} + diff --git a/hw3/llprograms/linear_search.ll b/hw3/llprograms/linear_search.ll new file mode 100644 index 0000000..3411abe --- /dev/null +++ b/hw3/llprograms/linear_search.ll @@ -0,0 +1,28 @@ +@glist = global [5 x i64] [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @search(i64 %x, [5 x i64]* %list) { + %i = alloca i64 + store i64 0, i64* %i + br label %loop +loop: + %count = load i64, i64* %i + %cmp1 = icmp eq i64 %count, 5 + br i1 %cmp1, label %false, label %check +check: + %ptr = getelementptr [5 x i64], [5 x i64]* %list, i32 0, i64 %count + %val = load i64, i64* %ptr + %cmp2 = icmp eq i64 %x, %val + %a = add i64 1, %count + store i64 %a, i64* %i + br i1 %cmp2, label %true, label %loop +true: + ret i64 1 +false: + ret i64 0 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %r = call i64 @search(i64 3, [5 x i64]* @glist) + ret i64 %r +} + diff --git a/hw3/llprograms/list1.ll b/hw3/llprograms/list1.ll new file mode 100644 index 0000000..0931924 --- /dev/null +++ b/hw3/llprograms/list1.ll @@ -0,0 +1,18 @@ +%node = type { i64, %node* } + +@hd = global %node { i64 1, %node* @md } +@md = global %node { i64 2, %node* @tl } +@tl = global %node { i64 3, %node* null } + +define i64 @main(i64 %argc, i8** %arcv) { + %head = getelementptr %node, %node* @hd, i32 0, i32 0 + %link = getelementptr %node, %node* @hd, i32 0, i32 1 + %next = load %node*, %node** %link + %val = getelementptr %node, %node* %next, i32 0, i32 0 + %link2 = getelementptr %node, %node* %next, i32 0, i32 1 + %next2 = load %node*, %node** %link2 + %val2 = getelementptr %node, %node* %next2, i32 0, i32 0 + %1 = load i64, i64* %val2 + ret i64 %1 +} + diff --git a/hw3/llprograms/lshr.ll b/hw3/llprograms/lshr.ll new file mode 100644 index 0000000..7a95ad0 --- /dev/null +++ b/hw3/llprograms/lshr.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = lshr i64 42, 2 + ret i64 %1 +} + diff --git a/hw3/llprograms/matmul.ll b/hw3/llprograms/matmul.ll new file mode 100644 index 0000000..e50f98a --- /dev/null +++ b/hw3/llprograms/matmul.ll @@ -0,0 +1,110 @@ +%vec = type [2 x i64] +%mat = type [2 x %vec] + +@mat1 = global %mat [ %vec [ i64 1, i64 2 ], %vec [ i64 3, i64 4 ] ] +@mat2 = global %mat [ %vec [ i64 5, i64 6 ], %vec [ i64 7, i64 8 ] ] +@mat3 = global %mat [ %vec [ i64 19, i64 22 ], %vec [ i64 43, i64 50 ] ] +@matr = global %mat [ %vec [ i64 0, i64 0 ], %vec [ i64 0, i64 0 ] ] + +define i64 @main(i64 %argc, i8** %argv) { + %cnt = alloca i64 + store i64 10000000, i64* %cnt + br label %loop + +loop: + %tmp = load i64, i64* %cnt + %b = icmp eq i64 %tmp, 0 + br i1 %b, label %exit, label %body + +body: + call void @matmul(%mat* @mat1, %mat* @mat2, %mat* @matr) + %ans = call i64 @mateq(%mat* @mat3, %mat* @matr) + %tmp2 = load i64, i64* %cnt + %tmp3 = sub i64 %tmp2, 1 + store i64 %tmp3, i64* %cnt + br label %loop + +exit: + ret i64 0 +} + +define void @matmul(%mat* %a, %mat* %b, %mat* %c) { + %i = alloca i64 + %j = alloca i64 + store i64 0, i64* %i + br label %starti +starti: + %iv = load i64, i64* %i + %ic = icmp slt i64 %iv, 2 + br i1 %ic, label %theni, label %endi +theni: + store i64 0, i64* %j + br label %startj +startj: + %jv = load i64, i64* %j + %jc = icmp slt i64 %jv, 2 + br i1 %jc, label %thenj, label %endj +thenj: + %r = getelementptr %mat, %mat* %c, i32 0, i64 %iv, i64 %jv + %a1 = getelementptr %mat, %mat* %a, i32 0, i64 %iv, i32 0 + %b1 = getelementptr %mat, %mat* %b, i32 0, i32 0, i64 %jv + %a2 = getelementptr %mat, %mat* %a, i32 0, i64 %iv, i32 1 + %b2 = getelementptr %mat, %mat* %b, i32 0, i32 1, i64 %jv + %a1v = load i64, i64* %a1 + %b1v = load i64, i64* %b1 + %a2v = load i64, i64* %a2 + %b2v = load i64, i64* %b2 + %ab1 = mul i64 %a1v, %b1v + %ab2 = mul i64 %a2v, %b2v + %ab = add i64 %ab1, %ab2 + store i64 %ab, i64* %r + %jinc = add i64 %jv, 1 + store i64 %jinc, i64* %j + br label %startj +endj: + %iinc = add i64 %iv, 1 + store i64 %iinc, i64* %i + br label %starti +endi: + ret void +} + +define i64 @mateq(%mat* %ma, %mat* %mb) { + %r = alloca i64 + store i64 0, i64* %r + %i = alloca i64 + %j = alloca i64 + store i64 0, i64* %i + br label %starti1 +starti1: + %iv = load i64, i64* %i + %ic = icmp slt i64 %iv, 2 + br i1 %ic, label %theni1, label %endi1 +theni1: + store i64 0, i64* %j + br label %startj1 +startj1: + %jv = load i64, i64* %j + %jc = icmp slt i64 %jv, 2 + br i1 %jc, label %thenj1, label %endj1 +thenj1: + %a = getelementptr %mat, %mat* %ma, i32 0, i64 %iv, i64 %jv + %b = getelementptr %mat, %mat* %mb, i32 0, i64 %iv, i64 %jv + %av = load i64, i64* %a + %bv = load i64, i64* %b + %cmp = xor i64 %av, %bv + %rv = load i64, i64* %r + %tmp = or i64 %cmp, %rv + store i64 %tmp, i64* %r + %jinc = add i64 %jv, 1 + store i64 %jinc, i64* %j + br label %startj1 +endj1: + %iinc = add i64 %iv, 1 + store i64 %iinc, i64* %i + br label %starti1 +endi1: + %rv1 = load i64, i64* %r + ret i64 %rv1 +} + diff --git a/hw3/llprograms/max_thomas_test.ll b/hw3/llprograms/max_thomas_test.ll new file mode 100644 index 0000000..3437726 --- /dev/null +++ b/hw3/llprograms/max_thomas_test.ll @@ -0,0 +1,22 @@ +define i64 @main(i64 %argc, i8** %argv) { + %a = alloca i64 + store i64 1, i64* %a + %b = alloca i64* + store i64* %a, i64** %b + %c = alloca i64** + store i64** %b, i64*** %c + %d = alloca i64*** + store i64*** %c, i64**** %d + %e = alloca i64**** + store i64**** %d, i64***** %e + %f = alloca i64***** + store i64***** %e, i64****** %f + %g = alloca i64****** + store i64****** %f, i64******* %g + %h = alloca i64******* + store i64******* %g, i64******** %h + %i = alloca i64******** + store i64******** %h, i64********* %i + ret i64 120 +} + diff --git a/hw3/llprograms/max_thomas_test_opt.ll b/hw3/llprograms/max_thomas_test_opt.ll new file mode 100644 index 0000000..1b5b7e8 --- /dev/null +++ b/hw3/llprograms/max_thomas_test_opt.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %argv) { + ret i64 120 +} + diff --git a/hw3/llprograms/mul.ll b/hw3/llprograms/mul.ll new file mode 100644 index 0000000..a3c6f49 --- /dev/null +++ b/hw3/llprograms/mul.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = mul i64 5, 9 + ret i64 %1 +} + diff --git a/hw3/llprograms/naive_factor_nonprime.ll b/hw3/llprograms/naive_factor_nonprime.ll new file mode 100644 index 0000000..a504f02 --- /dev/null +++ b/hw3/llprograms/naive_factor_nonprime.ll @@ -0,0 +1,44 @@ +define i64 @naive_mod(i64 %top, i64 %bottom) { + %product_sum = alloca i64 + store i64 0, i64* %product_sum + br label %start +start: + %1 = load i64, i64* %product_sum + %plus = add i64 %bottom, %1 + store i64 %plus, i64* %product_sum + %exceeded = icmp sgt i64 %plus, %top + br i1 %exceeded, label %final, label %start +final: + %2 = load i64, i64* %product_sum + %un_exceeded = sub i64 %2, %bottom + %out = sub i64 %top, %un_exceeded + ret i64 %out +} + +define i64 @naive_prime(i64 %n) { + %factor_attempt = alloca i64 + store i64 2, i64* %factor_attempt + br label %loop +loop: + %1 = load i64, i64* %factor_attempt + %sqr = mul i64 %1, %1 + %exceed_cap = icmp sgt i64 %sqr, %n + br i1 %exceed_cap, label %final_true, label %inc +inc: + %2 = load i64, i64* %factor_attempt + %plus = add i64 1, %1 + store i64 %plus, i64* %factor_attempt + %mod_result = call i64 @naive_mod(i64 %n, i64 %2) + %is_composite = icmp eq i64 0, %mod_result + br i1 %is_composite, label %final_false, label %loop +final_false: + ret i64 0 +final_true: + ret i64 1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %result = call i64 @naive_prime(i64 100) + ret i64 %result +} + diff --git a/hw3/llprograms/naive_factor_prime.ll b/hw3/llprograms/naive_factor_prime.ll new file mode 100644 index 0000000..395379e --- /dev/null +++ b/hw3/llprograms/naive_factor_prime.ll @@ -0,0 +1,44 @@ +define i64 @naive_mod(i64 %top, i64 %bottom) { + %product_sum = alloca i64 + store i64 0, i64* %product_sum + br label %start +start: + %1 = load i64, i64* %product_sum + %plus = add i64 %bottom, %1 + store i64 %plus, i64* %product_sum + %exceeded = icmp sgt i64 %plus, %top + br i1 %exceeded, label %final, label %start +final: + %2 = load i64, i64* %product_sum + %un_exceeded = sub i64 %2, %bottom + %out = sub i64 %top, %un_exceeded + ret i64 %out +} + +define i64 @naive_prime(i64 %n) { + %factor_attempt = alloca i64 + store i64 2, i64* %factor_attempt + br label %loop +loop: + %1 = load i64, i64* %factor_attempt + %sqr = mul i64 %1, %1 + %exceed_cap = icmp sgt i64 %sqr, %n + br i1 %exceed_cap, label %final_true, label %inc +inc: + %2 = load i64, i64* %factor_attempt + %plus = add i64 1, %1 + store i64 %plus, i64* %factor_attempt + %mod_result = call i64 @naive_mod(i64 %n, i64 %2) + %is_composite = icmp eq i64 0, %mod_result + br i1 %is_composite, label %final_false, label %loop +final_false: + ret i64 0 +final_true: + ret i64 1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %result = call i64 @naive_prime(i64 19) + ret i64 %result +} + diff --git a/hw3/llprograms/opt_cbr_test1.ll b/hw3/llprograms/opt_cbr_test1.ll new file mode 100644 index 0000000..ceb5fb7 --- /dev/null +++ b/hw3/llprograms/opt_cbr_test1.ll @@ -0,0 +1,19 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 0, 64 + %2 = alloca i64 + store i64 %1, i64* %2 + %3 = load i64, i64* %2 + %4 = mul i64 4, 12 + %5 = icmp sgt i64 %4, 52 + br i1 %5, label %then, label %else +then: + store i64 8, i64* %2 + br label %merge +else: + store i64 0, i64* %2 + br label %merge +merge: + %6 = load i64, i64* %2 + ret i64 %6 +} + diff --git a/hw3/llprograms/opt_globals_test1.ll b/hw3/llprograms/opt_globals_test1.ll new file mode 100644 index 0000000..36d30a3 --- /dev/null +++ b/hw3/llprograms/opt_globals_test1.ll @@ -0,0 +1,12 @@ +@x = global i64 1 +@y = global i64 2 + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = load i64, i64* @x + %2 = mul i64 %1, 7 + %3 = load i64, i64* @y + %4 = add i64 %3, 1 + store i64 %4, i64* @y + ret i64 %1 +} + diff --git a/hw3/llprograms/opt_globals_test1_soln.ll b/hw3/llprograms/opt_globals_test1_soln.ll new file mode 100644 index 0000000..615b2a8 --- /dev/null +++ b/hw3/llprograms/opt_globals_test1_soln.ll @@ -0,0 +1,8 @@ +@x = global i64 1 +@y = global i64 2 + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = load i64, i64* @x + ret i64 %1 +} + diff --git a/hw3/llprograms/or.ll b/hw3/llprograms/or.ll new file mode 100644 index 0000000..5b11be5 --- /dev/null +++ b/hw3/llprograms/or.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = or i64 1, 0 + ret i64 %1 +} + diff --git a/hw3/llprograms/puts.ll b/hw3/llprograms/puts.ll new file mode 100644 index 0000000..1fd8b58 --- /dev/null +++ b/hw3/llprograms/puts.ll @@ -0,0 +1,17 @@ +declare void @ll_puts(i8*) +declare i8* @ll_strcat(i8*, i8*) + +define i64 @main(i64 %argc, i8** %argv) { + %p1 = getelementptr i8*, i8** %argv, i32 1 + %a1 = load i8*, i8** %p1 + %p2 = getelementptr i8*, i8** %argv, i32 2 + %a2 = load i8*, i8** %p2 + %r = call i8* @strcat(i8* %a1, i8* %a2) + ret i64 0 +} + +define i8* @strcat(i8* %s1, i8* %s2) { + %p = call i8* @ll_strcat(i8* %s1, i8* %s2) + call void @ll_puts(i8* %p) + ret i8* %p +} diff --git a/hw3/llprograms/qtree.ll b/hw3/llprograms/qtree.ll new file mode 100644 index 0000000..81fdc74 --- /dev/null +++ b/hw3/llprograms/qtree.ll @@ -0,0 +1,13 @@ +%vec = type [2 x i64] +%centroid = type { i64, %vec } +%qtree = type { %centroid, [4 x %qtree*] } +%qtrees = type [1 x %qtree] + +@gbl = global %qtrees [ %qtree { %centroid { i64 1, %vec [ i64 2, i64 3 ] }, [4 x %qtree*] [ %qtree* null, %qtree* null, %qtree* null, %qtree* null ] } ] + +define i64 @main(i64 %argc, i8** %argv) { + %1 = getelementptr %qtrees, %qtrees* @gbl, i32 0, i32 0, i32 0, i32 1, i32 1 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/reed_nate_opt.ll b/hw3/llprograms/reed_nate_opt.ll new file mode 100644 index 0000000..cd467c5 --- /dev/null +++ b/hw3/llprograms/reed_nate_opt.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %arcv) { + br i1 0, label %l1, label %l2 +l1: + br i1 1, label %l2, label %l3 +l2: + ret i64 2500 +l3: + ret i64 0 +} + diff --git a/hw3/llprograms/regtest1.ll b/hw3/llprograms/regtest1.ll new file mode 100644 index 0000000..4d776b3 --- /dev/null +++ b/hw3/llprograms/regtest1.ll @@ -0,0 +1,10 @@ +define i64 @foo(i64 %x, i64 %y) { + %z = add i64 %x, %y + ret i64 %z +} + +define i64 @main(i64 %argc, i8** %arcv) { + %v = add i64 341, 42 + %ans = call i64 @foo(i64 %v, i64 %v) + ret i64 %ans +} diff --git a/hw3/llprograms/return.ll b/hw3/llprograms/return.ll new file mode 100644 index 0000000..f3bab9d --- /dev/null +++ b/hw3/llprograms/return.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + ret i64 0 +} + diff --git a/hw3/llprograms/return42.ll b/hw3/llprograms/return42.ll new file mode 100644 index 0000000..0ddd39b --- /dev/null +++ b/hw3/llprograms/return42.ll @@ -0,0 +1,6 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 0, i64* %1 + ret i64 42 +} + diff --git a/hw3/llprograms/return_intermediate.ll b/hw3/llprograms/return_intermediate.ll new file mode 100644 index 0000000..72202fc --- /dev/null +++ b/hw3/llprograms/return_intermediate.ll @@ -0,0 +1,7 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = mul i64 3, 6 + %3 = sub i64 %2, %1 + ret i64 %2 +} + diff --git a/hw3/llprograms/return_intermediate_dce.ll b/hw3/llprograms/return_intermediate_dce.ll new file mode 100644 index 0000000..85fa6d2 --- /dev/null +++ b/hw3/llprograms/return_intermediate_dce.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + ret i64 18 +} + diff --git a/hw3/llprograms/return_intermediate_fold.ll b/hw3/llprograms/return_intermediate_fold.ll new file mode 100644 index 0000000..5f68f1f --- /dev/null +++ b/hw3/llprograms/return_intermediate_fold.ll @@ -0,0 +1,6 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = mul i64 3, 6 + ret i64 18 +} + diff --git a/hw3/llprograms/returnvoid.ll b/hw3/llprograms/returnvoid.ll new file mode 100644 index 0000000..9f1681e --- /dev/null +++ b/hw3/llprograms/returnvoid.ll @@ -0,0 +1,4 @@ +define void @main(i64 %argc, i8** %arcv) { + ret void +} + diff --git a/hw3/llprograms/rsa.ll b/hw3/llprograms/rsa.ll new file mode 100644 index 0000000..6a231a7 --- /dev/null +++ b/hw3/llprograms/rsa.ll @@ -0,0 +1,55 @@ +define i64 @rsa_decrypt(i64 %c) { + %p = add i64 56807, 0 + %q = add i64 51683, 0 + %n = mul i64 %p, %q + %d = add i64 1409083253, 0 + %e = add i64 65537, 0 + %_b__3 = alloca i64 + store i64 %c, i64* %_b__3 + %_e__1 = alloca i64 + store i64 %d, i64* %_e__1 + %_res__5 = alloca i64 + store i64 1, i64* %_res__5 + %_i__7 = alloca i64 + store i64 0, i64* %_i__7 + br label %_cond__14 +_cond__14: + %_val___9 = load i64, i64* %_i__7 + %_val___10 = load i64, i64* %_e__1 + %_bop___11 = icmp slt i64 %_val___9, %_val___10 + br i1 %_bop___11, label %_body__13, label %_post__12 +_body__13: + %_val___15 = load i64, i64* %_res__5 + %_val___16 = load i64, i64* %_b__3 + %_bop___17 = mul i64 %_val___15, %_val___16 + store i64 %_bop___17, i64* %_res__5 + %_val___19 = load i64, i64* %_i__7 + %_bop___20 = add i64 %_val___19, 1 + store i64 %_bop___20, i64* %_i__7 + br label %_cond__14 +_post__12: + %_pow_res = load i64, i64* %_res__5 + %_x__25 = alloca i64 + store i64 %_pow_res, i64* %_x__25 + %_y__23 = alloca i64 + store i64 %n, i64* %_y__23 + %_val___27 = load i64, i64* %_x__25 + %_res__28 = alloca i64 + store i64 %_val___27, i64* %_res__28 + br label %_cond__35 +_cond__35: + %_val___30 = load i64, i64* %_res__28 + %_val___31 = load i64, i64* %_y__23 + %_bop___32 = icmp sge i64 %_val___30, %_val___31 + br i1 %_bop___32, label %_body__34, label %_post__33 +_body__34: + %_val___36 = load i64, i64* %_res__28 + %_val___37 = load i64, i64* %_y__23 + %_bop___38 = sub i64 %_val___36, %_val___37 + store i64 %_bop___38, i64* %_res__28 + br label %_cond__35 +_post__33: + %m = load i64, i64* %_res__28 + ret i64 %m +} + diff --git a/hw3/llprograms/rsaopt.ll b/hw3/llprograms/rsaopt.ll new file mode 100644 index 0000000..f0be90b --- /dev/null +++ b/hw3/llprograms/rsaopt.ll @@ -0,0 +1,50 @@ +define i64 @rsa_decrypt(i64 %c) { + %_b__3 = alloca i64 + store i64 %c, i64* %_b__3 + %_e__1 = alloca i64 + store i64 1409083253, i64* %_e__1 + %_res__5 = alloca i64 + store i64 1, i64* %_res__5 + %_i__7 = alloca i64 + store i64 0, i64* %_i__7 + br label %_cond__14 +_body__13: + %_val___15 = load i64, i64* %_res__5 + %_val___16 = load i64, i64* %_b__3 + %_bop___17 = mul i64 %_val___15, %_val___16 + store i64 %_bop___17, i64* %_res__5 + %_val___19 = load i64, i64* %_i__7 + %_bop___20 = add i64 %_val___19, 1 + store i64 %_bop___20, i64* %_i__7 + br label %_cond__14 +_body__34: + %_val___36 = load i64, i64* %_res__28 + %_val___37 = load i64, i64* %_y__23 + %_bop___38 = sub i64 %_val___36, %_val___37 + store i64 %_bop___38, i64* %_res__28 + br label %_cond__35 +_cond__14: + %_val___9 = load i64, i64* %_i__7 + %_val___10 = load i64, i64* %_e__1 + %_bop___11 = icmp slt i64 %_val___9, %_val___10 + br i1 %_bop___11, label %_body__13, label %_post__12 +_cond__35: + %_val___30 = load i64, i64* %_res__28 + %_val___31 = load i64, i64* %_y__23 + %_bop___32 = icmp sge i64 %_val___30, %_val___31 + br i1 %_bop___32, label %_body__34, label %_post__33 +_post__12: + %_pow_res = load i64, i64* %_res__5 + %_x__25 = alloca i64 + store i64 %_pow_res, i64* %_x__25 + %_y__23 = alloca i64 + store i64 2935956181, i64* %_y__23 + %_val___27 = load i64, i64* %_x__25 + %_res__28 = alloca i64 + store i64 %_val___27, i64* %_res__28 + br label %_cond__35 +_post__33: + %m = load i64, i64* %_res__28 + ret i64 %m +} + diff --git a/hw3/llprograms/shl.ll b/hw3/llprograms/shl.ll new file mode 100644 index 0000000..f2a42ef --- /dev/null +++ b/hw3/llprograms/shl.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = shl i64 42, 2 + ret i64 %1 +} + diff --git a/hw3/llprograms/sieve.ll b/hw3/llprograms/sieve.ll new file mode 100644 index 0000000..37ec0d3 --- /dev/null +++ b/hw3/llprograms/sieve.ll @@ -0,0 +1,71 @@ +declare i64* @ll_malloc(i64, i64) + +define i64 @main(i64 %argc, i8** %argv) { + %1 = call i64 @is_prime(i64 347) + ret i64 %1 +} + +define i64 @is_prime(i64 %n) { + %sieve = call i64* @ll_malloc(i64 8, i64 10000) + %1 = getelementptr i64, i64* %sieve, i32 0 + store i64 0, i64* %1 + %2 = getelementptr i64, i64* %sieve, i32 1 + store i64 0, i64* %2 + br label %start1 +start1: + %i = alloca i64 + store i64 2, i64* %i + br label %cmp1 +cmp1: + %3 = load i64, i64* %i + %4 = icmp slt i64 %3, 10000 + br i1 %4, label %loop1, label %end1 +loop1: + %5 = load i64, i64* %i + %6 = getelementptr i64, i64* %sieve, i64 %5 + store i64 1, i64* %6 + %7 = add i64 %5, 1 + store i64 %7, i64* %i + br label %cmp1 +end1: + br label %start2 +start2: + store i64 2, i64* %i + br label %cmp2 +cmp2: + %8 = load i64, i64* %i + %9 = icmp slt i64 %8, 10000 + br i1 %9, label %loop2, label %end2 +loop2: + %10 = load i64, i64* %i + %11 = getelementptr i64, i64* %sieve, i64 %10 + %12 = load i64, i64* %11 + %13 = icmp eq i64 %12, 1 + br i1 %13, label %then1, label %else1 +then1: + %j = alloca i64 + %14 = add i64 %10, %10 + store i64 %14, i64* %j + br label %cmp3 +cmp3: + %15 = load i64, i64* %j + %16 = icmp slt i64 %15, 10000 + br i1 %16, label %loop3, label %end3 +loop3: + %17 = getelementptr i64, i64* %sieve, i64 %15 + store i64 0, i64* %17 + %18 = add i64 %15, %10 + store i64 %18, i64* %j + br label %cmp3 +end3: + br label %else1 +else1: + %19 = load i64, i64* %i + %20 = add i64 %19, 1 + store i64 %20, i64* %i + br label %cmp2 +end2: + %ptr = getelementptr i64, i64* %sieve, i64 %n + %r = load i64, i64* %ptr + ret i64 %r +} diff --git a/hw3/llprograms/string1.ll b/hw3/llprograms/string1.ll new file mode 100644 index 0000000..4027d21 --- /dev/null +++ b/hw3/llprograms/string1.ll @@ -0,0 +1,12 @@ +declare void @ll_puts(i8*) +declare i8* @ll_strcat(i8*, i8*) + +@gstr = global [14 x i8] c"hello, world!\00" + +define i64 @main(i64 %argc, i8** %argv) { + %1 = getelementptr [14 x i8], [14 x i8]* @gstr, i32 0, i32 0 + %2 = call i8* @ll_strcat (i8* %1, i8* %1) + call void @ll_puts (i8* %2) + ret i64 0 +} + diff --git a/hw3/llprograms/sub.ll b/hw3/llprograms/sub.ll new file mode 100644 index 0000000..c90e1a8 --- /dev/null +++ b/hw3/llprograms/sub.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = sub i64 10, 9 + ret i64 %1 +} + diff --git a/hw3/llprograms/sub_neg.ll b/hw3/llprograms/sub_neg.ll new file mode 100644 index 0000000..ec1c5a5 --- /dev/null +++ b/hw3/llprograms/sub_neg.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = sub i64 9, 10 + ret i64 %1 +} + diff --git a/hw3/llprograms/sub_neg_dce.ll b/hw3/llprograms/sub_neg_dce.ll new file mode 100644 index 0000000..f29182f --- /dev/null +++ b/hw3/llprograms/sub_neg_dce.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + ret i64 -1 +} + diff --git a/hw3/llprograms/sub_neg_fold.ll b/hw3/llprograms/sub_neg_fold.ll new file mode 100644 index 0000000..c2978f9 --- /dev/null +++ b/hw3/llprograms/sub_neg_fold.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = sub i64 9, 10 + ret i64 -1 +} + diff --git a/hw3/llprograms/sum_tree.ll b/hw3/llprograms/sum_tree.ll new file mode 100644 index 0000000..71cb882 --- /dev/null +++ b/hw3/llprograms/sum_tree.ll @@ -0,0 +1,31 @@ +%struct.Node = type { %struct.Node*, %struct.Node*, i64 } + +@test1 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 100 } +@test2 = global %struct.Node { %struct.Node* @test1, %struct.Node* null, i64 10 } +@test3 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 1 } +@test = global %struct.Node { %struct.Node* @test2, %struct.Node* @test3, i64 5 } + +define i64 @sum_tree(%struct.Node* %t) { + %1 = icmp eq %struct.Node* %t, null + br i1 %1, label %then, label %else +then: + ret i64 0 +else: + %2 = getelementptr %struct.Node, %struct.Node* %t, i32 0, i32 2 + %3 = load i64, i64* %2 + %4 = getelementptr %struct.Node, %struct.Node* %t, i32 0, i32 1 + %5 = load %struct.Node*, %struct.Node** %4 + %6 = call i64 @sum_tree(%struct.Node* %5) + %7 = add i64 %3, %6 + %8 = getelementptr %struct.Node, %struct.Node* %t, i32 0, i32 0 + %9 = load %struct.Node*, %struct.Node** %8 + %10 = call i64 @sum_tree(%struct.Node* %9) + %11 = add i64 %7, %10 + ret i64 %11 +} + +define i64 @main(i64 %argc, i8** %argv) { + %1 = call i64 @sum_tree(%struct.Node* @test) + ret i64 %1 +} + diff --git a/hw3/llprograms/vivekraj_jjlee.ll b/hw3/llprograms/vivekraj_jjlee.ll new file mode 100644 index 0000000..b31a6f5 --- /dev/null +++ b/hw3/llprograms/vivekraj_jjlee.ll @@ -0,0 +1,12 @@ +define i64 @program(i64 %argc, i8** %argv) { + %a = xor i64 1, 2 + %b = mul i64 -3, 31 + %c = add i64 %b, 99 + %d = icmp slt i64 %c, 0 + br i1 %d, label %then, label %else +then: + ret i64 0 +else: + ret i64 1 +} + diff --git a/hw3/llprograms/vivekraj_jjlee_opt.ll b/hw3/llprograms/vivekraj_jjlee_opt.ll new file mode 100644 index 0000000..c30b0d3 --- /dev/null +++ b/hw3/llprograms/vivekraj_jjlee_opt.ll @@ -0,0 +1,8 @@ +define i64 @program(i64 %argc, i8** %argv) { + br i1 0, label %then, label %else +then: + ret i64 0 +else: + ret i64 1 +} + diff --git a/hw3/llprograms/xor.ll b/hw3/llprograms/xor.ll new file mode 100644 index 0000000..ed62864 --- /dev/null +++ b/hw3/llprograms/xor.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = xor i64 0, 0 + ret i64 %1 +} + diff --git a/hw3/main.ml b/hw3/main.ml new file mode 100644 index 0000000..72eefe9 --- /dev/null +++ b/hw3/main.ml @@ -0,0 +1,49 @@ +open Ll +open Arg +open Assert +open Driver + +(* testing harness ---------------------------------------------------------- *) +exception Ran_tests +let suite = ref (Studenttests.provided_tests @ Gradedtests.graded_tests) + +let execute_tests () = + let outcome = run_suite !suite in + Printf.printf "%s\n" (outcome_to_string outcome); + raise Ran_tests + + +(* command-line arguments --------------------------------------------------- *) +let args = + [ ("--test", Unit execute_tests, "run the test suite, ignoring other files inputs") + ; ("-op", Set_string Platform.output_path, "set the path to the output files directory [default='output']") + ; ("-o", Set_string executable_filename, "set the name of the resulting executable [default='a.out']") + ; ("-S", Clear assemble, "stop after generating .s files; do generate .o files") + ; ("-c", Clear link, "stop after generating .o files; do not generate executables") + ; ("--interpret-ll", Set interpret_ll, "runs each LL program through the LL interpreter") + ; ("--print-ll", Set print_ll_flag, "prints the program LL code") + ; ("--print-x86", Set print_x86_flag, "prints the program's assembly code") + ; ("--clang", Set clang, "compiles to assembly using clang, not the compilerdesign backend") + ; ("--execute-x86", Set execute_x86, "run the resulting executable file") + ; ("-v", Unit Platform.enable_verbose, "enables more verbose compilation output") + ] + + +(* Files found on the command line *) +let files = ref [] + +let main () = + Platform.configure_os (); + Platform.create_output_dir (); + try + Arg.parse args (fun filename -> files := filename :: !files) + "Compiler Design main test harness\n\ + USAGE: ./main.native [options] \n\ + see README for details about using the compiler"; + + process_files !files + + with Ran_tests -> + () + +;; main () diff --git a/hw3/studenttests.ml b/hw3/studenttests.ml new file mode 100644 index 0000000..f878420 --- /dev/null +++ b/hw3/studenttests.ml @@ -0,0 +1,10 @@ +open Assert + +(* These tests are provided by you -- they will not be graded *) + +(* You should also add additional test cases here to help you *) +(* debug your program. *) + +let provided_tests : suite = [ + +] diff --git a/hw3/util/assert.ml b/hw3/util/assert.ml new file mode 100644 index 0000000..a99d32e --- /dev/null +++ b/hw3/util/assert.ml @@ -0,0 +1,194 @@ +(* Assertion Testing and Grading Infrastructure *) +(* Author: Steve Zdancewic *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = unit -> unit + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = assertion test list + +(**************) +(* Assertions *) + +let assert_eq v1 v2 : assertion = + fun () -> if v1 <> v2 then failwith "not equal" else () + + +let assert_eqf f v2 : assertion = + fun () -> if f () <> v2 then failwith "not equal" else () + + +let assert_eqfs f v2 : assertion = + fun () -> + let s1 = f () in + if s1 <> v2 + then failwith @@ Printf.sprintf "not equal\n\texpected:%s\n\tgot:%s\n" v2 s1 + else () + + +let assert_fail : assertion = fun () -> failwith "assert fail" + +exception Timeout + +let timeout_assert (time : int) (a : assertion) : assertion = + fun () -> + let handler = Sys.Signal_handle (fun _ -> raise Timeout) in + let old = Sys.signal Sys.sigalrm handler in + let reset_sigalrm () = Sys.set_signal Sys.sigalrm old in + ignore (Unix.alarm time) ; + try + a () ; + reset_sigalrm () + with + | Timeout -> + reset_sigalrm () ; + failwith @@ Printf.sprintf "Timed out after %d seconds" time + | exc -> + reset_sigalrm () ; + raise exc + + +let timeout_test (time : int) (t : assertion test) : assertion test = + let map_timeout l = List.map (fun (i, a) -> (i, timeout_assert time a)) l in + match t with + | GradedTest (s, i, ls) -> + GradedTest (s, i, map_timeout ls) + | Test (s, ls) -> + Test (s, map_timeout ls) + + +let timeout_suite (time : int) (s : suite) : suite = + List.map (timeout_test time) s + + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = result test list + +let run_assertion (f : assertion) : result = + try + f () ; + Pass + with + | Failure m -> + Fail m + | e -> + Fail ("test threw exception: " ^ Printexc.to_string e) + + +let run_test (t : assertion test) : result test = + let run_case (cn, f) = (cn, run_assertion f) in + match t with + | GradedTest (n, s, cases) -> + Printf.eprintf "Running test %s\n%!" n ; + GradedTest (n, s, List.map run_case cases) + | Test (n, cases) -> + Printf.eprintf "Running test %s\n%!" n ; + Test (n, List.map run_case cases) + + +let run_suite (s : suite) : outcome = List.map run_test s + +(***********************) +(* Reporting functions *) + +let result_test_to_string (name_pts : string) (r : result test) : string = + let string_of_case (name, res) = + match res with + | Pass -> + "passed - " ^ name + | Fail msg -> + "FAILED - " ^ name ^ ": " ^ msg + in + match r with + | GradedTest (_, _, cases) | Test (_, cases) -> + name_pts + ^ List.fold_left + (fun rest case -> rest ^ "\n" ^ string_of_case case) + "" + cases + + +(* returns (name_pts, passed, failed, total, points_earned, max_given, max_hidden) *) +let get_results (t : result test) = + let num_passed cases = + List.fold_left + (fun cnt (_, r) -> match r with Pass -> cnt + 1 | _ -> cnt) + 0 + cases + in + let num_failed cases = + List.fold_left + (fun cnt (_, r) -> match r with Fail _ -> cnt + 1 | _ -> cnt) + 0 + cases + in + match t with + | GradedTest (name, pts, cases) -> + let passed = num_passed cases in + let failed = num_failed cases in + let total = List.length cases in + if total > 0 + then + let points_earned = + float_of_int passed /. float_of_int total *. float_of_int pts + in + let name_pts = + Printf.sprintf "%s (%1.f/%d points)" name points_earned pts + in + (name_pts, passed, failed, total, points_earned, pts, 0) + else + let name_pts = Printf.sprintf "%s (?/%d points)" name pts in + (name_pts, passed, failed, total, 0.0, 0, pts) + | Test (name, cases) -> + let total = List.length cases in + let passed = num_passed cases in + let failed = num_failed cases in + (name, passed, failed, total, 0.0, 0, 0) + + +let outcome_to_string (o : outcome) : string = + let sep = "\n---------------------------------------------------\n" in + let helper (passed, failed, total, pts, maxg, maxh, str) (t : result test) = + let name_pts, p, f, tot, s, mg, mh = get_results t in + ( passed + p + , failed + f + , total + tot + , s +. pts + , maxg + mg + , maxh + mh + , str + ^ "\n" + ^ + if f > 0 + then result_test_to_string name_pts t + else if tot > 0 + then name_pts ^ ":\n OK" + else name_pts ^ ":\n Hidden" ) + in + let p, f, tot, pts, maxg, maxh, str = + List.fold_left helper (0, 0, 0, 0.0, 0, 0, "") o + in + str + ^ sep + ^ Printf.sprintf + "Passed: %d/%d\n\ + Failed: %d/%d\n\ + Score: %1.f/%d (given)\n\ + \ ?/%d (hidden)" + p tot + f tot + pts maxg + maxh diff --git a/hw3/util/assert.mli b/hw3/util/assert.mli new file mode 100644 index 0000000..0159cf7 --- /dev/null +++ b/hw3/util/assert.mli @@ -0,0 +1,57 @@ +(* Assertion Testing and Grading Infrastructure *) +(* Author: Steve Zdancewic *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +exception Timeout + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = unit -> unit + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = assertion test list + +(**************) +(* Assertions *) + +val assert_eq : 'a -> 'a -> assertion + +val assert_eqf : (unit -> 'a) -> 'a -> assertion + +val assert_eqfs : (unit -> string) -> string -> assertion + +val assert_fail : assertion + +val timeout_assert : int -> assertion -> assertion + +val timeout_test : int -> assertion test -> assertion test + +val timeout_suite : int -> suite -> suite + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = result test list + +val run_assertion : assertion -> result + +val run_test : assertion test -> result test + +val run_suite : suite -> outcome + +(***********************) +(* Reporting functions *) + +val result_test_to_string : string -> result test -> string + +(* val get_results result test -> (string * int * int * int * float * int * int) *) +val outcome_to_string : outcome -> string diff --git a/hw3/util/platform.ml b/hw3/util/platform.ml new file mode 100644 index 0000000..4027171 --- /dev/null +++ b/hw3/util/platform.ml @@ -0,0 +1,210 @@ +(* -------------------------------------------------------------------------- *) +(** Assembling and linking for X86. Depends on the underlying OS platform *) + +open Printf +open Unix + +exception PlatformError of string * string + +(* paths -------------------------------------------------------------------- *) +let path_sep = "/" + +let dot_path = "./" + +let output_path = ref "output" + +let libs = ref [] + +let lib_paths = ref [] + +let lib_search_paths = ref [] + +let include_paths = ref [] + +let executable_name = ref "a.out" + +(* unix utility scripts ----------------------------------------------------- *) +let pp_cmd = ref "cpp -E " + +let rm_cmd = ref "rm -rf " + +(* -------------------------------------------------------------------------- *) +(* Platform specific configuration: Unix/Linux vs. Mac OS X *) + +let os = + let ic = Unix.open_process_in "uname -s" in + let uname = input_line ic in + let () = close_in ic in + uname + + +(* One of "Darwin" or "Linux" *) + +let linux = ref false + +let mangle name = if !linux then name else "_" ^ name + +let osx_target_triple = "x86_64-apple-macosx10.13.0" + +let linux_target_triple = "x86_64-unknown-linux" + +let target_triple = ref osx_target_triple + +let platform_flags = ref "" + +(* Set the link commands properly, ensure output directory exists *) +let configure_os () = + if os = "Linux" + then ( + linux := true ; + target_triple := linux_target_triple ; + platform_flags := "" ) + else if os = "Darwin" + then ( + linux := false ; + target_triple := osx_target_triple ; + platform_flags := "-fno-asynchronous-unwind-tables -mstackrealign" ) + else failwith @@ "Unsupported OS detected: " ^ os + + +(* verbose compiler output -------------------------------------------------- *) +let verbose = ref false + +let verb msg = + if !verbose + then ( + print_string msg ; + flush Pervasives.stdout ) + + +let verb_os () = + verb + @@ Printf.sprintf + "* PLATFORM: %s TRIPLE: %s FLAGS %s\n" + os + !target_triple + !platform_flags + + +let enable_verbose () = + verbose := true ; + verb_os () + + +(* create the output directory, which is assumed to exist *) +let create_output_dir () = + try ignore (stat !output_path) with + | Unix_error (ENOENT, _, _) -> + verb @@ Printf.sprintf "creating output directory: %s\n" !output_path ; + mkdir !output_path 0o755 + + +(* clang invocation stuff --------------------------------------------------- *) +let common_flags = "-Wno-override-module -Wno-unused-command-line-argument -mstack-alignment=8" + +let clang_ll_mode = "-S" + +let as_mode = "-c" + +let opt_level = ref "-O1 -Wall" + +let clang args = Printf.sprintf "clang %s -o " (String.concat " " args) + +let clang_cmd () = + clang [ clang_ll_mode; !opt_level; common_flags; !platform_flags ] + + +let as_cmd () = clang [ as_mode; !opt_level; common_flags; !platform_flags ] + +let link_cmd () = clang [ common_flags; !opt_level; !platform_flags ] + +(* filename munging --------------------------------------------------------- *) +let path_to_basename_ext (path : string) : string * string = + (* The path is of the form ... "foo/bar/baz/.ext" *) + let paths = Str.split (Str.regexp_string path_sep) path in + let _ = + if List.length paths = 0 then failwith @@ sprintf "bad path: %s" path + in + let filename = List.hd (List.rev paths) in + match Str.split (Str.regexp_string ".") filename with + | [ root ] -> + (root, "") + | [ root; ext ] -> + (root, ext) + | _ -> + failwith @@ sprintf "bad filename: %s" filename + + +(* compilation and shell commands-------------------------------------------- *) + +(* Platform independent shell command *) +let sh (cmd : string) (ret : string -> int -> 'a) : 'a = + verb (sprintf "* %s\n" cmd) ; + match system cmd with + | WEXITED i -> + ret cmd i + | WSIGNALED i -> + raise (PlatformError (cmd, sprintf "Signaled with %d." i)) + | WSTOPPED i -> + raise (PlatformError (cmd, sprintf "Stopped with %d." i)) + + +(* Generate a file name that does not already exist. + basedir includes the path separator +*) +let gen_name (basedir : string) (basen : string) (baseext : string) : string = + let rec nocollide ofs = + let nfn = + sprintf + "%s/%s%s%s" + basedir + basen + (if ofs = 0 then "" else "_" ^ string_of_int ofs) + baseext + in + try + ignore (stat nfn) ; + nocollide (ofs + 1) + with + | Unix_error (ENOENT, _, _) -> + nfn + in + nocollide 0 + + +let raise_error cmd i = + if i <> 0 then raise (PlatformError (cmd, sprintf "Exited with status %d." i)) + + +let ignore_error _ _ = () + +let preprocess (dot_oat : string) (dot_i : string) : unit = + sh + (sprintf + "%s%s %s %s" + !pp_cmd + (List.fold_left (fun s i -> s ^ " -I" ^ i) "" !include_paths) + dot_oat + dot_i) + raise_error + + +let clang_compile (dot_ll : string) (dot_s : string) : unit = + sh (sprintf "%s%s %s" (clang_cmd ()) dot_s dot_ll) raise_error + + +let assemble (dot_s : string) (dot_o : string) : unit = + sh (sprintf "%s%s %s" (as_cmd ()) dot_o dot_s) raise_error + + +let link (mods : string list) (out_fn : string) : unit = + sh + (sprintf + "%s%s %s %s %s %s" + (link_cmd ()) + out_fn + (String.concat " " (mods @ !lib_paths)) + (List.fold_left (fun s i -> s ^ " -L" ^ i) "" !lib_search_paths) + (List.fold_left (fun s i -> s ^ " -I" ^ i) "" !include_paths) + (List.fold_left (fun s l -> s ^ " -l" ^ l) "" !libs)) + raise_error diff --git a/hw3/x86/testX86.ml b/hw3/x86/testX86.ml new file mode 100644 index 0000000..1b23983 --- /dev/null +++ b/hw3/x86/testX86.ml @@ -0,0 +1,34 @@ +open X86 +open Cunit + +let hello_label = mk_lbl_named "hellostr" +let puts_label = mk_lbl_named "_puts" (* gcc on linux/mac uses _ to munge names *) + +let main_seq = [ + Push (esp); + Mov (ebp, esp); + + Add (esp, Imm (-8l)); (* Not sure why this has to be 8 *) + Mov (stack_offset 0l, Lbl hello_label); + Call (Lbl puts_label); + + Mov (esp, ebp); + Pop (ebp); + Ret +] + +let main_bb = { + (mk_insn_block (mk_lbl_named "_main") main_seq) with + global = true +} + +let hello_data = { + link = false; + label = (mk_lbl_named "hellostr"); + value = GStringz "Hello, world!" +} + +let cu = [Data hello_data; Code main_bb] + +let _ = + print_endline (string_of_cunit cu) diff --git a/hw3/x86/x86.ml b/hw3/x86/x86.ml new file mode 100644 index 0000000..802ee18 --- /dev/null +++ b/hw3/x86/x86.ml @@ -0,0 +1,165 @@ +(* X86lite language representation. *) + +(* assembler syntax --------------------------------------------------------- *) + +(* Labels for code blocks and global data. *) +type lbl = string + +type quad = int64 + +(* Immediate operands *) +type imm = Lit of quad + | Lbl of lbl + +(* Registers: + instruction pointer: rip + arguments: rdi, rsi, rdx, rcx, r09, r08 + callee-save: rbx, rbp, r12-r15 +*) +type reg = Rip + | Rax | Rbx | Rcx | Rdx | Rsi | Rdi | Rbp | Rsp + | R08 | R09 | R10 | R11 | R12 | R13 | R14 | R15 + +type operand = Imm of imm (* immediate *) + | Reg of reg (* register *) + | Ind1 of imm (* indirect: displacement *) + | Ind2 of reg (* indirect: (%reg) *) + | Ind3 of (imm * reg) (* indirect: displacement(%reg) *) + +(* Condition Codes *) +type cnd = Eq | Neq | Gt | Ge | Lt | Le + +type opcode = Movq | Pushq | Popq + | Leaq + | Incq | Decq | Negq | Notq + | Addq | Subq | Imulq | Xorq | Orq | Andq + | Shlq | Sarq | Shrq + | Jmp | J of cnd + | Cmpq | Set of cnd + | Callq | Retq + +(* An instruction is an opcode plus its operands. + Note that arity and other constraints about the operands + are not checked. *) +type ins = opcode * operand list + +type data = Asciz of string + | Quad of imm + +type asm = Text of ins list (* code *) + | Data of data list (* data *) + +(* labeled blocks of data or code *) +type elem = { lbl: lbl; global: bool; asm: asm } + +type prog = elem list + +(* Provide some syntactic sugar for writing x86 code in OCaml files. *) +module Asm = struct + let (~$) i = Imm (Lit (Int64.of_int i)) (* int64 constants *) + let (~$$) l = Imm (Lbl l) (* label constants *) + let (~%) r = Reg r (* registers *) + + (* helper functions for building blocks of data or code *) + let data l ds = { lbl = l; global = true; asm = Data ds } + let text l is = { lbl = l; global = false; asm = Text is } + let gtext l is = { lbl = l; global = true; asm = Text is } +end + +(* pretty printing ----------------------------------------------------------- *) + +let string_of_reg : reg -> string = function + | Rip -> "%rip" + | Rax -> "%rax" | Rbx -> "%rbx" | Rcx -> "%rcx" | Rdx -> "%rdx" + | Rsi -> "%rsi" | Rdi -> "%rdi" | Rbp -> "%rbp" | Rsp -> "%rsp" + | R08 -> "%r8 " | R09 -> "%r9 " | R10 -> "%r10" | R11 -> "%r11" + | R12 -> "%r12" | R13 -> "%r13" | R14 -> "%r14" | R15 -> "%r15" + +let string_of_byte_reg : reg -> string = function + | Rip -> failwith "%rip used as byte register" + | Rax -> "%al" | Rbx -> "%bl" | Rcx -> "%cl" | Rdx -> "%dl" + | Rsi -> "%sil" | Rdi -> "%dil" | Rbp -> "%bpl" | Rsp -> "%spl" + | R08 -> "%r8b" | R09 -> "%r9b" | R10 -> "%r10b" | R11 -> "%r11b" + | R12 -> "%r12b" | R13 -> "%r13b" | R14 -> "%r14b" | R15 -> "%r15b" + +let string_of_lbl (l:lbl) : string = l + +let string_of_imm : imm -> string = function + | Lit i -> Int64.to_string i + | Lbl l -> string_of_lbl l + +let string_of_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_byte_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_byte_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_jmp_operand : operand -> string = function + | Imm i -> string_of_imm i + | Reg r -> "*" ^ string_of_reg r + | Ind1 i -> "*" ^ string_of_imm i + | Ind2 r -> "*" ^ "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> "*" ^ string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_cnd : cnd -> string = function + | Eq -> "e" | Neq -> "ne" | Gt -> "g" + | Ge -> "ge" | Lt -> "l" | Le -> "le" + +let string_of_opcode : opcode -> string = function + | Movq -> "movq" | Pushq -> "pushq" | Popq -> "popq" + | Leaq -> "leaq" + | Incq -> "incq" | Decq -> "decq" | Negq -> "negq" | Notq -> "notq" + | Addq -> "addq" | Subq -> "subq" | Imulq -> "imulq" + | Xorq -> "xorq" | Orq -> "orq" | Andq -> "andq" + | Shlq -> "shlq" | Sarq -> "sarq" | Shrq -> "shrq" + | Jmp -> "jmp" | J c -> "j" ^ string_of_cnd c + | Cmpq -> "cmpq" | Set c -> "set" ^ string_of_cnd c + | Callq -> "callq" | Retq -> "retq" + +let map_concat s f l = String.concat s @@ List.map f l + +let string_of_shift op = function + | [ Imm i ; dst ] as args -> + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " string_of_operand args + | [ Reg Rcx ; dst ] -> + Printf.sprintf "\t%s\t%%cl, %s" (string_of_opcode op) (string_of_operand dst) + | args -> failwith (Printf.sprintf "shift instruction has invalid operands: %s\n" + (map_concat ", " string_of_operand args)) + +let string_of_ins (op, args: ins) : string = + match op with + | Shlq | Sarq | Shrq -> string_of_shift op args + | _ -> + let f = match op with + | J _ | Jmp | Callq -> string_of_jmp_operand + | Set _ -> string_of_byte_operand + | _ -> string_of_operand + in + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " f args + +let string_of_data : data -> string = function + | Asciz s -> "\t.asciz\t" ^ "\"" ^ (String.escaped s) ^ "\"" + | Quad i -> "\t.quad\t" ^ string_of_imm i + +let string_of_asm : asm -> string = function + | Text is -> "\t.text\n" ^ map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n" ^ map_concat "\n" string_of_data ds + +let string_of_elem {lbl; global; asm} : string = + let sec, body = match asm with + | Text is -> "\t.text\n", map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n", map_concat "\n" string_of_data ds + in + let glb = if global then "\t.globl\t" ^ string_of_lbl lbl ^ "\n" else "" in + sec ^ glb ^ string_of_lbl lbl ^ ":\n" ^ body + +let string_of_prog (p:prog) : string = + String.concat "\n" @@ List.map string_of_elem p diff --git a/hw4/.ocamlinit b/hw4/.ocamlinit new file mode 100644 index 0000000..56ad796 --- /dev/null +++ b/hw4/.ocamlinit @@ -0,0 +1,9 @@ +#use "topfind";; + +#directory "_build" +#directory "_build/util" +#directory "_build/x86" +#directory "_build/grading" + +#load_rec "x86.cmo" +#use "llinterp.ml" \ No newline at end of file diff --git a/hw4/Makefile b/hw4/Makefile new file mode 100644 index 0000000..12de57b --- /dev/null +++ b/hw4/Makefile @@ -0,0 +1,24 @@ +INCLUDES= util,x86,grading,ll +LIBS = unix,str +SUBMIT := lexer.mll parser.mly frontend.ml team.txt + +HWNAME := hw04 +ZIPNAME := $(HWNAME)-submit.zip + + +all: main.native + +.PHONY: test +test: main.native + ./main.native --test + +main.native: $(SUBMIT) ast.ml astlib.ml backend.ml driver.ml main.ml progasts.ml runtime.c + ocamlbuild -Is $(INCLUDES) -libs $(LIBS) -pkg num main.native -use-menhir -yaccflag --explain + +zip: $(SUBMIT) + zip '$(ZIPNAME)' $(SUBMIT) + +.PHONY: clean +clean: + ocamlbuild -clean + rm -rf output a.out diff --git a/hw4/README b/hw4/README new file mode 100644 index 0000000..c640226 --- /dev/null +++ b/hw4/README @@ -0,0 +1,76 @@ +Using main.native: + +main.native acts like the clang compiler. Given several .ll, .c, and .o files, +it will compile the .ll files to .s files (using the Compiler Design backend) +and then combine the results with the .c and .o files to produce an executable +named a.out. You can also compile the .ll files using clang instead of the +Compiler Design backend, which can be useful for testing purposes. + + +* To run the automated test harness do: + ./main.native --test + +* To compile ll files using the Compiler Design backend: + ./main.native path/to/foo.ll + + - creates output/foo.s backend assembly code + - creates output/foo.o assembled object file + - creates a.out linked executable + + NOTE: by default the .s and .o files are created in + a directory called output, and the filenames are + chosen so that multiple runs of the compiler will + not overwrite previous outputs. foo.ll will be + compiled first to foo.s then foo_1.s, foo_2.s, etc. + + +* To compile ll files using the clang backend: + ./main.native --clang path/to/foo.ll + +* Useful flags: + --print-oat + pretty prints the Oat abstract syntax to the terminal + + --print-ll + echoes the ll program to the terminal + + --print-x86 + echoes the resulting .s file to the terminal + + --interpret-ll + runs the ll file through the reference interpreter + and outputs the results to the console + + --execute-x86 + runs the resulting a.out file natively + (applies to either the Compiler Design backend or clang-compiled code) + + --clang compiles to assembly using clang, not the Compiler Design backend + + -v + generates verbose output, showing which commands are used + for linking, etc. + + -op + change the output path [DEFAULT=output] + + -o + change the generated executable's name [DEFAULT=a.out] + + -S + stop after generating .s files + + -c + stop after generating .o files + + -h or --help + display the list of options + +* Example uses: + +Run the test case /programs/factrect.ll using the Compiler Design backend: + + +./main.native --execute-x86 programs/factrect.ll +--------------------------------------------------------------- Executing: a.out +* a.out returned 120 diff --git a/hw4/ast.ml b/hw4/ast.ml new file mode 100644 index 0000000..0b0319c --- /dev/null +++ b/hw4/ast.ml @@ -0,0 +1,84 @@ + +type 'a node = { elt : 'a; loc : Range.t } + +(** val no_loc : 'a1 -> 'a1 node **) + +let no_loc x = + { elt = x; loc = Range.norange } + +type id = string + +type ty = +| TBool +| TInt +| TRef of rty +and rty = +| RString +| RArray of ty +| RFun of ty list * ret_ty +and ret_ty = +| RetVoid +| RetVal of ty + +type unop = +| Neg +| Lognot +| Bitnot + +type binop = +| Add +| Sub +| Mul +| Eq +| Neq +| Lt +| Lte +| Gt +| Gte +| And +| Or +| IAnd +| IOr +| Shl +| Shr +| Sar + +type exp = +| CNull of rty +| CBool of bool +| CInt of int64 +| CStr of string +| CArr of ty * exp node list +| NewArr of ty * exp node +| Id of id +| Index of exp node * exp node +| Call of exp node * exp node list +| Bop of binop * exp node * exp node +| Uop of unop * exp node + +type cfield = id * exp node + +type vdecl = id * exp node + +type stmt = +| Assn of exp node * exp node +| Decl of vdecl +| Ret of exp node option +| SCall of exp node * exp node list +| If of exp node * stmt node list * stmt node list +| For of vdecl list * exp node option * stmt node option * stmt node list +| While of exp node * stmt node list + +type block = stmt node list + +type gdecl = { name : id; init : exp node } + +type fdecl = { frtyp : ret_ty; fname : id; args : (ty * id) list; body : block } + +type field = { fieldName : id; ftyp : ty } + +type decl = +| Gvdecl of gdecl node +| Gfdecl of fdecl node + +type prog = decl list diff --git a/hw4/astlib.ml b/hw4/astlib.ml new file mode 100644 index 0000000..3a676f4 --- /dev/null +++ b/hw4/astlib.ml @@ -0,0 +1,553 @@ +(* astlib.ml *) + +(* Helper functions of abstract syntax of trees. *) +(******************************************************************************) + +open Format +open Ast +open Range + +(* Precedence for expressions and operators *) +(* Higher precedences bind more tightly *) + +let prec_of_binop = function +| Mul -> 100 +| Add | Sub -> 90 +| Shl | Shr | Sar -> 80 +| Lt | Lte | Gt | Gte -> 70 +| Eq | Neq -> 60 +| And -> 50 +| Or -> 40 +| IAnd -> 30 +| IOr -> 20 + +let prec_of_unop = function _ -> 110 + +let prec_of_exp = function +| Bop (o,_,_) -> prec_of_binop o +| Uop (o,_) -> prec_of_unop o +| _ -> 130 + + +(* Pretty Printer for AST *) +let string_of_unop = function +| Neg -> "-" +| Lognot -> "!" +| Bitnot -> "~" + +let string_of_binop = function +| Mul -> "*" +| Add -> "+" +| Sub -> "-" +| Shl -> "<<" +| Shr -> ">>" +| Sar -> ">>>" +| Lt -> "<" +| Lte -> "<=" +| Gt -> ">" +| Gte -> ">=" +| Eq -> "==" +| Neq -> "!=" +| And -> "&" +| Or -> "|" +| IAnd -> "[&]" +| IOr -> "[|]" + +let print_id_aux fmt (x:id) = pp_print_string fmt x + +let rec print_list_aux fmt sep pp l = + begin match l with + | [] -> () + | [h] -> pp fmt h + | h::tl -> pp fmt h; sep (); + print_list_aux fmt sep pp tl + end + +let rec print_ty_aux fmt t = + let pps = pp_print_string fmt in + match t with + | TBool -> pps "bool" + | TInt -> pps "int" + | TRef r -> print_rty_aux fmt r + +and print_ret_ty_aux fmt t = + let pps = pp_print_string fmt in + begin match t with + | RetVoid -> pps "void" + | RetVal t -> print_ty_aux fmt t + end + +and print_rty_aux fmt r = + let pps = pp_print_string fmt in + begin match r with + | RString -> pps "string" + | RArray t -> print_ty_aux fmt t; pps "[]" + | RFun (ts, t) -> pps "("; + print_list_aux fmt (fun () -> pps ", ") print_ty_aux ts; + pps ")"; pps "->"; print_ret_ty_aux fmt t + end + +and print_exp_aux level fmt e = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let this_level = prec_of_exp e.elt in + + if this_level < level then pps "("; + begin match e.elt with + | CNull t -> print_rty_aux fmt t; pps "null" + | CBool v -> pps (if v then "true" else "false") + | CInt v -> pps (Int64.to_string v) + | CStr v -> pps (Printf.sprintf "%S" v) + | CArr (ty,vs) -> begin + pps "new "; print_ty_aux fmt ty; pps "[]"; + pps "{"; + pp_open_hbox fmt (); + print_list_aux fmt (fun () -> pps ","; pp_print_space fmt()) (print_exp_aux 0) vs; + pp_close_box fmt (); + pps "}"; + end + | Id id -> print_id_aux fmt id + | Index (e,i) -> print_exp_aux this_level fmt e; pps "["; print_exp_aux 0 fmt i; pps "]" + | Call (e, es) -> print_exp_aux this_level fmt e; print_exps_aux "(" ")" fmt es + | NewArr (ty, e1) -> + pps "new "; print_ty_aux fmt ty; + pps "["; print_exp_aux 0 fmt e1; pps "]" + | Bop (o,l,r) -> + pp_open_box fmt 0; + print_exp_aux this_level fmt l; + ppsp (); pps (string_of_binop o); ppsp (); + print_exp_aux this_level fmt r; + pp_close_box fmt () + | Uop (o,v) -> + pp_open_box fmt 0; + pps (string_of_unop o); + print_exp_aux this_level fmt v; + pp_close_box fmt () + end; if this_level < level then pps ")" + +and print_cfield_aux l fmt (name, exp) = + pp_open_box fmt 0; + pp_print_string fmt name; + pp_print_string fmt "="; print_exp_aux l fmt exp; + pp_close_box fmt (); + +and print_exps_aux l r fmt es = + let pps = pp_print_string fmt in + pps l; + pp_open_hvbox fmt 0; + print_list_aux fmt + (fun () -> pps ","; pp_print_space fmt()) + (fun fmt -> fun e -> print_exp_aux 0 fmt e) es; + pp_close_box fmt (); + pps r + +let print_vdecl_aux semi fmt (id, init) = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + pp_open_hbox fmt (); + pps "var "; print_id_aux fmt id; + ppsp (); pps " ="; ppsp (); + print_exp_aux 0 fmt init; pps semi; + pp_close_box fmt () + +let rec print_block_aux fmt stmts = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let ppnl = pp_force_newline fmt in + + if (List.length stmts) > 0 then + begin pps "{"; ppnl (); pps " "; + pp_open_vbox fmt 0; + print_list_aux fmt (fun () -> ppsp ()) print_stmt_aux stmts; + pp_close_box fmt (); + ppnl (); pps "}" + end + else pps "{ }" + +and print_cond_aux fmt b_then opt_b_else = + let pps = pp_print_string fmt in + print_block_aux fmt b_then; + begin match opt_b_else with + | [] -> () + | b_else -> pps " else "; print_block_aux fmt b_else + end + +and print_stmt_aux fmt s = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + + begin match s.elt with + | Decl d -> print_vdecl_aux ";" fmt d + + | Assn (p,e) -> + pp_open_box fmt 0; + print_exp_aux 0 fmt p; + pps " ="; ppsp (); + print_exp_aux 0 fmt e; + pps ";"; pp_close_box fmt () + + | SCall (e, es) -> + print_exp_aux 0 fmt e; print_exps_aux "(" ")" fmt es; pps ";" + + | Ret (eo) -> + pps "return"; + begin match eo with + | None -> () + | Some e -> pps " "; print_exp_aux 0 fmt e + end; pps ";" + + | If (e, b_then, opt_b_else) -> + pps "if ("; print_exp_aux 0 fmt e; pps ") "; + print_cond_aux fmt b_then opt_b_else + + | While(e, b) -> + pps "while ("; print_exp_aux 0 fmt e; pps ") "; + print_block_aux fmt b + + | For(decls, eo, so, body) -> + pps "for ("; pp_open_hvbox fmt 0; + print_list_aux fmt (fun () -> pps ","; ppsp ()) (print_vdecl_aux "") decls; + pps ";"; ppsp (); + begin match eo with + | None -> (); + | Some e -> print_exp_aux 0 fmt e; + end; + pps ";"; ppsp (); + begin match so with + | None -> () + | Some s -> print_stmt_aux fmt s + end; pp_close_box fmt (); + pps ") "; print_block_aux fmt body + end + +let print_fdecl_aux fmt {elt={frtyp; fname; args; body}} = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let ppnl = pp_force_newline fmt in + + print_ret_ty_aux fmt frtyp; + pps @@ Printf.sprintf " %s(" fname; + pp_open_hbox fmt (); + print_list_aux fmt (fun () -> pps ","; ppsp ()) + (fun fmt -> fun (t, id) -> + print_ty_aux fmt t; + pps " "; + print_id_aux fmt id; + ) args; + pp_close_box fmt (); + pps ") "; print_block_aux fmt body; ppnl () + +let print_gdecl_aux fmt (gd:Ast.gdecl) = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + pp_open_hbox fmt (); + pps @@ Printf.sprintf "global %s =" gd.name; ppsp (); + print_exp_aux 0 fmt gd.init; pps ";"; + pp_close_box fmt () + +let print_field fmt f = + let pps = pp_print_string fmt in + pp_open_hbox fmt (); + print_ty_aux fmt f.ftyp; pps " "; pps f.fieldName; + pp_close_box fmt () + +let print_decl_aux fmt g = + begin match g with + | Gvdecl d -> print_gdecl_aux fmt d.elt + | Gfdecl f -> print_fdecl_aux fmt f + end + +let print_prog_aux fmt p = + let ppnl = pp_force_newline fmt in + pp_open_vbox fmt 0; + List.iter (fun g -> print_decl_aux fmt g; ppnl (); ppnl ()) p; + pp_close_box fmt () + +let print ppx x : unit = + pp_open_hvbox std_formatter 0; + ppx std_formatter x; + pp_close_box std_formatter (); + pp_print_newline std_formatter () + +let string_of ppx x : string = + pp_open_hvbox str_formatter 0; + ppx str_formatter x; + pp_close_box str_formatter (); + flush_str_formatter () + +let print_prog (p:prog) : unit = print print_prog_aux p +let string_of_prog (p:prog) : string = string_of print_prog_aux p + +let print_stmt (s:stmt node) : unit = print print_stmt_aux s +let string_of_stmt (s:stmt node) : string = string_of print_stmt_aux s + +let print_block (b:block) : unit = print print_block_aux b +let string_of_block (b:block) : string = string_of print_block_aux b + +let print_exp (e:exp node) : unit = print (print_exp_aux 0) e +let string_of_exp (e:exp node) : string = string_of (print_exp_aux 0) e + +let print_ty (t:ty) : unit = print print_ty_aux t +let string_of_ty (t:ty) : string = string_of print_ty_aux t + +(* AST to ML *) + +let sp = Printf.sprintf + +let ml_string_of_list (f: 'a -> string) (l: 'a list) : string = + sp "[ %s ]" (String.concat " ; " (List.map f l)) + +let ml_string_of_option (f: 'a -> string) (o: 'a option) : string = + begin match o with + | None -> sp "None" + | Some x -> sp "Some (%s)" (f x) + end + +(* TODO Change ml string printing for loc *) + +let ml_string_of_node (f: 'a -> string) ({elt;loc}: 'a node) = + sp "{ elt = %s; loc = %s }" (f elt) (Range.ml_string_of_range loc) + +let rec ml_string_of_ty (t:ty) : string = + match t with + | TBool -> "TBool" + | TInt -> "TInt" + | TRef r -> sp "TRef (%s)" (ml_string_of_reft r) + +and ml_string_of_ret_ty r = + match r with + | RetVoid -> "TVoid" + | RetVal t -> sp "RetVal (%s)" (ml_string_of_ty t) + + +and ml_string_of_reft (r:rty) : string = + match r with + | RString -> "RString" + | RArray t -> sp "(RArray (%s))" (ml_string_of_ty t) + | RFun (ts, t) -> sp "RFun (%s, %s)" + (ml_string_of_list ml_string_of_ty ts) + (ml_string_of_ret_ty t) + + +let ml_string_of_id : id -> string = (sp "\"%s\"") + +let ml_string_of_binop : binop -> string = function + | Add -> "Add" + | Sub -> "Sub" + | Mul -> "Mul" + | Eq -> "Eq" + | Neq -> "Neq" + | Lt -> "Lt" + | Lte -> "Lte" + | Gt -> "Gt" + | Gte -> "Gte" + | And -> "And" + | Or -> "Or" + | IAnd -> "IAnd" + | IOr -> "IOr" + | Shl -> "Shl" + | Shr -> "Shr" + | Sar -> "Sar" + +let ml_string_of_unop : unop -> string = function + | Neg -> "Neg" + | Lognot -> "Lognot" + | Bitnot -> "Bitnot" + +let rec ml_string_of_exp_aux (e: exp) : string = + begin match e with + | CNull t -> sp "CNull %s" (ml_string_of_reft t) + | CBool b -> sp "CBool %b" b + | CInt i -> sp "CInt %LiL" i + | CStr s -> sp "CStr %S" s + | CArr (t,cs) -> sp "CArr (%s,%s)" + (ml_string_of_ty t) + (ml_string_of_list ml_string_of_exp cs) + | Id id -> sp "Id %s" (ml_string_of_id id) + | Index (e, i) -> sp "Index (%s, %s)" + (ml_string_of_exp e) (ml_string_of_exp i) + | Call (e, exps) -> sp "Call (%s, %s)" + (ml_string_of_exp e) + (ml_string_of_list ml_string_of_exp exps) + | NewArr (t,e1) -> sp "NewArr (%s,%s)" + (ml_string_of_ty t) (ml_string_of_exp e1) + | Bop (b, e1, e2) -> sp "Bop (%s,%s,%s)" + (ml_string_of_binop b) (ml_string_of_exp e1) (ml_string_of_exp e2) + | Uop (u, e) -> sp "Uop (%s, %s)" + (ml_string_of_unop u) (ml_string_of_exp e) + end + +and ml_string_of_exp (e:exp node) : string = + ml_string_of_node ml_string_of_exp_aux e + +and ml_string_of_field ((id, exp) : cfield) : string = + sp "%s = %s;" (ml_string_of_id id) (ml_string_of_exp exp) + +let ml_string_of_vdecl_aux (id,init:vdecl) : string = + sp "(%s, %s)" + (ml_string_of_id id) (ml_string_of_exp init) + +let ml_string_of_vdecl (d:vdecl node) : string = + ml_string_of_node ml_string_of_vdecl_aux d + +let rec ml_string_of_stmt_aux (s:stmt) : string = + match s with + | Assn (p, e) -> sp "Assn (%s,%s)" (ml_string_of_exp p) (ml_string_of_exp e) + | Decl d -> sp "Decl (%s)" (ml_string_of_vdecl_aux d) + | Ret e -> sp "Ret (%s)" (ml_string_of_option ml_string_of_exp e) + | SCall (exp, exps) -> + sp "SCall (%s, %s)" (ml_string_of_exp exp) (ml_string_of_list ml_string_of_exp exps) + | If (e,b1,b2) -> sp "If (%s,%s,%s)" + (ml_string_of_exp e) (ml_string_of_block b1) (ml_string_of_block b2) + | For (d,e,s,b) -> sp "For (%s,%s,%s,%s)" + (ml_string_of_list ml_string_of_vdecl_aux d) + (ml_string_of_option ml_string_of_exp e) + (ml_string_of_option ml_string_of_stmt s) (ml_string_of_block b) + | While (e,b) -> sp "While (%s,%s)" (ml_string_of_exp e) (ml_string_of_block b) + +and ml_string_of_stmt (s:stmt node) : string = + ml_string_of_node ml_string_of_stmt_aux s + +and ml_string_of_block (b:block) : string = + ml_string_of_list ml_string_of_stmt b + +let ml_string_of_args : (ty * id) list -> string = + ml_string_of_list (fun (t,i) -> + sp "(%s,%s)" (ml_string_of_ty t) (ml_string_of_id i)) + +let rec ml_string_of_fdecl_aux (f:fdecl) : string = + sp "{ frtyp = %s; fname = %s; args = %s; body = %s }" + (ml_string_of_ret_ty f.frtyp) (ml_string_of_id f.fname) + (ml_string_of_args f.args) (ml_string_of_block f.body) + +and ml_string_of_fdecl (f:fdecl node) : string = + ml_string_of_node ml_string_of_fdecl_aux f + +let ml_string_of_gdecl_aux (gd:gdecl) : string = + sp "{ name = %s; init = %s }" + (ml_string_of_id gd.name) (ml_string_of_exp gd.init) + +let ml_string_of_gdecl (d:gdecl node) : string = + ml_string_of_node ml_string_of_gdecl_aux d + + +let ml_string_of_decl : decl -> string = function + | Gvdecl d -> sp "Gvdecl (%s)" (ml_string_of_gdecl d) + | Gfdecl f -> sp "Gfdecl (%s)" (ml_string_of_fdecl f) + +let ml_string_of_prog : prog -> string = + ml_string_of_list ml_string_of_decl + +(* Checking AST equivalence *) +let eq_option (f: 'a -> 'a -> bool) (o1: 'a option) (o2: 'a option) : bool = + begin match o1, o2 with + | None, None -> true + | Some a1, Some a2 -> f a1 a2 + | _ -> false + end + +let rec eq_list (f: 'a -> 'a -> bool) (l1: 'a list) (l2: 'a list) : bool = + begin match l1, l2 with + | [], [] -> true + | h1::t1, h2::t2 -> f h1 h2 && eq_list f t1 t2 + | _ -> false + end + +let eq_node (f: 'a -> 'a -> bool) (l1: 'a node) (l2 : 'a node) : bool = + f l1.elt l2.elt + +let eq_id : id -> id -> bool = String.equal + +let rec eq_ty (t1: ty) (t2: ty) : bool = + match t1, t2 with + | TBool, TBool + | TInt, TInt -> true + | TRef r1, TRef r2 -> eq_rtyp r1 r2 + | _ -> false + +and eq_ret_ty r1 r2 : bool = + match r1, r2 with + | RetVoid, RetVoid -> true + | RetVal t1, RetVal t2 -> eq_ty t1 t2 + | _, _ -> false + +and eq_rtyp (r1:rty) (r2:rty) : bool = + begin match r1, r2 with + | RString, RString -> true + | RArray t1, RArray t2 -> eq_ty t1 t2 + | _ -> false + end + + +let eq_unop : unop -> unop -> bool = (=) +let eq_binop : binop -> binop -> bool = (=) + +let rec eq_exp_aux (e1:exp) (e2:exp) : bool = + begin match e1, e2 with + | CNull t1, CNull t2 -> eq_rtyp t1 t2 + | CBool b1, CBool b2 -> b1 = b2 + | CInt i1, CInt i2 -> i1 = i2 + | CStr s1, CStr s2 -> s1 = s2 + | CArr (t1,cs1), CArr (t2,cs2) -> eq_ty t1 t2 && eq_list eq_exp cs1 cs2 + | Id i1, Id i2 -> eq_id i1 i2 + | Index (e1,i1), Index (e2,i2) -> eq_exp e1 e2 && eq_exp i1 i2 + | Call (i1, es1), Call (i2, es2) -> eq_exp i1 i2 && eq_list eq_exp es1 es2 + | NewArr (t1, e11), NewArr (t2, e21) -> + eq_ty t1 t2 && eq_exp e11 e21 + | Bop (b1, e11, e12), Bop (b2, e21, e22) -> + eq_binop b1 b2 && eq_exp e11 e21 && eq_exp e12 e22 + | Uop (u1, e1), Uop (u2, e2) -> + eq_unop u1 u2 && eq_exp e1 e2 + | _ -> false + end + +and eq_exp (e1:exp node) (e2:exp node) : bool = eq_node eq_exp_aux e1 e2 + +let eq_vdecl_aux (i1,e1:vdecl) (i2,e2:vdecl) : bool = + eq_id i1 i2 && eq_exp e1 e2 + +let eq_vdecl (d1:vdecl node) (d2:vdecl node) : bool = + eq_node eq_vdecl_aux d1 d2 + + +let rec eq_stmt_aux (s1: stmt) (s2: stmt) : bool = + begin match s1, s2 with + | Assn (p1, e1), Assn (p2, e2) -> eq_exp p1 p2 && eq_exp e1 e2 + | Decl d1, Decl d2 -> eq_vdecl_aux d1 d2 + | Ret eo1, Ret eo2 -> eq_option eq_exp eo1 eo2 + | SCall (x1, es1), SCall (x2, es2) -> eq_exp x1 x2 && eq_list eq_exp es1 es2 + | If (e1, b11, b12), If (e2, b21, b22) -> + eq_exp e1 e2 && eq_block b11 b21 && eq_block b12 b22 + | For (ds1, eo1, s1, b1), For (ds2, eo2, s2, b2) -> + eq_list eq_vdecl_aux ds1 ds2 && eq_option eq_exp eo1 eo2 && + eq_option eq_stmt s1 s2 && eq_block b1 b2 + | While (e1, b1), While (e2, b2) -> eq_exp e1 e2 && eq_block b1 b2 + | _ -> false + end + +and eq_stmt (s1:stmt node) (s2:stmt node) : bool = eq_node eq_stmt_aux s1 s2 +and eq_block (b1:block) (b2:block) : bool = eq_list eq_stmt b1 b2 + +let eq_args (a1:(ty * id) list) (a2:(ty * id) list) : bool = + eq_list (fun (t1,i1) (t2, i2) -> eq_ty t1 t2 && eq_id i1 i2) a1 a2 + +let rec eq_fdecl_aux (f1:fdecl) (f2:fdecl) : bool = + eq_ret_ty f1.frtyp f2.frtyp && eq_id f1.fname f2.fname && + eq_args f1.args f2.args && eq_block f1.body f2.body + +and eq_fdecl (f1:fdecl node) (f2:fdecl node) : bool = eq_node eq_fdecl_aux f1 f2 + +let eq_gdecl_aux (g1:gdecl) (g2:gdecl) : bool = + eq_id g1.name g2.name && eq_exp g1.init g2.init + +let eq_gdecl (d1:gdecl node) (d2:gdecl node) : bool = + eq_node eq_gdecl_aux d1 d2 + +let eq_decl (g1:decl) (g2:decl) : bool = + begin match g1, g2 with + | Gvdecl d1, Gvdecl d2 -> eq_gdecl d1 d2 + | Gfdecl f1, Gfdecl f2 -> eq_fdecl f1 f2 + | _ -> false + end + +let eq_prog (p1: prog) (p2: prog) : bool = eq_list eq_decl p1 p2 diff --git a/hw4/backend.ml b/hw4/backend.ml new file mode 100644 index 0000000..beebfd6 --- /dev/null +++ b/hw4/backend.ml @@ -0,0 +1,479 @@ +(* ll ir compilation -------------------------------------------------------- *) + +open Ll +open X86 + +(* Overview ----------------------------------------------------------------- *) + +(* We suggest that you spend some time understinging this entire file and + how it fits with the compiler pipeline before making changes. The suggested + plan for implementing the compiler is provided on the project web page. +*) + + +(* helpers ------------------------------------------------------------------ *) + +(* Map LL comparison operations to X86 condition codes *) +let compile_cnd = function + | Ll.Eq -> X86.Eq + | Ll.Ne -> X86.Neq + | Ll.Slt -> X86.Lt + | Ll.Sle -> X86.Le + | Ll.Sgt -> X86.Gt + | Ll.Sge -> X86.Ge + +let imm_of_int (n:int) = Imm (Lit (Int64.of_int n)) + +(* Compute an indirect address that is a fixed byte offset from %rbp *) +let rbp_offset (offset:int) : X86.operand = + let amt = Int64.of_int offset in + Ind3 (Lit amt, Rbp) + +(* locals and layout -------------------------------------------------------- *) + +(* One key problem in compiling the LLVM IR is how to map its local + identifiers to X86 abstractions. For the best performance, one + would want to use an X86 register for each LLVM %uid. However, + since there are an unlimited number of %uids and only 16 registers, + doing so effectively is quite difficult. We will see later in the + course how _register allocation_ algorithms can do a good job at + this. + + A simpler, but less performant, implementation is to map each %uid + in the LLVM source to a _stack slot_ (i.e. a region of memory in + the stack). Since LLVMlite, unlike real LLVM, permits %uid locals + to store only 64-bit data, each stack slot is an 8-byte value. + + [ NOTE: For compiling LLVMlite, even i1 data values should be + represented as a 8-byte quad. This greatly simplifies code + generation. ] + + We call the datastructure that maps each %uid to its stack slot a + 'stack layout'. A stack layout maps a uid to an X86 operand for + accessing its contents. For this compilation strategy, the operand + is always an offset from %rbp (in bytes) that represents a storage slot in + the stack. +*) + +type layout = (uid * X86.operand) list + +(* A context contains the global type declarations (needed for getelementptr + calculations) and a stack layout. *) +type ctxt = { tdecls : (tid * ty) list + ; layout : layout + } + +(* useful for looking up items in tdecls or layouts *) +let lookup m x = List.assoc x m + + +(* compiling operands ------------------------------------------------------ *) + +(* LLVM IR instructions support several kinds of operands. + + LL local %uids live in stack slots, whereas global ids live at + global addresses that must be computed from a label. Constants are + immediately available, and the operand Null is the 64-bit 0 value. + + NOTE: two important facts about global identifiers: + + (1) You should use (Platform.mangle gid) to obtain a string + suitable for naming a global label on your platform (OS X expects + "_main" while linux expects "main"). + + (2) 64-bit assembly labels are not allowed as immediate operands. + That is, the X86 code: movq _gid %rax which looks like it should + put the address denoted by _gid into %rax is not allowed. + Instead, you need to compute an %rip-relative address using the + leaq instruction: leaq _gid(%rip). + + One strategy for compiling instruction operands is to use a + designated register (or registers) for holding the values being + manipulated by the LLVM IR instruction. You might find it useful to + implement the following helper function, whose job is to generate + the X86 instruction that moves an LLVM operand into a designated + destination (usually a register). +*) +let compile_operand ctxt dest : Ll.operand -> ins = + function + | Null -> Asm.(Movq, [~$0; dest]) + | Const i -> Asm.(Movq, [Imm (Lit i); dest]) + | Gid id -> Asm.(Leaq, [Ind3 (Lbl (Platform.mangle id), Rip); dest]) + | Id id -> Asm.(Movq, [lookup ctxt.layout id; dest]) + + +(* compiling call ---------------------------------------------------------- *) + +(* You will probably find it helpful to implement a helper function that + generates code for the LLVM IR call instruction. + + The code you generate should follow the x64 System V AMD64 ABI + calling conventions, which places the first six 64-bit (or smaller) + values in registers and pushes the rest onto the stack. Note that, + since all LLVM IR operands are 64-bit values, the first six + operands will always be placed in registers. (See the notes about + compiling fdecl below.) + + [ NOTE: It is the caller's responsibility to clean up arguments + pushed onto the stack, so you must free the stack space after the + call returns. ] + + [ NOTE: Don't forget to preserve caller-save registers (only if + needed). ] +*) + + +let arg_reg : int -> (X86.operand) option = function + | 0 -> Some (Reg Rdi) + | 1 -> Some (Reg Rsi) + | 2 -> Some (Reg Rdx) + | 3 -> Some (Reg Rcx) + | 4 -> Some (Reg R08) + | 5 -> Some (Reg R09) + | n -> None + +let compile_call ctxt fop args = + let op_to_rax = compile_operand ctxt (Reg Rax) in + let call_code, op = match fop with + | Gid g -> [], Imm (Lbl (Platform.mangle g)) + | Id _ -> [op_to_rax fop], (Reg Rax) + | _ -> failwith "call function operand was not a local or global id" + in + + let arg_code = + let (_, register_arg_code, stack_arg_code) = + List.fold_left (fun (i, r, s) (_,op) -> + let r, s = match arg_reg i with + | Some reg -> r @ (op_to_rax op :: Asm.([Movq, [~%Rax; reg]])), s + | None -> r, (op_to_rax op :: Asm.([Pushq, [~%Rax]])) @ s + in (i+1, r, s) + ) (0, [], []) args + in register_arg_code @ stack_arg_code + in + + arg_code @ call_code @ + (X86.Callq, [op]) :: + (if (List.length args) > 6 then + Asm.([Addq, [imm_of_int (8 * ((List.length args) - 6)); ~%Rsp]]) + else []) + +(* compiling getelementptr (gep) ------------------------------------------- *) + +(* The getelementptr instruction computes an address by indexing into + a datastructure, following a path of offsets. It computes the + address based on the size of the data, which is dictated by the + data's type. + + To compile getelmentptr, you must generate x86 code that performs + the appropriate arithemetic calculations. +*) + +(* [size_ty] maps an LLVMlite type to a size in bytes. + (needed for getelementptr) + + - the size of a struct is the sum of the sizes of each component + - the size of an array of t's with n elements is n * the size of t + - all pointers, I1, and I64 are 8 bytes + - the size of a named type is the size of its definition + + - Void, i8, and functions have undefined sizes according to LLVMlite. + Your function should simply return 0 in those cases +*) +let rec size_ty (tdecls:(tid * ty) list) (t:Ll.ty) : int = + begin match t with + | Void | I8 | Fun _ -> 0 + | I1 | I64 | Ptr _ -> 8 (* Target 64-bit only subset of X86 *) + | Struct ts -> List.fold_left (fun acc t -> acc + (size_ty tdecls t)) 0 ts + | Array (n, t) -> n * (size_ty tdecls t) + | Namedt id -> size_ty tdecls (List.assoc id tdecls) + end + +(* Compute the size of the offset (in bytes) of the nth element of a region + of memory whose types are given by the list. Also returns the nth type. *) +let index_into tdecls (ts:ty list) (n:int) : int * ty = + let rec loop ts n acc = + begin match (ts, n) with + | (u::_, 0) -> (acc, u) + | (u::us, n) -> loop us (n-1) (acc + (size_ty tdecls u)) + | _ -> failwith "index_into encountered bogus index" + end + in loop ts n 0 + + +(* Generates code that computes a pointer value. + + 1. op must be of pointer type: t* + + 2. the value of op is the base address of the calculation + + 3. the first index in the path is treated as the index into an array + of elements of type t located at the base address + + 4. subsequent indices are interpreted according to the type t: + + - if t is a struct, the index must be a constant n and it + picks out the n'th element of the struct. [ NOTE: the offset + within the struct of the n'th element is determined by the + sizes of the types of the previous elements ] + + - if t is an array, the index can be any operand, and its + value determines the offset within the array. + + - if t is any other type, the path is invalid + + 5. if the index is valid, the remainder of the path is computed as + in (4), but relative to the type f the sub-element picked out + by the path so far +*) +let compile_gep (ctxt:ctxt) (op : Ll.ty * Ll.operand) (path: Ll.operand list) : ins list = + let op_to_rax = compile_operand ctxt (Reg Rax) in + let rec loop ty path code = + match (ty, path) with + | (_, []) -> List.rev code + + | (Struct ts, Const n::rest) -> + let (offset, u) = index_into ctxt.tdecls ts (Int64.to_int n) in + loop u rest @@ Asm.(Addq, [~$offset; ~%Rax])::code + + | (Array(_, u), Const n::rest) -> + (* Statically calculate the offset *) + let offset = (size_ty ctxt.tdecls u) * (Int64.to_int n) in + loop u rest @@ Asm.(Addq, [~$offset; ~%Rax])::code + + | (Array(_, u), offset_op::rest) -> + loop u rest @@ + Asm.([ Addq, [~%Rcx; ~%Rax] + ; Imulq, [imm_of_int @@ size_ty ctxt.tdecls u; ~%Rax] ]) + @ (op_to_rax offset_op) :: + Asm.(Movq, [~%Rax; ~%Rcx]) + :: code + + | (Namedt t, p) -> loop (List.assoc t ctxt.tdecls) p code + + | _ -> failwith "compile_gep encountered unsupported getelementptr data" in + + match op with + | (Ptr t, op) -> loop (Array(0, t)) path [op_to_rax op] + | _ -> failwith "compile_gep got incorrect parameters" + + +(* compiling instructions -------------------------------------------------- *) + +(* The result of compiling a single LLVM instruction might be many x86 + instructions. We have not determined the structure of this code + for you. Some of the instructions require only a couple of assembly + instructions, while others require more. We have suggested that + you need at least compile_operand, compile_call, and compile_gep + helpers; you may introduce more as you see fit. + + Here are a few notes: + + - Icmp: the Setb instruction may be of use. Depending on how you + compile Cbr, you may want to ensure that the value produced by + Icmp is exactly 0 or 1. + + - Load & Store: these need to dereference the pointers. Const and + Null operands aren't valid pointers. Don't forget to + Platform.mangle the global identifier. + + - Alloca: needs to return a pointer into the stack + + - Bitcast: does nothing interesting at the assembly level +*) +let compile_insn (ctxt:ctxt) ((uid:uid), (i:Ll.insn)) : X86.ins list = + let op_to = compile_operand ctxt in + let op_to_rax = op_to (Reg Rax) in (* Move the value of op into rax *) + let op_to_rcx = op_to (Reg Rcx) in (* Move the value of op into rax *) + let dst = lookup ctxt.layout uid in + match i with + | Binop (bop, t, op1, op2) -> + let bin op = + (op_to_rax op1) :: + (op_to_rcx op2) :: + Asm.([ op, [~%Rcx; ~%Rax] + ; Movq, [~%Rax; dst] ]) + in + begin match bop with + | Ll.Add -> bin Addq + | Ll.Sub -> bin Subq + | Ll.Mul -> bin Imulq + | Ll.Shl -> bin Shlq + | Ll.Lshr -> bin Shrq + | Ll.Ashr -> bin Sarq + | Ll.And -> bin Andq + | Ll.Or -> bin Orq + | Ll.Xor -> bin Xorq + end + + (* Alloca instructions allocate an fresh stack slot and + move the address of the newly allocated storage into the + destination uid. *) + | Alloca (_t) -> Asm.([ Pushq, [~$0] + ; Movq, [~%Rsp; dst] ]) + + (* Load dereferences the pointer value stored in a local. + Global and constant pointers don't need indirection. *) + | Load (t, op) -> (op_to_rax op) :: Asm.([ Movq, [Ind2 Rax; ~%Rcx] + ; Movq, [~%Rcx; dst] ]) + + (* Store also needs to dereference the destination pointer if it's a global *) + | Store (_, src, (Id uid as dest)) -> + (op_to_rcx src) :: + (op_to_rax dest) :: Asm.([Movq, [~%Rcx; Ind2 Rax]]) + | Store (_, src, Gid gid) -> + (op_to_rax src) :: Asm.([Movq, [~%Rax; Ind3 (Lbl (Platform.mangle gid), Rip)]]) + | Store (_, _, _) -> failwith "store destination was not a local or global id" + + (* Treat LL i1 values as words, so zero-out the rest of the bits *) + | Icmp (cnd, _, op1, op2) -> (op_to_rax op1) :: + (op_to_rcx op2) :: + Asm.([ Cmpq, [~%Rcx; ~%Rax] + ; (Set (compile_cnd cnd)), [dst] + ; Andq, [imm_of_int 1; dst] ]) + + | Call(ret_ty, fop, args) -> + let code = compile_call ctxt fop args in + code @ + (match ret_ty with + | Void -> [] + | _ -> Asm.([Movq, [~%Rax; dst]])) + + (* Bitcast is effectively just a Mov at the assembly level *) + | Bitcast (_, op, _) -> (op_to_rax op) :: Asm.([Movq, [~%Rax; dst]]) + + (* Defer to the helper function to compute the pointer value *) + | Gep (t, op, path) -> + let code = compile_gep ctxt (t, op) path in + code @ Asm.([ Movq, [~%Rax; dst] ]) + + +(* compiling terminators --------------------------------------------------- *) + +(* prefix the function name [fn] to a label to ensure that the X86 labels are + globally unique . *) +let mk_lbl (fn:string) (l:string) = fn ^ "." ^ l + +(* Compile block terminators is not too difficult: + + - Ret should properly exit the function: freeing stack space, + restoring the value of %rbp, and putting the return value (if + any) in %rax. + + - Br should jump + + - Cbr branch should treat its operand as a boolean conditional +*) +let compile_terminator (fn:string) (ctxt:ctxt) (t:Ll.terminator) : ins list = + let epilogue = Asm.([ Movq, [~%Rbp; ~%Rsp] + ; Popq, [~%Rbp] + ; Retq, []]) + in match t with + | Ll.Ret (_, None) -> epilogue + | Ll.Ret (_, Some o) -> (compile_operand ctxt (Reg Rax) o) :: epilogue + | Ll.Br l -> Asm.([ Jmp, [~$$(mk_lbl fn l)] ]) + | Ll.Cbr (o, l1, l2) -> (compile_operand ctxt (Reg Rax) o) + :: Asm.([ Cmpq, [~$0; ~%Rax] + ; J (X86.Neq) , [~$$(mk_lbl fn l1)] + ; Jmp, [~$$(mk_lbl fn l2)] + ]) + +(* compiling blocks --------------------------------------------------------- *) + +let compile_block (fn:string) (ctxt:ctxt) (blk:Ll.block) : ins list = + let insns = List.map (compile_insn ctxt) blk.insns |> List.flatten in + let term = compile_terminator fn ctxt (snd blk.term) in + insns @ term + +let compile_lbl_block fn lbl ctxt blk : elem = + Asm.text (mk_lbl fn lbl) (compile_block fn ctxt blk) + + + +(* compile_fdecl ------------------------------------------------------------ *) +let rbp_offset n = Ind3 (Lit (Int64.of_int @@ 8 * n), Rbp) + +(* This helper function computes the location of the nth incoming + function argument: either in a register or relative to %rbp, + according to the calling conventions. You might find it useful for + compile_fdecl. + + [ NOTE: the first six arguments are numbered 0 .. 5 ] +*) +let arg_loc (n : int) : operand = + begin match arg_reg n with + | Some op -> op + | None -> rbp_offset (n-4) + end + +(* We suggest that you create a helper function that computes the + stack layout for a given function declaration. + + - each function argument should be copied into a stack slot + - in this (inefficient) compilation strategy, each local id + is also stored as a stack slot. + - see the discussion about locals + +*) +let stack_layout (args : uid list) ((block, lbled_blocks):cfg) : layout = + let lbled_block_isns = List.map (fun (_, blk) -> blk.insns) lbled_blocks in + let cfg_uids = List.map fst (block.insns @ (List.flatten lbled_block_isns)) in + List.mapi (fun i uid -> (uid, rbp_offset (-i - 1))) (args @ cfg_uids) + +(* The code for the entry-point of a function must do several things: + + - since our simple compiler maps local %uids to stack slots, + compiling the control-flow-graph body of an fdecl requires us to + compute the layout (see the discussion of locals and layout) + + - the function code should also comply with the calling + conventions, typically by moving arguments out of the parameter + registers (or stack slots) into local storage space. For our + simple compilation strategy, that local storage space should be + in the stack. (So the function parameters can also be accounted + for in the layout.) + + - the function entry code should allocate the stack storage needed + to hold all of the local stack slots. +*) +let compile_fdecl (tdecls:(tid * ty) list) (name:string) ({ f_ty; f_param; f_cfg }:fdecl) : prog = + let entry_name = (Platform.mangle name) in + let layout = stack_layout f_param f_cfg in + let init_arg_code = + (List.mapi (fun i uid -> Asm.([ Movq, [arg_loc i; ~%Rax] + ; Movq, [~%Rax; lookup layout uid] ]) ) + f_param) |> List.flatten + in + let ctxt = { tdecls; layout } in + let tmpsize = 8 * (List.length layout) in + + let prologue = Asm.([ Pushq, [~%Rbp] + ; Movq, [~%Rsp; ~%Rbp] + ; Subq, [~$tmpsize; ~%Rsp] ]) + @ init_arg_code + in + let (entry, body) = f_cfg in + let entry_insns = compile_block name ctxt entry in + (Asm.gtext entry_name @@ prologue @ entry_insns) :: + (List.map (fun (lbl, blk) -> compile_lbl_block name lbl ctxt blk) body) + + +(* compile_gdecl ------------------------------------------------------------ *) +(* Compile a global value into an X86 global data declaration and map + a global uid to its associated X86 label. +*) +let rec compile_ginit : ginit -> X86.data list = function + | GNull -> [Quad (Lit 0L)] + | GGid gid -> [Quad (Lbl (Platform.mangle gid))] + | GInt c -> [Quad (Lit c)] + | GString s -> [Asciz s] + | GArray gs | GStruct gs -> List.map compile_gdecl gs |> List.flatten + | GBitcast (t1,g,t2) -> compile_ginit g + +and compile_gdecl (_, g) = compile_ginit g + + +(* compile_prog ------------------------------------------------------------- *) +let compile_prog {tdecls; gdecls; fdecls} : X86.prog = + let g = fun (lbl, gdecl) -> Asm.data (Platform.mangle lbl) (compile_gdecl gdecl) in + let f = fun (name, fdecl) -> compile_fdecl tdecls name fdecl in + (List.map g gdecls) @ (List.map f fdecls |> List.flatten) diff --git a/hw4/driver.ml b/hw4/driver.ml new file mode 100644 index 0000000..f2cbe9c --- /dev/null +++ b/hw4/driver.ml @@ -0,0 +1,209 @@ +open Printf +open Platform + +(* configuration flags ------------------------------------------------------ *) +let interpret_ll = ref false (* run the ll interpreter? *) +let print_ll_flag = ref false (* print the generated ll code? *) +let print_x86_flag = ref false (* print the generated x86 code? *) +let print_ast_flag = ref false +let print_oat_flag = ref false +let clang = ref false (* use the clang backend? *) +let assemble = ref true (* assemble the .s to .o files? *) +let link = ref true (* combine multiple .o files executable? *) +let execute_x86 = ref false (* run the resulting x86 program? *) +let executable_filename = ref "a.out" + + +(* files processed during this run of the compiler *) +let files : string list ref = ref [] + +let link_files = ref [] +let add_link_file path = + link_files := path :: (!link_files) + + +(* terminal output ---------------------------------------------------------- *) + +let print_banner s = + let rec dashes n = if n = 0 then "" else "-"^(dashes (n-1)) in + printf "%s %s\n%!" (dashes (79 - (String.length s))) s + +let print_ll file ll_ast = + print_banner (file ^ ".ll"); + print_endline (Llutil.string_of_prog ll_ast) + +let print_x86 file asm_str = + print_banner file; + print_endline asm_str + +(* file i/o ----------------------------------------------------------------- *) + +let read_file (file:string) : string = + let lines = ref [] in + let channel = open_in file in + try while true; do + lines := input_line channel :: !lines + done; "" + with End_of_file -> + close_in channel; + String.concat "\n" (List.rev !lines) + +let write_file (file:string) (out:string) = + let channel = open_out file in + fprintf channel "%s" out; + close_out channel + + +(* running the generated code ----------------------------------------------- *) + +let interpret program args : string = + let result = Llinterp.interp_prog program args in + Llinterp.string_of_sval result + +let run_executable arg pr = + let cmd = sprintf "%s%s %s" dot_path pr arg in + sh cmd (fun _ i -> i) + +let run_executable_to_tmpfile arg pr tmp = + let cmd = sprintf "%s%s %d > %s 2>&1" dot_path pr arg tmp in + sh cmd ignore_error + + +let run_program (args:string) (executable:string) (tmp_out:string) : string = + let cmd = sprintf "%s%s %s > %s 2>&1" dot_path executable args tmp_out in + let _ = sh cmd ignore_error + in + read_file tmp_out + +let run_program_error (args:string) (executable:string) (tmp_out:string) : string = + let cmd = sprintf "timeout 60 %s%s %s > %s 2>&1" dot_path executable args tmp_out in + let result = sh cmd (fun _ i -> i) + in + (read_file tmp_out) ^ (string_of_int result) + + +(* compiler pipeline -------------------------------------------------------- *) + +(* These functions implement the compiler pipeline for a single ll file: + - parse the file + - compile to a .s file using either clang or backend.ml + - assemble the .s to a .o file using clang +*) +let parse_ll_file filename = + let program = read_file filename |> + Lexing.from_string |> + Llparser.prog Lllexer.token + in + program + + +let string_of_ll_ast path ll_ast = + let ll_str = Llutil.string_of_prog ll_ast in + let prog = Printf.sprintf "; generated from: %s\ntarget triple = \"%s\"\n%s\n" + path !Platform.target_triple ll_str in + prog + + +let process_ll_ast path file ll_ast = + let _ = if !print_ll_flag then print_ll file ll_ast in + + (* Optionally interpret it using the reference interpreter. *) + let _ = if !interpret_ll then + let result = interpret ll_ast [] in + Printf.printf "Interpreter Result: %s\n" result + in + + (* generated file names *) + let dot_s_file = Platform.gen_name !Platform.output_path file ".s" in + let dot_o_file = Platform.gen_name !Platform.output_path file ".o" in + + let _ = + if !clang then begin + Platform.verb "* compiling with clang"; + Platform.clang_compile path dot_s_file; + if !print_x86_flag then begin + print_banner dot_s_file; + Platform.sh (Printf.sprintf "cat %s" dot_s_file) Platform.raise_error + end + end else begin + Platform.verb "* compiling with Compiler Design backend"; + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + let _ = if !print_x86_flag then print_x86 dot_s_file asm_str in + let _ = write_file dot_s_file asm_str in + () + end + in + let _ = if !assemble then Platform.assemble dot_s_file dot_o_file in + let _ = add_link_file dot_o_file in + () + +let process_ll_file path file = + let _ = Platform.verb @@ Printf.sprintf "* processing file: %s\n" path in + let ll_ast = parse_ll_file path in + process_ll_ast path file ll_ast + +(* oat pipeline ------------------------------------------------------------- *) + +let parse_oat_file filename = + let lexbuf = read_file filename |> + Lexing.from_string + in + Lexer.reset_lexbuf filename 0 lexbuf; (* set the filename *) + try + Parser.prog Lexer.token lexbuf + with + | Parser.Error -> failwith @@ Printf.sprintf "Parse error at: %s" + (Range.string_of_range (Range.lex_range lexbuf)) + + +let print_oat file ll_ast = + print_banner (file ^ ".oat"); + Astlib.print_prog ll_ast + +let print_ast p = Printf.printf "\n%s\n\n" (Astlib.ml_string_of_prog p) + +let process_oat_ast path file oat_ast = + if !print_oat_flag then print_oat file oat_ast; + if !print_ast_flag then print_ast oat_ast; + let ll_ast = Frontend.cmp_prog oat_ast in + let dot_ll_file = Platform.gen_name !Platform.output_path file ".ll" in + Platform.verb @@ Printf.sprintf "writing file: %s\n" dot_ll_file; + let prog = string_of_ll_ast path ll_ast in + write_file dot_ll_file prog; + process_ll_ast dot_ll_file file ll_ast + +let process_oat_file path basename = + Platform.verb @@ Printf.sprintf "* processing file: %s\n" path; + let oat_ast = parse_oat_file path in + process_oat_ast path basename oat_ast + + +(* process files based on extension ----------------------------------------- *) + +let process_file path = + let basename, ext = Platform.path_to_basename_ext path in + begin match ext with + | "oat" -> process_oat_file path basename + | "ll" -> process_ll_file path basename + | "o" -> add_link_file path + | "c" -> add_link_file path + | _ -> failwith @@ Printf.sprintf "found unsupported file type: %s" path + end + +(* process each file separately and then link all of them together *) +let process_files files = + if (List.length files) > 0 then begin + + List.iter process_file files; + + ( if !assemble && !link then + Platform.link (List.rev !link_files@["runtime.c"]) !executable_filename ); + + ( if !assemble && !link && !execute_x86 then + let ret = run_executable "" !executable_filename in + print_banner @@ Printf.sprintf "Executing: %s" !executable_filename; + Printf.printf "* %s returned %d\n" !executable_filename ret ) + end + + diff --git a/hw4/frontend.ml b/hw4/frontend.ml new file mode 100644 index 0000000..05e81e0 --- /dev/null +++ b/hw4/frontend.ml @@ -0,0 +1,445 @@ +open Ll +open Llutil +open Ast + +(* instruction streams ------------------------------------------------------ *) + +(* As in the last project, we'll be working with a flattened representation + of LLVMlite programs to make emitting code easier. This version + additionally makes it possible to emit elements will be gathered up and + "hoisted" to specific parts of the constructed CFG + - G of gid * Ll.gdecl: allows you to output global definitions in the middle + of the instruction stream. You will find this useful for compiling string + literals + - E of uid * insn: allows you to emit an instruction that will be moved up + to the entry block of the current function. This will be useful for + compiling local variable declarations +*) + +type elt = + | L of Ll.lbl (* block labels *) + | I of uid * Ll.insn (* instruction *) + | T of Ll.terminator (* block terminators *) + | G of gid * Ll.gdecl (* hoisted globals (usually strings) *) + | E of uid * Ll.insn (* hoisted entry block instructions *) + +type stream = elt list +let ( >@ ) x y = y @ x +let ( >:: ) x y = y :: x +let lift : (uid * insn) list -> stream = List.rev_map (fun (x,i) -> I (x,i)) + +(* Build a CFG and collection of global variable definitions from a stream *) +let cfg_of_stream (code:stream) : Ll.cfg * (Ll.gid * Ll.gdecl) list = + let gs, einsns, insns, term_opt, blks = List.fold_left + (fun (gs, einsns, insns, term_opt, blks) e -> + match e with + | L l -> + begin match term_opt with + | None -> + if (List.length insns) = 0 then (gs, einsns, [], None, blks) + else failwith @@ Printf.sprintf "build_cfg: block labeled %s has\ + no terminator" l + | Some term -> + (gs, einsns, [], None, (l, {insns; term})::blks) + end + | T t -> (gs, einsns, [], Some (Llutil.Parsing.gensym "tmn", t), blks) + | I (uid,insn) -> (gs, einsns, (uid,insn)::insns, term_opt, blks) + | G (gid,gdecl) -> ((gid,gdecl)::gs, einsns, insns, term_opt, blks) + | E (uid,i) -> (gs, (uid, i)::einsns, insns, term_opt, blks) + ) ([], [], [], None, []) code + in + match term_opt with + | None -> failwith "build_cfg: entry block has no terminator" + | Some term -> + let insns = einsns @ insns in + ({insns; term}, blks), gs + + +(* compilation contexts ----------------------------------------------------- *) + +(* To compile OAT variables, we maintain a mapping of source identifiers to the + corresponding LLVMlite operands. Bindings are added for global OAT variables + and local variables that are in scope. *) + +module Ctxt = struct + + type t = (Ast.id * (Ll.ty * Ll.operand)) list + let empty = [] + + (* Add a binding to the context *) + let add (c:t) (id:id) (bnd:Ll.ty * Ll.operand) : t = (id,bnd)::c + + (* Lookup a binding in the context *) + let lookup (id:Ast.id) (c:t) : Ll.ty * Ll.operand = + List.assoc id c + + (* Lookup a function, fail otherwise *) + let lookup_function (id:Ast.id) (c:t) : Ll.ty * Ll.operand = + match List.assoc id c with + | Ptr (Fun (args, ret)), g -> Ptr (Fun (args, ret)), g + | _ -> failwith @@ id ^ " not bound to a function" + + let lookup_function_option (id:Ast.id) (c:t) : (Ll.ty * Ll.operand) option = + try Some (lookup_function id c) with _ -> None + +end + +(* compiling OAT types ------------------------------------------------------ *) + +(* The mapping of source types onto LLVMlite is straightforward. Booleans and ints + are represented as the corresponding integer types. OAT strings are + pointers to bytes (I8). Arrays are the most interesting type: they are + represented as pointers to structs where the first component is the number + of elements in the following array. + + The trickiest part of this project will be satisfying LLVM's rudimentary type + system. Recall that global arrays in LLVMlite need to be declared with their + length in the type to statically allocate the right amount of memory. The + global strings and arrays you emit will therefore have a more specific type + annotation than the output of cmp_rty. You will have to carefully bitcast + gids to satisfy the LLVM type checker. +*) + +let rec cmp_ty : Ast.ty -> Ll.ty = function + | Ast.TBool -> I1 + | Ast.TInt -> I64 + | Ast.TRef r -> Ptr (cmp_rty r) + +and cmp_rty : Ast.rty -> Ll.ty = function + | Ast.RString -> I8 + | Ast.RArray u -> Struct [I64; Array(0, cmp_ty u)] + | Ast.RFun (ts, t) -> + let args, ret = cmp_fty (ts, t) in + Fun (args, ret) + +and cmp_ret_ty : Ast.ret_ty -> Ll.ty = function + | Ast.RetVoid -> Void + | Ast.RetVal t -> cmp_ty t + +and cmp_fty (ts, r) : Ll.fty = + List.map cmp_ty ts, cmp_ret_ty r + + +let typ_of_binop : Ast.binop -> Ast.ty * Ast.ty * Ast.ty = function + | Add | Mul | Sub | Shl | Shr | Sar | IAnd | IOr -> (TInt, TInt, TInt) + | Eq | Neq | Lt | Lte | Gt | Gte -> (TInt, TInt, TBool) + | And | Or -> (TBool, TBool, TBool) + +let typ_of_unop : Ast.unop -> Ast.ty * Ast.ty = function + | Neg | Bitnot -> (TInt, TInt) + | Lognot -> (TBool, TBool) + +(* Compiler Invariants + + The LLVM IR type of a variable (whether global or local) that stores an Oat + array value (or any other reference type, like "string") will always be a + double pointer. In general, any Oat variable of Oat-type t will be + represented by an LLVM IR value of type Ptr (cmp_ty t). So the Oat variable + x : int will be represented by an LLVM IR value of type i64*, y : string will + be represented by a value of type i8**, and arr : int[] will be represented + by a value of type {i64, [0 x i64]}**. Whether the LLVM IR type is a + "single" or "double" pointer depends on whether t is a reference type. + + We can think of the compiler as paying careful attention to whether a piece + of Oat syntax denotes the "value" of an expression or a pointer to the + "storage space associated with it". This is the distinction between an + "expression" and the "left-hand-side" of an assignment statement. Compiling + an Oat variable identifier as an expression ("value") does the load, so + cmp_exp called on an Oat variable of type t returns (code that) generates a + LLVM IR value of type cmp_ty t. Compiling an identifier as a left-hand-side + does not do the load, so cmp_lhs called on an Oat variable of type t returns + and operand of type (cmp_ty t)*. Extending these invariants to account for + array accesses: the assignment e1[e2] = e3; treats e1[e2] as a + left-hand-side, so we compile it as follows: compile e1 as an expression to + obtain an array value (which is of pointer of type {i64, [0 x s]}* ). + compile e2 as an expression to obtain an operand of type i64, generate code + that uses getelementptr to compute the offset from the array value, which is + a pointer to the "storage space associated with e1[e2]". + + On the other hand, compiling e1[e2] as an expression (to obtain the value of + the array), we can simply compile e1[e2] as a left-hand-side and then do the + load. So cmp_exp and cmp_lhs are mutually recursive. [[Actually, as I am + writing this, I think it could make sense to factor the Oat grammar in this + way, which would make things clearer, I may do that for next time around.]] + + + Consider globals7.oat + + /--------------- globals7.oat ------------------ + global arr = int[] null; + + int foo() { + var x = new int[3]; + arr = x; + x[2] = 3; + return arr[2]; + } + /------------------------------------------------ + + The translation (given by cmp_ty) of the type int[] is {i64, [0 x i64}* so + the corresponding LLVM IR declaration will look like: + + @arr = global { i64, [0 x i64] }* null + + This means that the type of the LLVM IR identifier @arr is {i64, [0 x i64]}** + which is consistent with the type of a locally-declared array variable. + + The local variable x would be allocated and initialized by (something like) + the following code snippet. Here %_x7 is the LLVM IR uid containing the + pointer to the "storage space" for the Oat variable x. + + %_x7 = alloca { i64, [0 x i64] }* ;; (1) + %_raw_array5 = call i64* @oat_alloc_array(i64 3) ;; (2) + %_array6 = bitcast i64* %_raw_array5 to { i64, [0 x i64] }* ;; (3) + store { i64, [0 x i64]}* %_array6, { i64, [0 x i64] }** %_x7 ;; (4) + + (1) note that alloca uses cmp_ty (int[]) to find the type, so %_x7 has + the same type as @arr + + (2) @oat_alloc_array allocates len+1 i64's + + (3) we have to bitcast the result of @oat_alloc_array so we can store it + in %_x7 + + (4) stores the resulting array value (itself a pointer) into %_x7 + + The assignment arr = x; gets compiled to (something like): + + %_x8 = load { i64, [0 x i64] }*, { i64, [0 x i64] }** %_x7 ;; (5) + store {i64, [0 x i64] }* %_x8, { i64, [0 x i64] }** @arr ;; (6) + + (5) load the array value (a pointer) that is stored in the address pointed + to by %_x7 + + (6) store the array value (a pointer) into @arr + + The assignment x[2] = 3; gets compiled to (something like): + + %_x9 = load { i64, [0 x i64] }*, { i64, [0 x i64] }** %_x7 ;; (7) + %_index_ptr11 = getelementptr { i64, [0 x i64] }, + { i64, [0 x i64] }* %_x9, i32 0, i32 1, i32 2 ;; (8) + store i64 3, i64* %_index_ptr11 ;; (9) + + (7) as above, load the array value that is stored %_x7 + + (8) calculate the offset from the array using GEP + + (9) store 3 into the array + + Finally, return arr[2]; gets compiled to (something like) the following. + Note that the way arr is treated is identical to x. (Once we set up the + translation, there is no difference between Oat globals and locals, except + how their storage space is initially allocated.) + + %_arr12 = load { i64, [0 x i64] }*, { i64, [0 x i64] }** @arr ;; (10) + %_index_ptr14 = getelementptr { i64, [0 x i64] }, + { i64, [0 x i64] }* %_arr12, i32 0, i32 1, i32 2 ;; (11) + %_index15 = load i64, i64* %_index_ptr14 ;; (12) + ret i64 %_index15 + + (10) just like for %_x9, load the array value that is stored in @arr + + (11) calculate the array index offset + + (12) load the array value at the index + +*) + +(* Global initialized arrays: + + There is another wrinkle: To compile global initialized arrays like in the + globals4.oat, it is helpful to do a bitcast once at the global scope to + convert the "precise type" required by the LLVM initializer to the actual + translation type (which sets the array length to 0). So for globals4.oat, + the arr global would compile to (something like): + + @arr = global { i64, [0 x i64] }* bitcast + ({ i64, [4 x i64] }* @_global_arr5 to { i64, [0 x i64] }* ) + @_global_arr5 = global { i64, [4 x i64] } + { i64 4, [4 x i64] [ i64 1, i64 2, i64 3, i64 4 ] } + +*) + + + +(* Some useful helper functions *) + +(* Generate a fresh temporary identifier. Since OAT identifiers cannot begin + with an underscore, these should not clash with any source variables *) +let gensym : string -> string = + let c = ref 0 in + fun (s:string) -> incr c; Printf.sprintf "_%s%d" s (!c) + +(* Amount of space an Oat type takes when stored in the satck, in bytes. + Note that since structured values are manipulated by reference, all + Oat values take 8 bytes on the stack. +*) +let size_oat_ty (t : Ast.ty) = 8L + +(* Generate code to allocate a zero-initialized array of source type TRef (RArray t) of the + given size. Note "size" is an operand whose value can be computed at + runtime *) +let oat_alloc_array (t:Ast.ty) (size:Ll.operand) : Ll.ty * operand * stream = + let ans_id, arr_id = gensym "array", gensym "raw_array" in + let ans_ty = cmp_ty @@ TRef (RArray t) in + let arr_ty = Ptr I64 in + ans_ty, Id ans_id, lift + [ arr_id, Call(arr_ty, Gid "oat_alloc_array", [I64, size]) + ; ans_id, Bitcast(arr_ty, Id arr_id, ans_ty) ] + +(* Compiles an expression exp in context c, outputting the Ll operand that will + recieve the value of the expression, and the stream of instructions + implementing the expression. + + Tips: + - use the provided cmp_ty function! + + - string literals (CStr s) should be hoisted. You'll need to make sure + either that the resulting gid has type (Ptr I8), or, if the gid has type + [n x i8] (where n is the length of the string), convert the gid to a + (Ptr I8), e.g., by using getelementptr. + + - use the provided "oat_alloc_array" function to implement literal arrays + (CArr) and the (NewArr) expressions + +*) + +let rec cmp_exp (c:Ctxt.t) (exp:Ast.exp node) : Ll.ty * Ll.operand * stream = + failwith "cmp_exp not implemented" + +(* Compile a statement in context c with return typ rt. Return a new context, + possibly extended with new local bindings, and the instruction stream + implementing the statement. + + Left-hand-sides of assignment statements must either be OAT identifiers, + or an index into some arbitrary expression of array type. Otherwise, the + program is not well-formed and your compiler may throw an error. + + Tips: + - for local variable declarations, you will need to emit Allocas in the + entry block of the current function using the E() constructor. + + - don't forget to add a bindings to the context for local variable + declarations + + - you can avoid some work by translating For loops to the corresponding + While loop, building the AST and recursively calling cmp_stmt + + - you might find it helpful to reuse the code you wrote for the Call + expression to implement the SCall statement + + - compiling the left-hand-side of an assignment is almost exactly like + compiling the Id or Index expression. Instead of loading the resulting + pointer, you just need to store to it! + + *) + +let rec cmp_stmt (c:Ctxt.t) (rt:Ll.ty) (stmt:Ast.stmt node) : Ctxt.t * stream = + failwith "cmp_stmt not implemented" + +(* Compile a series of statements *) +and cmp_block (c:Ctxt.t) (rt:Ll.ty) (stmts:Ast.block) : Ctxt.t * stream = + List.fold_left (fun (c, code) s -> + let c, stmt_code = cmp_stmt c rt s in + c, code >@ stmt_code + ) (c,[]) stmts + + + +(* Adds each function identifer to the context at an + appropriately translated type. + + NOTE: The Gid of a function is just its source name +*) +let cmp_function_ctxt (c:Ctxt.t) (p:Ast.prog) : Ctxt.t = + List.fold_left (fun c -> function + | Ast.Gfdecl { elt={ frtyp; fname; args } } -> + let ft = TRef (RFun (List.map fst args, frtyp)) in + Ctxt.add c fname (cmp_ty ft, Gid fname) + | _ -> c + ) c p + +(* Populate a context with bindings for global variables + mapping OAT identifiers to LLVMlite gids and their types. + + Only a small subset of OAT expressions can be used as global initializers + in well-formed programs. (The constructors starting with C). +*) +let cmp_global_ctxt (c:Ctxt.t) (p:Ast.prog) : Ctxt.t = + failwith "cmp_global_ctxt not implemented" + +(* Compile a function declaration in global context c. Return the LLVMlite cfg + and a list of global declarations containing the string literals appearing + in the function. + + You will need to + 1. Allocate stack space for the function parameters using Alloca + 2. Store the function arguments in their corresponding alloca'd stack slot + 3. Extend the context with bindings for function variables + 4. Compile the body of the function using cmp_block + 5. Use cfg_of_stream to produce a LLVMlite cfg from + *) + +let cmp_fdecl (c:Ctxt.t) (f:Ast.fdecl node) : Ll.fdecl * (Ll.gid * Ll.gdecl) list = + failwith "cmp_fdecl not implemented" + +(* Compile a global initializer, returning the resulting LLVMlite global + declaration, and a list of additional global declarations. + + Tips: + - Only CNull, CBool, CInt, CStr, and CArr can appear as global initializers + in well-formed OAT programs. Your compiler may throw an error for the other + cases + + - OAT arrays are always handled via pointers. A global array of arrays will + be an array of pointers to arrays emitted as additional global declarations. +*) + +let rec cmp_gexp c (e:Ast.exp node) : Ll.gdecl * (Ll.gid * Ll.gdecl) list = + failwith "cmp_gexp not implemented" + +(* Oat internals function context ------------------------------------------- *) +let internals = [ + "oat_alloc_array", Ll.Fun ([I64], Ptr I64) + ] + +(* Oat builtin function context --------------------------------------------- *) +let builtins = + [ "array_of_string", cmp_rty @@ RFun ([TRef RString], RetVal (TRef(RArray TInt))) + ; "string_of_array", cmp_rty @@ RFun ([TRef(RArray TInt)], RetVal (TRef RString)) + ; "length_of_string", cmp_rty @@ RFun ([TRef RString], RetVal TInt) + ; "string_of_int", cmp_rty @@ RFun ([TInt], RetVal (TRef RString)) + ; "string_cat", cmp_rty @@ RFun ([TRef RString; TRef RString], RetVal (TRef RString)) + ; "print_string", cmp_rty @@ RFun ([TRef RString], RetVoid) + ; "print_int", cmp_rty @@ RFun ([TInt], RetVoid) + ; "print_bool", cmp_rty @@ RFun ([TBool], RetVoid) + ] + +(* Compile a OAT program to LLVMlite *) +let cmp_prog (p:Ast.prog) : Ll.prog = + (* add built-in functions to context *) + let init_ctxt = + List.fold_left (fun c (i, t) -> Ctxt.add c i (Ll.Ptr t, Gid i)) + Ctxt.empty builtins + in + let fc = cmp_function_ctxt init_ctxt p in + + (* build global variable context *) + let c = cmp_global_ctxt fc p in + + (* compile functions and global variables *) + let fdecls, gdecls = + List.fold_right (fun d (fs, gs) -> + match d with + | Ast.Gvdecl { elt=gd } -> + let ll_gd, gs' = cmp_gexp c gd.init in + (fs, (gd.name, ll_gd)::gs' @ gs) + | Ast.Gfdecl fd -> + let fdecl, gs' = cmp_fdecl c fd in + (fd.elt.fname,fdecl)::fs, gs' @ gs + ) p ([], []) + in + + (* gather external declarations *) + let edecls = internals @ builtins in + { tdecls = []; gdecls; fdecls; edecls } diff --git a/hw4/gradedtests.ml b/hw4/gradedtests.ml new file mode 100644 index 0000000..f1b3d84 --- /dev/null +++ b/hw4/gradedtests.ml @@ -0,0 +1,264 @@ +open Ast +open Astlib +open Assert +open Driver + +(* Do NOT modify this file -- we will overwrite it with our *) +(* own version when we test your project. *) + +(* These tests will be used to grade your assignment *) + +let assert_eq_ast (f: 'a -> 'a -> bool) (print : 'a -> string) (x: 'a) (y: unit -> 'a) : assertion = + fun () -> + let result = y () in + if f x result then () else + let msg = Printf.sprintf "EXPECTED: %s\nGOT: %s\n" (print x) (print result) in + failwith msg + +let parse_test parse (compare : 'a -> 'a -> bool) (printer : 'a -> string) (code : string) (ast : 'a) : assertion = + let lexbuf = Lexing.from_string code in + assert_eq_ast compare printer ast (fun () -> (parse Lexer.token lexbuf)) + +let exp_test code ast = parse_test Parser.exp_top eq_exp string_of_exp code ast + +let parse_consts = + [ ("parse consts test one", exp_test "bool[] null" (no_loc (CNull (RArray TBool)))) + ; ("parse consts test two", exp_test "42" (no_loc (CInt 42L))) + ; ("parse consts test three", exp_test "true" (no_loc (CBool true))) + ; ("parse consts test four", exp_test "false" (no_loc (CBool false))) + ; ("parse consts test five", exp_test "\"hello world\"" (no_loc (CStr "hello world"))) + ; ("parse consts test six", exp_test "new int[]{1, 2, 3}" (no_loc (CArr (TInt, [no_loc (CInt 1L); no_loc (CInt 2L); no_loc (CInt 3L)])))) + ] + +let parse_exp_tests = + [ ("parse exp test 1", exp_test "1" (no_loc (CInt 1L))) + ; ("parse exp test 2", exp_test "1+2" (no_loc (Bop (Add,no_loc (CInt 1L),no_loc (CInt 2L))))) + ; ("parse exp test 3", exp_test "1+2+3" (no_loc (Bop (Add,no_loc (Bop (Add,no_loc (CInt 1L),no_loc (CInt 2L))),no_loc (CInt 3L))))) + ; ("parse exp test 4", exp_test "1+2*3" (no_loc (Bop (Add,no_loc (CInt 1L),no_loc (Bop (Mul,no_loc (CInt 2L),no_loc (CInt 3L))))))) + ; ("parse exp test 5", exp_test "1+(2+3)" (no_loc (Bop (Add,no_loc (CInt 1L),no_loc (Bop (Add,no_loc (CInt 2L),no_loc (CInt 3L))))))) + ; ("parse exp test 6", exp_test "(1+2)*3" (no_loc (Bop (Mul,no_loc (Bop (Add,no_loc (CInt 1L),no_loc (CInt 2L))),no_loc (CInt 3L))))) + ; ("parse exp test 7", exp_test "1+2*3+4" (no_loc (Bop (Add,no_loc (Bop (Add,no_loc (CInt 1L),no_loc (Bop (Mul,no_loc (CInt 2L),no_loc (CInt 3L))))),no_loc (CInt 4L))))) + ; ("parse exp test 8", exp_test "1-2 == 3+4" (no_loc (Bop (Eq,no_loc (Bop (Sub,no_loc (CInt 1L),no_loc (CInt 2L))),no_loc (Bop (Add,no_loc (CInt 3L),no_loc (CInt 4L))))))) + ; ("parse exp test 9", exp_test "(1+2)*(3+4)" (no_loc (Bop (Mul,no_loc (Bop (Add,no_loc (CInt 1L),no_loc (CInt 2L))),no_loc (Bop (Add,no_loc (CInt 3L),no_loc (CInt 4L))))))) + ; ("parse exp test 10", exp_test "true & true | false" (no_loc (Bop (Or,no_loc (Bop (And,no_loc (CBool true),no_loc (CBool true))),no_loc (CBool false))))) + ; ("parse exp test 11", exp_test "true & (true | false)" (no_loc (Bop (And,no_loc (CBool true),no_loc (Bop (Or,no_loc (CBool true),no_loc (CBool false))))))) + ; ("parse exp test 12", exp_test "!(~5 == ~6) & -5+10 < 0" (no_loc (Bop (And,no_loc (Uop (Lognot, no_loc (Bop (Eq,no_loc (Uop (Bitnot, no_loc (CInt 5L))),no_loc (Uop (Bitnot, no_loc (CInt 6L))))))),no_loc (Bop (Lt,no_loc (Bop (Add,no_loc (Uop (Neg, no_loc (CInt 5L))),no_loc (CInt 10L))),no_loc (CInt 0L))))))) + ; ("parse exp test 13", exp_test "1+2 >> (3-4 >>> 7*8) << 9" (no_loc (Bop (Shl,no_loc (Bop (Shr,no_loc (Bop (Add,no_loc (CInt 1L),no_loc (CInt 2L))),no_loc (Bop (Sar,no_loc (Bop (Sub,no_loc (CInt 3L),no_loc (CInt 4L))),no_loc (Bop (Mul,no_loc (CInt 7L),no_loc (CInt 8L))))))),no_loc (CInt 9L))))) + ; ("parse exp test 14", exp_test "~5 >> 7 - 10 < 9 * -6-4 | !false" (no_loc (Bop (Or,no_loc (Bop (Lt,no_loc (Bop (Shr,no_loc (Uop (Bitnot, no_loc (CInt 5L))),no_loc (Bop (Sub,no_loc (CInt 7L),no_loc (CInt 10L))))),no_loc (Bop (Sub,no_loc (Bop (Mul,no_loc (CInt 9L),no_loc (Uop (Neg, no_loc (CInt 6L))))),no_loc (CInt 4L))))),no_loc (Uop (Lognot, no_loc (CBool false))))))) + ; ("parse exp test 15", exp_test "false == 2 >= 3 | true != 9 - 10 <= 4" (no_loc (Bop (Or,no_loc (Bop (Eq,no_loc (CBool false),no_loc (Bop (Gte,no_loc (CInt 2L),no_loc (CInt 3L))))),no_loc (Bop (Neq,no_loc (CBool true),no_loc (Bop (Lte,no_loc (Bop (Sub,no_loc (CInt 9L),no_loc (CInt 10L))),no_loc (CInt 4L))))))))) + ; ("parse exp test 16", exp_test "1-2*3+4 < 5 | 6+7-2 > 1 | true & false" (no_loc (Bop (Or,no_loc (Bop (Or,no_loc (Bop (Lt,no_loc (Bop (Add,no_loc (Bop (Sub,no_loc (CInt 1L),no_loc (Bop (Mul,no_loc (CInt 2L),no_loc (CInt 3L))))),no_loc (CInt 4L))),no_loc (CInt 5L))),no_loc (Bop (Gt,no_loc (Bop (Sub,no_loc (Bop (Add,no_loc (CInt 6L),no_loc (CInt 7L))),no_loc (CInt 2L))),no_loc (CInt 1L))))),no_loc (Bop (And,no_loc (CBool true),no_loc (CBool false))))))) + ; ("parse exp test 17", exp_test "true [&] false | false [|] true & true" (no_loc (Bop (IOr,no_loc (Bop (IAnd,no_loc (CBool true),no_loc (Bop (Or,no_loc (CBool false),no_loc (CBool false))))),no_loc (Bop (And,no_loc (CBool true),no_loc (CBool true))))))) + ; ("parse exp test 18", exp_test "true [|] false [&] true & true | false" (no_loc (Bop (IOr,no_loc (CBool true),no_loc (Bop (IAnd,no_loc (CBool false),no_loc (Bop (Or,no_loc (Bop (And,no_loc (CBool true),no_loc (CBool true))),no_loc (CBool false))))))))) + ; ("parse exp test 19", exp_test "new int[3]" (no_loc (NewArr (TInt,no_loc (CInt 3L))))) + ; ("parse exp test 20", exp_test "bar (x, \"compilerdesign\")" (no_loc (Call (no_loc (Id "bar"), [ no_loc (Id ("x")) ; no_loc (CStr "compilerdesign") ])))) + ; ("parse exp test 21", exp_test "new int[3]" (no_loc (NewArr (TInt,no_loc (CInt 3L))))) + ; ("parse exp test 22", exp_test "new int[][]{new int[]{10,11},new int[]{20,21},new int[]{30,31}}" (no_loc (CArr (TRef (RArray TInt), [ no_loc (CArr (TInt, [ no_loc (CInt 10L) ; no_loc (CInt 11L) ])) ; no_loc (CArr (TInt, [ no_loc (CInt 20L) ; no_loc (CInt 21L) ])) ; no_loc (CArr (TInt, [ no_loc (CInt 30L) ; no_loc (CInt 31L) ])) ])))) + ; ("parse exp test 23", exp_test "proc1 ()" (no_loc (Call (no_loc (Id "proc1"), [ ])))) + ; ("parse exp test 24", exp_test "array[0]" (no_loc (Index (no_loc (Id ("array")), no_loc (CInt 0L))))) + ; ("parse exp test 25", exp_test "i + y[1][1]" (no_loc (Bop (Add,no_loc (Id ("i")),no_loc (Index (no_loc (Index (no_loc (Id ("y")), no_loc (CInt 1L))), no_loc (CInt 1L))))))) + ; ("parse exp test 26", exp_test "-!~x[0][0]" (no_loc (Uop (Neg, no_loc (Uop (Lognot, no_loc (Uop (Bitnot, no_loc (Index (no_loc (Index (no_loc (Id ("x")), no_loc (CInt 0L))), no_loc (CInt 0L))))))))))) + ; ("parse exp test 27", exp_test "print_string (string_concat (str1, str2))" (no_loc (Call (no_loc (Id "print_string"), [ no_loc (Call (no_loc (Id "string_concat"), [ no_loc (Id ("str1")) ; no_loc (Id ("str2")) ])) ])))) + ] + +let stmt_test code ast = parse_test Parser.stmt_top eq_stmt string_of_stmt code ast + +let parse_stmt_tests = + [ ("parse stmt test 1", stmt_test "var n = 8;" (no_loc (Decl ("n", no_loc (CInt 8L) )))) + ; ("parse stmt test 2", stmt_test "var x=a[0];" (no_loc (Decl ("x", no_loc (Index (no_loc (Id ("a")), no_loc (CInt 0L))))))) + ; ("parse stmt test 3", stmt_test "return;" (no_loc (Ret (None)))) + ; ("parse stmt test 4", stmt_test "return x+y;" (no_loc (Ret (Some (no_loc (Bop (Add,no_loc (Id ("x")),no_loc (Id ("y"))))))))) + ; ("parse stmt test 5", stmt_test "a[j>>1]=v;" (no_loc (Assn (no_loc (Index (no_loc (Id ("a")), no_loc (Bop (Shr,no_loc (Id ("j")),no_loc (CInt 1L))))) ,no_loc (Id ("v")))))) + ; ("parse stmt test 6", stmt_test "foo(a,1,n);" (no_loc (SCall (no_loc (Id "foo"), [ no_loc (Id ("a")) ; no_loc (CInt 1L) ; no_loc (Id ("n")) ])))) + ; ("parse stmt test 7", stmt_test "a[i]=a[i>>1];" (no_loc (Assn (no_loc (Index (no_loc (Id ("a")), no_loc (Id ("i")))) , no_loc (Index (no_loc (Id ("a")), no_loc (Bop (Shr,no_loc (Id ("i")),no_loc (CInt 1L))))))))) + ; ("parse stmt test 8", stmt_test "var a = new int[8];" (no_loc (Decl ("a", no_loc (NewArr (TInt,no_loc (CInt 8L))))))) + ; ("parse stmt test 9", stmt_test "if((j1)&(a[i>>1]>1]; i=i>>1; }" (no_loc (While (no_loc (Bop (And,no_loc (Bop (Gt,no_loc (Id ("i")),no_loc (CInt 1L))),no_loc (Bop (Lt,no_loc (Index (no_loc (Id ("a")),no_loc (Bop (Shr, no_loc (Id ("i")), no_loc (CInt 1L))))),no_loc (Id ("v")))))),[ no_loc (Assn (no_loc (Index (no_loc (Id ("a")), no_loc (Id ("i")))), no_loc (Index (no_loc (Id ("a")), no_loc (Bop (Shr, no_loc (Id ("i")), no_loc (CInt 1L))))))) ; no_loc (Assn (no_loc (Id ("i")),no_loc (Bop (Shr,no_loc (Id ("i")),no_loc (CInt 1L))))) ])))) + ; ("parse stmt test 12", stmt_test "for (; i > 0; i=i-1;) { for (var j = 1; j <= i; j=j+1;) { if (numbers[j-1] > numbers[i]) { temp = numbers[j-1]; numbers[j-1] = numbers[i]; numbers[i] = temp; } } }" (no_loc (For ([ ],Some (no_loc (Bop (Gt,no_loc (Id ("i")),no_loc (CInt 0L)))),Some (no_loc (Assn (no_loc (Id ("i")),no_loc (Bop (Sub,no_loc (Id ("i")),no_loc (CInt 1L)))))),[ no_loc (For ([ "j", no_loc (CInt 1L) ],Some (no_loc (Bop (Lte,no_loc (Id ("j")),no_loc (Id ("i"))))),Some (no_loc (Assn (no_loc (Id ("j")),no_loc (Bop (Add,no_loc (Id ("j")),no_loc (CInt 1L)))))),[ no_loc (If (no_loc (Bop (Gt,no_loc (Index (no_loc (Id ("numbers")), no_loc (Bop (Sub, no_loc (Id ("j")), no_loc (CInt 1L))))),no_loc (Index (no_loc (Id ("numbers")), no_loc (Id ("i")))))),[ no_loc (Assn (no_loc (Id ("temp")), no_loc (Index (no_loc (Id ("numbers")), no_loc (Bop (Sub,no_loc (Id ("j")),no_loc (CInt 1L))))))) ; no_loc (Assn (no_loc (Index (no_loc (Id ("numbers")), no_loc (Bop (Sub,no_loc (Id ("j")),no_loc (CInt 1L))))) ,no_loc (Index (no_loc (Id ("numbers")), no_loc (Id ("i")))))) ; no_loc (Assn (no_loc (Index (no_loc (Id ("numbers")), no_loc (Id ("i")))) ,no_loc (Id ("temp")))) ],[ ])) ])) ])))) + ; ("parse stmt test 13", stmt_test "for (var i = 0, var j = 0; ;) { }" (no_loc (For ([ "i", no_loc (CInt 0L) ; "j", no_loc (CInt 0L) ], None, None, [ ])))) + ] + +let parse_file_test filepath ast = + assert_eq_ast Astlib.eq_prog string_of_prog ast (fun () -> Driver.parse_oat_file filepath) + +let parse_prog_tests = + [ ("parse prog test 1", parse_file_test "oatprograms/easy_p1.oat" Progasts.easy_p1_ast) + ; ("parse prog test 2", parse_file_test "oatprograms/easy_p2.oat" Progasts.easy_p2_ast) + ; ("parse prog test 3", parse_file_test "oatprograms/easy_p3.oat" Progasts.easy_p3_ast) + ; ("parse prog test 4", parse_file_test "oatprograms/easy_p4.oat" Progasts.easy_p4_ast) + ; ("parse prog test 5", parse_file_test "oatprograms/easy_p5.oat" Progasts.easy_p5_ast) + ; ("parse prog test 6", parse_file_test "oatprograms/easy_p6.oat" Progasts.easy_p6_ast) + ; ("parse prog test 7", parse_file_test "oatprograms/easy_p7.oat" Progasts.easy_p7_ast) + ] + +let parse_tests = parse_consts + @ parse_exp_tests + @ parse_stmt_tests + @ parse_prog_tests + +let oat_file_test path args = + let () = Platform.verb @@ Printf.sprintf "** Processing: %s\n" path in + + let output_path = !Platform.output_path in + let dot_ll_file = Platform.gen_name output_path "test" ".ll" in + let exec_file = Platform.gen_name output_path "exec" "" in + let tmp_file = Platform.gen_name output_path "tmp" ".txt" in + + let oat_ast = parse_oat_file path in + let ll_ast = Frontend.cmp_prog oat_ast in + let ll_str = Driver.string_of_ll_ast path ll_ast in + let () = write_file dot_ll_file ll_str in + let () = Platform.link (dot_ll_file::["runtime.c"]) exec_file in + + let result = Driver.run_program_error args exec_file tmp_file in + (* let () = Platform.sh (Printf.sprintf "rm -f %s %s %s" dot_ll_file exec_file tmp_file) Platform.ignore_error in *) + let () = Platform.verb @@ Printf.sprintf "** Executable output:\n%s\n" result in + result + +let executed_oat_file tests = + List.map (fun (path, args, ans) -> + (path ^ " args: " ^ args), assert_eqfs (fun () -> oat_file_test path args) ans) + tests + +let easiest_tests = [ + ("oatprograms/easyrun1.oat", "", "17"); + ("oatprograms/easyrun2.oat", "", "35"); + ("oatprograms/easyrun3.oat", "", "73"); + ("oatprograms/easyrun4.oat", "", "6"); + ("oatprograms/easyrun5.oat", "", "212"); + ("oatprograms/easyrun6.oat", "", "9"); + ("oatprograms/easyrun7.oat", "", "23"); + ("oatprograms/easyrun8.oat", "", "96"); + ("oatprograms/easyrun9.oat", "", "236"); + ("oatprograms/easyrun10.oat", "", "254"); +] + +let globals_tests = [ + ("oatprograms/globals1.oat", "", "42"); + ("oatprograms/globals2.oat", "", "17"); + ("oatprograms/globals3.oat", "", "17"); + ("oatprograms/globals4.oat", "", "5"); + ("oatprograms/globals5.oat", "", "17"); + ("oatprograms/globals6.oat", "", "15"); + ("oatprograms/globals7.oat", "", "3"); +] + +let path_tests = [ + ("oatprograms/path1.oat", "", "17"); + ("oatprograms/path2.oat", "", "35"); + ("oatprograms/path3.oat", "", "3"); + ("oatprograms/arrayargs.oat", "", "17"); + ("oatprograms/arrayargs1.oat", "", "17"); + ("oatprograms/arrayargs2.oat", "", "17"); + ("oatprograms/arrayargs3.oat", "", "34"); +] + +let easy_tests = [ + ("oatprograms/run13.oat", "", "1"); + ("oatprograms/run21.oat", "", "99"); + ("oatprograms/run26.oat", "", "0"); + ("oatprograms/run27.oat", "", "99"); + ("oatprograms/run28.oat", "", "18"); + ("oatprograms/run29.oat", "", "1"); + ("oatprograms/run30.oat", "", "9"); + ("oatprograms/run31.oat", "", "9"); + ("oatprograms/run32.oat", "", "33"); + ("oatprograms/run33.oat", "", "1"); + ("oatprograms/run34.oat", "", "66"); + ("oatprograms/run35.oat", "", "66"); + ("oatprograms/run36.oat", "", "0"); + ("oatprograms/run37.oat", "", "2"); + ("oatprograms/run38.oat", "", "31"); + ("oatprograms/run39.oat", "a", "2"); + ("oatprograms/run40.oat", "", "8"); + ("oatprograms/run41.oat", "", "3"); + ("oatprograms/run42.oat", "", "2"); + ("oatprograms/run49.oat", "", "abc0"); + ("oatprograms/run50.oat", "", "abcde0"); + ("oatprograms/run60.oat", "", "42"); + ("oatprograms/run61.oat", "", "420"); +] + +let medium_tests = [ + ("oatprograms/fact.oat", "", "1200"); + ("oatprograms/run1.oat", "", "153"); + ("oatprograms/run2.oat", "", "6"); + ("oatprograms/run3.oat", "", "2"); + ("oatprograms/run4.oat", "", "42"); + ("oatprograms/run5.oat", "", "4"); + ("oatprograms/run6.oat", "", "1"); + ("oatprograms/run7.oat", "", "20"); + ("oatprograms/run8.oat", "", "2"); + ("oatprograms/run9.oat", "", "4"); + ("oatprograms/run10.oat", "", "5"); + ("oatprograms/run11.oat", "", "7"); + ("oatprograms/run14.oat", "", "16"); + ("oatprograms/run15.oat", "", "19"); + ("oatprograms/run16.oat", "", "13"); + ("oatprograms/run18.oat", "", "231"); + ("oatprograms/run19.oat", "", "231"); + ("oatprograms/run20.oat", "", "19"); + ("oatprograms/run22.oat", "", "abc0"); + ("oatprograms/run23.oat", "", "1230"); + ("oatprograms/run24.oat", "", "0"); + ("oatprograms/run25.oat", "", "nnn0"); + ("oatprograms/run43.oat", "", "42"); + ("oatprograms/run44.oat", "", "hello0"); + ("oatprograms/run45.oat", "", "420"); + ("oatprograms/run46.oat", "", "420"); + ("oatprograms/run47.oat", "", "3"); + ("oatprograms/run48.oat", "", "11"); + ("oatprograms/run53.oat", "", "nnn0"); + ("oatprograms/lib4.oat", "", "53220"); + ("oatprograms/lib5.oat", "", "20"); + ("oatprograms/lib6.oat", "", "56553"); + ("oatprograms/lib7.oat", "", "53"); + ("oatprograms/lib8.oat", "", "Hello world!0"); + ("oatprograms/lib9.oat", "a b c d", "abcd5"); + ("oatprograms/lib11.oat", "", "45"); + ("oatprograms/lib14.oat", "", "~}|{zyxwvu0"); + ("oatprograms/lib15.oat", "123456789", "456780"); +] + +let hard_tests = [ +("oatprograms/fac.oat", "", "120"); +("oatprograms/qsort.oat", "", "kpyf{shomfhkmopsy{255"); +("oatprograms/bsort.oat", "", "y}xotnuw notuwxy}255"); +("oatprograms/msort.oat", "", "~}|{zyxwvu uvwxyz{|}~ 0"); +("oatprograms/msort2.oat", "", "~}|{zyxwvu uvwxyz{|}~ 0"); +("oatprograms/selectionsort.oat", "", "01253065992000"); +("oatprograms/matrixmult.oat", "", "19 16 13 23 \t5 6 7 6 \t19 16 13 23 \t5 6 7 6 \t0"); +] + +let old_student_tests = [ + ("oatprograms/binary_search.oat", "", "Correct!0") + ; ("oatprograms/xor_shift.oat", "", "838867572\n22817190600") + ; ("oatprograms/sieve.oat", "", "25") + ; ("oatprograms/count_sort.oat", "", "AFHZAAEYC\nAAACEFHYZ0") + ; ("oatprograms/fibo.oat", "", "0") + ; ("oatprograms/heap.oat", "", "1") + ; ("oatprograms/binary_gcd.oat", "", "3") + ; ("oatprograms/lfsr.oat", "", "TFTF FFTT0") + ; ("oatprograms/gnomesort.oat", "", "01253065992000") + ; ("oatprograms/josh_joyce_test.oat", "", "0") + ; ("oatprograms/gcd.oat", "", "16") + ; ("oatprograms/life.oat", "", "00101001100101000") + ; ("oatprograms/lcs.oat", "", "OAT0") + ; ("oatprograms/insertion_sort.oat", "", "42") + ; ("oatprograms/maxsubsequence.oat", "", "107") +] + +let student_tests = [] + +let tests : suite = + [ GradedTest("parse tests", 15, parse_tests); + GradedTest("easiest tests", 15, executed_oat_file easiest_tests); + GradedTest("globals tests", 10, executed_oat_file globals_tests); + GradedTest("path tests", 10, executed_oat_file path_tests); + GradedTest("easy tests", 10, executed_oat_file easy_tests); + GradedTest("medium tests", 10, executed_oat_file medium_tests); + GradedTest("hard tests", 10, executed_oat_file (hard_tests @ old_student_tests)); + GradedTest("hidden tests", 20, executed_oat_file student_tests); + ] + +let graded_tests : suite = tests diff --git a/hw4/lexer.mll b/hw4/lexer.mll new file mode 100644 index 0000000..d864900 --- /dev/null +++ b/hw4/lexer.mll @@ -0,0 +1,199 @@ +{ + open Lexing + open Parser + open Range + + exception Lexer_error of Range.t * string + + let reset_lexbuf (filename:string) (lnum:int) lexbuf : unit = + lexbuf.lex_curr_p <- { + pos_fname = filename; + pos_cnum = 0; + pos_bol = 0; + pos_lnum = lnum; + } + + let newline lexbuf = + lexbuf.lex_curr_p <- { (lexeme_end_p lexbuf) with + pos_lnum = (lexeme_end_p lexbuf).pos_lnum + 1; + pos_bol = (lexeme_end lexbuf) } + + (* Boilerplate to define exceptional cases in the lexer. *) + let unexpected_char lexbuf (c:char) : 'a = + raise (Lexer_error (Range.lex_range lexbuf, + Printf.sprintf "Unexpected character: '%c'" c)) + + (* Lexing reserved words *) + let reserved_words = [ + (* Keywords *) + ("null", NULL); + ("void", TVOID); + ("int", TINT); + ("string", TSTRING); + ("else", ELSE); + ("if", IF); + ("while", WHILE); + ("return", RETURN); + ("var", VAR); + ("global", GLOBAL); + + (* Symbols *) + ( ";", SEMI); + ( ",", COMMA); + ( "{", LBRACE); + ( "}", RBRACE); + ( "+", PLUS); + ( "-", DASH); + ( "*", STAR); + ( "=", EQ); + ( "==", EQEQ); + ( "!", BANG); + ( "~", TILDE); + ( "(", LPAREN); + ( ")", RPAREN); + ( "[", LBRACKET); + ( "]", RBRACKET); + ] + +let (symbol_table : (string, Parser.token) Hashtbl.t) = Hashtbl.create 1024 + let _ = + List.iter (fun (str,t) -> Hashtbl.add symbol_table str t) reserved_words + + let create_token lexbuf = + let str = lexeme lexbuf in + try (Hashtbl.find symbol_table str) + with _ -> IDENT str + + (* Lexing comments and strings *) + let string_buffer = ref (Bytes.create 2048) + let string_end = ref 0 + let start_lex = ref (Range.start_of_range Range.norange) + + let start_pos_of_lexbuf lexbuf : pos = + (Range.pos_of_lexpos (lexeme_start_p lexbuf)) + + let lex_long_range lexbuf : Range.t = + let end_p = lexeme_end_p lexbuf in + mk_range end_p.pos_fname (!start_lex) (pos_of_lexpos end_p) + + let reset_str () = string_end := 0 + + let add_str ch = + let x = !string_end in + let buffer = !string_buffer + in + if x = Bytes.length buffer then + begin + let new_buffer = Bytes.create (x*2) in + Bytes.blit buffer 0 new_buffer 0 x; + Bytes.set new_buffer x ch; + string_buffer := new_buffer; + string_end := x+1 + end + else + begin + Bytes.set buffer x ch; + string_end := x+1 + end + + let get_str () = Bytes.sub_string (!string_buffer) 0 (!string_end) + + (* Lexing directives *) + let lnum = ref 1 +} + +(* Declare your aliases (let foo = regex) and rules here. *) +let newline = '\n' | ('\r' '\n') | '\r' +let lowercase = ['a'-'z'] +let uppercase = ['A'-'Z'] +let character = uppercase | lowercase +let whitespace = ['\t' ' '] +let digit = ['0'-'9'] +let hexdigit = ['0'-'9'] | ['a'-'f'] | ['A'-'F'] + +rule token = parse + | eof { EOF } + + | "/*" { start_lex := start_pos_of_lexbuf lexbuf; comments 0 lexbuf } + | '"' { reset_str(); start_lex := start_pos_of_lexbuf lexbuf; string false lexbuf } + | '#' { let p = lexeme_start_p lexbuf in + if p.pos_cnum - p.pos_bol = 0 then directive 0 lexbuf + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "# can only be the 1st char in a line.")) } + + | lowercase (digit | character | '_')* { create_token lexbuf } + | digit+ | "0x" hexdigit+ { INT (Int64.of_string (lexeme lexbuf)) } + | whitespace+ { token lexbuf } + | newline { newline lexbuf; token lexbuf } + + | ';' | ',' | '{' | '}' | '+' | '-' | '*' | '=' | "==" + | "!=" | '!' | '~' | '(' | ')' | '[' | ']' + { create_token lexbuf } + + | _ as c { unexpected_char lexbuf c } + +and directive state = parse + | whitespace+ { directive state lexbuf } + | digit+ { if state = 0 then + (lnum := int_of_string (lexeme lexbuf); + directive 1 lexbuf) + else if state = 2 then directive 3 lexbuf + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + | '"' { if state = 1 then + begin + reset_str(); + start_lex := start_pos_of_lexbuf lexbuf; + string true lexbuf + end + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) + } + | newline { if state = 2 || state = 3 then + begin + reset_lexbuf (get_str()) !lnum lexbuf; + token lexbuf + end + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + | _ { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + +and comments level = parse + | "*/" { if level = 0 then token lexbuf + else comments (level-1) lexbuf } + | "/*" { comments (level+1) lexbuf} + | [^ '\n'] { comments level lexbuf } + | "\n" { newline lexbuf; comments level lexbuf } + | eof { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "comments are not closed")) } + +and string in_directive = parse + | '"' { if in_directive = false then + STRING (get_str()) + else directive 2 lexbuf } + | '\\' { add_str(escaped lexbuf); string in_directive lexbuf } + | '\n' { add_str '\n'; newline lexbuf; string in_directive lexbuf } + | eof { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "String is not terminated")) } + | _ { add_str (Lexing.lexeme_char lexbuf 0); string in_directive lexbuf } + +and escaped = parse + | 'n' { '\n' } + | 't' { '\t' } + | '\\' { '\\' } + | '"' { '\034' } + | '\'' { '\'' } + | ['0'-'9']['0'-'9']['0'-'9'] + { + let x = int_of_string(lexeme lexbuf) in + if x > 255 then + raise (Lexer_error (lex_long_range lexbuf, + (Printf.sprintf "%s is an illegal escaped character constant" (lexeme lexbuf)))) + else + Char.chr x + } + | [^ '"' '\\' 't' 'n' '\''] + { raise (Lexer_error (lex_long_range lexbuf, + (Printf.sprintf "%s is an illegal escaped character constant" (lexeme lexbuf) ))) } + diff --git a/hw4/ll/ll-original.ml b/hw4/ll/ll-original.ml new file mode 100644 index 0000000..c0acb18 --- /dev/null +++ b/hw4/ll/ll-original.ml @@ -0,0 +1,81 @@ +(* LLVMlite: A simplified subset of the LLVM IR *) + +type uid = string (* Local identifiers *) +type gid = string (* Global identifiers *) +type tid = string (* Named types *) +type lbl = string (* Labels *) + +(* LLVM IR types *) +type ty = + | Void (* mix of unit/bottom from C *) + | I1 | I8 | I64 (* integer types *) + | Ptr of ty (* t* *) + | Struct of ty list (* { t1, t2, ... , tn } *) + | Array of int * ty (* [ NNN x t ] *) + | Fun of fty (* t1, ..., tn -> tr *) + | Namedt of tid (* named type aliases *) + +(* Function type: argument types and return type *) +and fty = ty list * ty + +(* Syntactic Values *) +type operand = + | Null (* null pointer *) + | Const of int64 (* integer constant *) + | Gid of gid (* A global identifier *) + | Id of uid (* A local identifier *) + +(* Type-annotated operands *) + +(* Binary operations *) +type bop = Add | Sub | Mul | Shl | Lshr | Ashr | And | Or | Xor + +(* Comparison Operators *) +type cnd = Eq | Ne | Slt | Sle | Sgt | Sge + +(* Instructions *) +type insn = + | Binop of bop * ty * operand * operand (* bop ty %o1, %o2 *) + | Alloca of ty (* alloca ty *) + | Load of ty * operand (* load ty %u *) + | Store of ty * operand * operand (* store ty %t, ty* %u *) + | Icmp of cnd * ty * operand * operand (* icmp %s ty %s, %s *) + | Call of ty * operand * (ty * operand) list (* fn(%1, %2, ...) *) + | Bitcast of ty * operand * ty (* bitcast ty1 %u to ty2 *) + | Gep of ty * operand * operand list (* getelementptr ty* %u, i64 %vi, ... *) + +(* Block terminators *) +type terminator = + | Ret of ty * operand option (* ret i64 %s *) + | Br of lbl (* br label %lbl *) + | Cbr of operand * lbl * lbl (* br i1 %s, label %l1, label %l2 *) + +(* Basic blocks *) +type block = { insns: (uid * insn) list; terminator: uid * terminator } + +(* Control Flow Graph: a pair of an entry block and a set labeled blocks *) +type cfg = block * (lbl * block) list + +(* Function declarations *) +type fdecl = { fty: fty; param: uid list; cfg: cfg } + +(* Initializers for global data *) +type ginit = + | GNull (* null literal *) + | GGid of gid (* reference another global *) + | GInt of int64 (* global integer value *) + | GString of string (* constant global string *) + | GArray of gdecl list (* global array *) + | GStruct of gdecl list (* global struct *) + +(* Global declaration *) +and gdecl = ty * ginit + +(* LLVMlite programs *) +type prog = + { tdecls: (tid * ty) list (* named types *) + ; gdecls: (gid * gdecl) list (* global data *) + ; fdecls: (gid * fdecl) list (* code *) + ; edecls: (gid * ty) list (* external declarations *) + } + diff --git a/hw4/ll/ll.ml b/hw4/ll/ll.ml new file mode 100644 index 0000000..9cd2ff8 --- /dev/null +++ b/hw4/ll/ll.ml @@ -0,0 +1,98 @@ +(* LLVMlite: A simplified subset of LLVM IR *) + +(* Local identifiers *) +type uid = string + +(* Global identifiers *) +type gid = string + +(* Named types *) +type tid = string + +(* Labels *) +type lbl = string + +(* LLVM types *) +type ty = +| Void +| I1 +| I8 +| I64 +| Ptr of ty +| Struct of ty list +| Array of int * ty +| Fun of ty list * ty +| Namedt of tid + +(* Function type: argument types and return type *) +type fty = ty list * ty + +(* Syntactic Values *) +type operand = +| Null +| Const of int64 +| Gid of gid +| Id of uid + +(* Binary i64 Operations *) +type bop = +| Add +| Sub +| Mul +| Shl +| Lshr +| Ashr +| And +| Or +| Xor + +(* Comparison Operators *) +type cnd = +| Eq +| Ne +| Slt +| Sle +| Sgt +| Sge + +(* Instructions *) +type insn = +| Binop of bop * ty * operand * operand +| Alloca of ty +| Load of ty * operand +| Store of ty * operand * operand +| Icmp of cnd * ty * operand * operand +| Call of ty * operand * (ty * operand) list +| Bitcast of ty * operand * ty +| Gep of ty * operand * operand list + +type terminator = +| Ret of ty * operand option +| Br of lbl +| Cbr of operand * lbl * lbl + +(* Basic Blocks *) +type block = { insns : (uid * insn) list; term : (uid * terminator) } + +(* Control Flow Graphs: entry and labeled blocks *) +type cfg = block * (lbl * block) list + +(* Function Declarations *) +type fdecl = { f_ty : fty; f_param : uid list; f_cfg : cfg } + +(* Global Data Initializers *) +type ginit = +| GNull +| GGid of gid +| GInt of int64 +| GString of string +| GArray of (ty * ginit) list +| GStruct of (ty * ginit) list +| GBitcast of ty * ginit * ty + +(* Global Declarations *) +type gdecl = ty * ginit + +(* LLVMlite Programs *) +type prog = { tdecls : (tid * ty) list; gdecls : (gid * gdecl) list; + fdecls : (gid * fdecl) list; edecls : (gid * ty) list } diff --git a/hw4/ll/llinterp.ml b/hw4/ll/llinterp.ml new file mode 100644 index 0000000..2e2388b --- /dev/null +++ b/hw4/ll/llinterp.ml @@ -0,0 +1,470 @@ +open Ll +open Llutil + +(* LLVMlite interpreter *) + +type mid = int (* memory block id *) +type fid = int (* stack frame id *) +type idx = int (* index *) + +(* Memory block identifier *) +type bid = GlobId of gid + | HeapId of mid + | StckId of fid + | NullId + +(* Pointers are tagged with a description of the block they reference + offsets are represented as paths into memory values *) +type ptr = ty * bid * idx list + +(* "Simple" or stack values *) +type sval = + | VUndef + | VInt of int64 + | VPtr of ptr + +(* Memory values *) +type mtree = MWord of sval + | MStr of string + | MNode of mval +and mval = mtree list + +(* Locals *) +type locals = uid -> sval + +(* The memory state *) +type config = + { globals : (gid * mval) list + ; heap : (mid * mval) list + ; stack : (fid * mval) list + } + +(* Create memory value for global declaration *) +let mval_of_gdecl (gd:gdecl) : mval = + let rec mtree_of_gdecl : gdecl -> mtree = function + | ty, GNull -> MWord (VPtr (ty, NullId, [0])) + | ty, GGid g -> MWord (VPtr (ty, GlobId g, [0])) + | _, GBitcast (t1, v,t2) -> mtree_of_gdecl (t1, v) + | _, GInt i -> MWord (VInt i) + | _, GString s -> MStr s + | _, GArray gs + | _, GStruct gs -> MNode (List.map mtree_of_gdecl gs) + in [mtree_of_gdecl gd] + +(* Create fully undefined memory value for a type *) +let mval_of_ty (nt:tid -> ty) (t:ty) : mval = + let rec mtree_of_ty : ty -> mtree = function + | I1 | I8 | I64 | Ptr _ -> MWord VUndef + | Array (n, I8) -> MStr (String.make n '\x00') + | Array (n, t) -> MNode Array.(make n (MWord VUndef) |> to_list) + | Struct ts -> MNode (List.map mtree_of_ty ts) + | Fun _ | Void -> failwith "mval_of_ty: mval for bad type" + | Namedt id -> mtree_of_ty (nt id) + in [mtree_of_ty t] + + +(* Printing machine states *) +let mapcat s f l = String.concat s @@ List.map f l +let prefix p f a = p ^ f a +let ( ^. ) s t = if s = "" || t = "" then "" else s ^ t +let pp = Printf.sprintf + +let string_of_bid = function + | GlobId gid -> "@" ^ gid + | HeapId mid -> "M" ^ (string_of_int mid) + | StckId fid -> "S" ^ (string_of_int fid) + | NullId -> "null" + +let string_of_ptr (t, b, i) = + pp "%s %s %s" (string_of_ty t) (string_of_bid b) + (mapcat ", " string_of_int i) + +let string_of_sval (sv:sval) : string = + match sv with + | VUndef -> "undef" + | VInt x -> Int64.to_string x + | VPtr p -> string_of_ptr p + +let rec string_of_mval (mv:mval) : string = + "[" ^ (mapcat " " string_of_mtree mv) ^ "]" + +and string_of_mtree = function + | MWord sv -> string_of_sval sv + | MStr s -> "\"" ^ s ^ "\"" + | MNode m -> string_of_mval m + + +(* Varieties of undefined behavior. Can be raised by load/store *) +exception OOBIndexDeref (* mem access not in bounds of an array *) +exception NullPtrDeref (* deref Null *) +exception UndefPtrDeref (* deref Undef pointer (from bad GEP) *) +exception IncompatTagDeref (* deref pointer at wrong type (bad bitcast) *) +exception UndefMemDeref (* read uninitialized memory *) +exception UninitMemLoad (* uninitialized memory load *) +exception UseAfterFree (* deref freed stack/heap memory *) + + +(* Arithmetic operations are all signed 64bit 2s compliment (mod In64.max_int) *) +let interp_bop (b:bop) (v1:sval) (v2:sval) : sval = + let i, j = match v1, v2 with + | VInt i, VInt j -> i, j + | _ -> invalid_arg "interp_bop" + in + let open Int64 in + let f = match b with + | Add -> add | Sub -> sub | Mul -> mul + | And -> logand | Or -> logor | Xor -> logxor + | Shl -> fun i j -> shift_left i @@ to_int j + | Lshr -> fun i j -> shift_right_logical i @@ to_int j + | Ashr -> fun i j -> shift_right i @@ to_int j + in VInt (f i j) + +let interp_cnd (c:cnd) (v1:sval) (v2:sval) = + let f = match c with + | Eq -> (=) | Ne -> (<>) | Slt -> (<) + | Sle -> (<=) | Sgt -> (>) | Sge -> (>=) + in + match v1, v2, c with + | VPtr (_,b1,i1), VPtr (_,b2,i2), Eq + | VPtr (_,b1,i1), VPtr (_,b2,i2), Ne -> + VInt (if f (b1,i1) (b2,i2) then 1L else 0L) + | VInt i, VInt j, _ -> + VInt (if f i j then 1L else 0L) + | _ -> invalid_arg "interp_cnd" + +let interp_i1 : sval -> bool = function + | VInt 0L -> false + | VInt 1L -> true + | _ -> invalid_arg "interp_i1" + +let rec interp_operand (nt:tid -> ty) (locs:locals) (ty:ty) (o:operand) : sval = + match ty, o with + | I64, Const i -> VInt i + | Ptr ty, Null -> VPtr (ty, NullId, [0]) + | Ptr ty, Gid g -> VPtr (ty, GlobId g, [0]) + | _, Id u -> locs u + | Namedt id, o -> interp_operand nt locs (nt id) o + | _ -> failwith @@ "interp_operand: malformed operand " ^ soo o ^ ":" ^ sot ty + + +(* Some utility functions *) +let update f k v = fun k' -> if k = k' then v else f k' + +let rec is_prefix (l:'a list) (m:'a list) : bool = + match l, m with + | [], _ -> true + | _, [] -> false + | a::l, b::m -> a = b && is_prefix l m + +let replace_assoc (l:('a * 'b) list) (a:'a) (b:'b) : ('a * 'b) list = + let rec loop acc = function + | [] -> List.rev @@ (a,b)::acc + | (a',_)::l' when a = a' -> List.rev_append acc @@ (a,b):: l' + | e::l' -> loop (e::acc) l' + in + loop [] l + +let replace_nth (l:'a list) (n:int) (a:'a) : 'a list = + let rec loop acc n = function + | [] -> raise Not_found + | a'::l' -> if n = 0 then List.rev_append acc (a::l') + else loop (a'::acc) (pred n) l' + in + loop [] n l + + +(* Memory access *) +let rec load_idxs (m:mval) (idxs:idx list) : mtree = + match idxs with + | [] -> MNode m + | i::idxs' -> + let len = List.length m in + if len <= i || i < 0 then raise OOBIndexDeref else + match idxs', List.nth m i with + | [], mt -> mt + | [0], MStr s -> MStr s (* [n x i8]* %p and gep [n x i8]* %p, 0, 0 alias *) + | _, MWord v -> failwith "load_idxs: attempted to index into word" + | _, MStr _ -> failwith "load_idxs: attempted to index into string" + | _, MNode m' -> load_idxs m' idxs' + +let rec store_idxs (m:mval) (idxs:idx list) (mt:mtree) : mval = + match idxs with + | [] -> [mt] + | i::idxs' -> + let len = List.length m in + if len <= i || i < 0 then raise OOBIndexDeref else + match idxs', List.nth m i with + | [], _ -> replace_nth m i mt + | _, MWord v -> failwith "store_idxs: attempted to index into word" + | _, MStr _ -> failwith "store_idxs: attempted to index into string" + | _, MNode m' -> replace_nth m i @@ MNode (store_idxs m' idxs' mt) + +let load_bid (c:config) (bid:bid) : mval = + match bid with + | NullId -> raise NullPtrDeref + | HeapId mid -> + (try List.assoc mid c.heap + with Not_found -> raise UseAfterFree) + | GlobId gid -> + (try List.assoc gid c.globals + with Not_found -> failwith "Load: bogus gid") + | StckId fid -> + (try List.assoc fid c.stack + with Not_found -> raise UseAfterFree) + + +let load_ptr (c:config) (_, bid, idxs:ptr) : mtree = + load_idxs (load_bid c bid) idxs + +let store_ptr (c:config) (_, bid, idxs:ptr) (mt:mtree) : config = + let mval = load_bid c bid in + match bid with + | NullId -> raise NullPtrDeref + | HeapId mid -> + let mval' = store_idxs mval idxs mt in + let heap = replace_assoc c.heap mid mval' in + {c with heap} + | GlobId gid -> + let mval' = store_idxs mval idxs mt in + let globals = replace_assoc c.globals gid mval' in + {c with globals} + | StckId fid -> + let frame' = store_idxs mval idxs mt in + let stack = replace_assoc c.stack fid frame' in + {c with stack} + + +(* Tag and GEP implementation *) +let effective_tag (nt:tid -> ty) (tag, _, idxs :ptr) : ty = + let rec loop tag idxs = + match tag, idxs with + | t, [] -> t + | Struct ts, i::idxs' -> if List.length ts <= i + then failwith "effective_tag: index oob of struct" + else loop (List.nth ts i) idxs' + | Array (n, t), i::idxs' -> loop t idxs' (* Don't check if OOB! *) + | Namedt id, _ -> loop (nt id) idxs + | _, _::_ -> failwith "effective_tag: index into non-aggregate" + in + loop tag @@ try List.tl idxs + with Failure _ -> failwith "effective_tag: invalid pointer missing first index" + + +let rec gep_idxs (p:idx list) (idxs:idx list) : idx list = + match p, idxs with + | [], _ | _, [] -> failwith "gep_idxs: invalid indices" + | [i], j::idxs' -> i+j::idxs' + | i::p', _ -> i::gep_idxs p' idxs + + +let legal_gep (nt:tid -> ty) (sty:ty) (tag:ty) : bool = + let rec ptrtoi8 : ty -> ty = function + | Ptr _ -> Ptr I8 + | Struct ts -> Struct (List.map ptrtoi8 ts) + | Array (n, t) -> Array (n, ptrtoi8 t) + | Namedt id -> ptrtoi8 (nt id) + | t -> t + in + let rec flatten_ty : ty -> ty list = function + | Struct ts -> List.(concat @@ map flatten_ty ts) + | t -> [t] + in + is_prefix (flatten_ty @@ ptrtoi8 sty) (flatten_ty @@ ptrtoi8 tag) + +let gep_ptr (nt:tid -> ty) (ot:ty) (p:ptr) (idxs':idx list) : sval = + if not (legal_gep nt ot @@ effective_tag nt p) then VUndef else + match p with + | t, NullId, idxs -> VUndef + | t, bid, idxs -> + VPtr (t, bid, gep_idxs idxs idxs') + + +(* LLVMlite reference interpreter *) +let interp_prog {tdecls; gdecls; fdecls} (args:string list) : sval = + + let globals = List.map (fun (g,gd) -> g,mval_of_gdecl gd) gdecls in + + let nt (id:tid) : ty = + try List.assoc id tdecls + with Not_found -> failwith @@ "interp_prog: undefined named type " ^ id + in + + let interp_op = interp_operand nt in + + let next_id : unit -> fid = + let c = ref 0 in + fun () -> c := succ !c; !c + in + + (* Global identifiers that will be interpreted as external functions *) + let runtime_fns = [ "ll_puts"; "ll_strcat"; "ll_ltoa" ] + in + + (* External function implementation *) + let runtime_call (t:ty) (fn:gid) (args:sval list) (c:config) : config * sval = + let load_strptr p = match load_ptr c p with + | MStr s -> s + | _ -> failwith "runtime_call: non string-ptr arg" + in + match t, fn, args with + | Void, "ll_puts", [VPtr p] -> + let s = load_strptr p in + print_endline s; + c, VUndef + | Ptr t, "ll_strcat", [VPtr ps1; VPtr ps2] -> + let s1 = load_strptr ps1 in + let s2 = load_strptr ps2 in + let mid = next_id () in + let mv = [MStr (s1 ^ s2)] in + let heap = (mid, mv)::c.heap in + {c with heap}, VPtr (t, HeapId mid, [0]) + | I64, "ll_ltoa", [VInt i; VPtr dst] -> + let mid = next_id () in + let mv = [MStr (Int64.to_string i)] in + let heap = (mid, mv)::c.heap in + {c with heap}, VPtr (t, HeapId mid, [0]) + | _ -> failwith @@ "runtime_call: invalid call to " ^ fn + in + + + (* Interprety the body of a function *) + let rec interp_cfg (k, blocks:cfg) (locs:locals) (c:config) : config * sval = + match k.insns, k.term with + + | (u, Binop (b, t, o1, o2))::insns, _ -> + let v1 = interp_op locs t o1 in + let v2 = interp_op locs t o2 in + let vr = interp_bop b v1 v2 in + let locs' = update locs u vr in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Icmp (cnd, t, o1, o2))::insns, _ -> + let v1 = interp_op locs t o1 in + let v2 = interp_op locs t o2 in + let vr = interp_cnd cnd v1 v2 in + let locs' = update locs u vr in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Alloca ty)::insns, _ -> + begin match c.stack with + | [] -> failwith "stack empty" + | (fid,frame)::stack' -> + let ptr = VPtr (ty, StckId fid, [List.length frame]) in + let stack = (fid, frame @ [MWord VUndef])::stack' in + let locs' = update locs u ptr in + interp_cfg ({k with insns}, blocks) locs' {c with stack} + end + + | (u, Load (Ptr t, o))::insns, _ -> + let mt = match interp_op locs (Ptr t) o with + | VPtr p -> + if effective_tag nt p <> t + then raise IncompatTagDeref + else load_ptr c p + | VUndef -> raise UndefPtrDeref + | VInt _ -> failwith "non-ptr arg for load" + in + let v = match mt with + | MWord VUndef -> raise UninitMemLoad + | MWord v -> v + | _ -> failwith "load: returned aggregate" + in + let locs' = update locs u v in + interp_cfg ({k with insns}, blocks) locs' c + + | (_, Store (t, os, od))::insns, _ -> + let vs = interp_op locs t os in + let vd = interp_op locs (Ptr t) od in + let c' = match vd with + | VPtr p -> + if effective_tag nt p <> t + then raise IncompatTagDeref + else store_ptr c p (MWord vs) + | VUndef -> raise UndefPtrDeref + | VInt _ -> failwith "non-vptr arg for load" + in + interp_cfg ({k with insns}, blocks) locs c' + + | (u, Call (t, ofn, ato))::insns, _ -> + let ats, aos = List.split ato in + let ft = Ptr (Fun (ats, t)) in + let g = match interp_op locs ft ofn with + | VPtr (_, GlobId g, [0]) -> g + | _ -> failwith "bad call arg" + in + let args = List.map2 (interp_op locs) ats aos in + let c', r = interp_call t g args c in + let locs' = update locs u r in + interp_cfg ({k with insns}, blocks) locs' c' + + | (u, Bitcast (t1, o, _))::insns, _ -> + let v = interp_op locs t1 o in + let locs' = update locs u v in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Gep (Ptr t, o, os))::insns, _ -> + let idx_of_sval : sval -> idx = function + | VInt i -> Int64.to_int i + | _ -> failwith "idx_of_sval: non-integer value" + in + let vs = List.map (interp_op locs I64) os in + let idxs' = List.map idx_of_sval vs in + let v' = match interp_op locs (Ptr t) o with + | VPtr p -> gep_ptr nt t p idxs' + | VUndef -> VUndef + | VInt _ -> failwith "non-ptr arg for gep" + in + let locs' = update locs u v' in + interp_cfg ({k with insns}, blocks) locs' c + + | [], (_, Ret (_, None)) -> + {c with stack = List.tl c.stack}, VUndef + + | [], (_, Ret (t, Some o)) -> + {c with stack = List.tl c.stack}, interp_op locs t o + + | [], (_, Br l) -> + let k' = List.assoc l blocks in + interp_cfg (k', blocks) locs c + + | [], (_, Cbr (o, l1, l2)) -> + let v = interp_op locs I1 o in + let l' = if interp_i1 v then l1 else l2 in + let k' = List.assoc l' blocks in + interp_cfg (k', blocks) locs c + + | (u,i)::_, _ -> failwith @@ "interp_cfg: invalid instruction \"" + ^ string_of_insn i ^ "\" at %" ^ u + + and interp_call (ty:ty) (fn:gid) (args:sval list) (c:config) : config * sval = + if List.mem fn runtime_fns + then runtime_call ty fn args c + else + let {f_param; f_cfg} = try List.assoc fn fdecls + with Not_found -> failwith @@ "interp_call: undefined function " ^ fn + in + if List.(length f_param <> length args) then + failwith @@ "interp_call: wrong no. arguments for " ^ fn; + let init_locs l = failwith @@ "interp_call: undefined local " ^ l in + let locs = List.fold_left2 update init_locs f_param args in + let stack = (next_id(), [])::c.stack in + interp_cfg f_cfg locs {c with stack} + in + + let mkarg a (p,h) = + let id = next_id () in + VPtr (I8, HeapId id, [0])::p, (id, [MStr a])::h + in + let ptrs, heap = List.fold_right mkarg ("LLINTERP"::args) ([],[]) in + + let narg = List.length args + 1 in + let argc = VInt (Int64.of_int @@ narg) in + let aid = next_id () in + let argv = VPtr (Array (narg, Ptr I8), HeapId aid, [0; 0]) in + let amval = List.map (fun p -> MWord p) ptrs in + let heap = (aid, [MNode amval])::heap in + + let _, r = interp_call I64 "main" [argc; argv] {globals; heap; stack=[]} in + r + + diff --git a/hw4/ll/lllexer.mll b/hw4/ll/lllexer.mll new file mode 100644 index 0000000..2fbacba --- /dev/null +++ b/hw4/ll/lllexer.mll @@ -0,0 +1,83 @@ +{ open Lexing + open Llparser + + exception SyntaxError of string +} + +let newline = '\n' | ('\r' '\n') | '\r' +let whitespace = ['\t' ' '] +let lowercase = ['a'-'z'] +let uppercase = ['A'-'Z'] +let character = lowercase | uppercase +let digit = '-'? ['0'-'9'] +let identifier = (character | digit | '_' ) (character | digit | '_' | '.')* + +rule token = parse + | eof { EOF } + | whitespace+ { token lexbuf } + | newline+ { token lexbuf } + | "c\"" { read_string (Buffer.create 17) lexbuf } + | '*' { STAR } + | ',' { COMMA } + | ':' { COLON } + | '=' { EQUALS } + | '(' { LPAREN } + | ')' { RPAREN } + | '{' { LBRACE } + | '}' { RBRACE } + | '[' { LBRACKET } + | ']' { RBRACKET } + | "i1" { I1 } + | "i8" { I8 } + | "i32" { I32 } + | "i64" { I64 } + | "to" { TO } + | "br" { BR } + | "eq" { EQ } + | "ne" { NE } + | "or" { OR } + | "and" { AND } + | "add" { ADD } + | "sub" { SUB } + | "mul" { MUL } + | "xor" { XOR } + | "slt" { SLT } + | "sle" { SLE } + | "sgt" { SGT } + | "sge" { SGE } + | "shl" { SHL } + | "ret" { RET } + | "getelementptr" { GEP } + | "type" { TYPE } + | "null" { NULL } + | "lshr" { LSHR } + | "ashr" { ASHR } + | "call" { CALL } + | "icmp" { ICMP } + | "void" { VOID } + | "load" { LOAD } + | "entry" { ENTRY } + | "store" { STORE } + | "label" { LABEL } + | "global" { GLOBAL } + | "define" { DEFINE } + | "declare" { DECLARE } + | "external" { EXTERNAL } + | "alloca" { ALLOCA } + | "bitcast" { BITCAST } + | '%' ('.' ?) (identifier as i) { UID i } + | '@' ('.' ?) (identifier as i) { GID i } + | "x" { CROSS } (* for Array types *) + | digit+ as d { INT (int_of_string d) } + | identifier as i { LBL i } + | ";" ([^ '\n' '\r'])* newline { token lexbuf } (* comments *) + | "declare" ([^ '\n' '\r'])* newline { token lexbuf } (* declare acts as a comment for our IR *) + | _ as c { raise @@ SyntaxError ("Unexpected character: " ^ Char.escaped c) } + +and read_string buf = parse + | '\\' "00" '"' { STRING (Buffer.contents buf) } + | '\\' { Buffer.add_char buf '\\'; read_string buf lexbuf } + | [^ '"' '\\']+ { Buffer.add_string buf (Lexing.lexeme lexbuf) + ; read_string buf lexbuf } + | _ { raise (SyntaxError ("Illegal string character: " ^ Lexing.lexeme lexbuf)) } + | eof { raise (SyntaxError ("String is not terminated")) } diff --git a/hw4/ll/llparser.mly b/hw4/ll/llparser.mly new file mode 100644 index 0000000..ca28340 --- /dev/null +++ b/hw4/ll/llparser.mly @@ -0,0 +1,298 @@ +%{ open Ll + open Llutil.Parsing + +%} + +(* Symbols *) +%token STAR (* * *) +%token COMMA (* , *) +%token COLON (* : *) +%token EQUALS (* = *) +%token LPAREN (* ( *) +%token RPAREN (* ) *) +%token LBRACE (* { *) +%token RBRACE (* } *) +%token LBRACKET (* [ *) +%token RBRACKET (* ] *) +%token EOF + +(* Reserved Words *) +%token CROSS (* x *) +%token I1 (* i1 *) +%token I8 (* i8 *) +%token I32 (* i32 *) +%token I64 (* i64 *) +%token TO (* to *) +%token BR (* br *) +%token EQ (* eq *) +%token NE (* ne *) +%token OR (* or *) +%token AND (* and *) +%token ADD (* add *) +%token SUB (* sub *) +%token MUL (* mul *) +%token XOR (* xor *) +%token SLT (* slt *) +%token SLE (* sle *) +%token SGT (* sgt *) +%token SGE (* sge *) +%token SHL (* shl *) +%token RET (* ret *) +%token TYPE (* type *) +%token NULL (* null *) +%token LSHR (* lshr *) +%token ASHR (* ashr *) +%token CALL (* call *) +%token ICMP (* icmp *) +%token VOID (* void *) +%token LOAD (* load *) +%token STORE (* store *) +%token LABEL (* label *) +%token ENTRY (* entry *) +%token GLOBAL (* global *) +%token DEFINE (* define *) +%token DECLARE (* define *) +%token EXTERNAL (* external *) +%token ALLOCA (* alloca *) +%token BITCAST (* bitcast *) +%token GEP (* getelementptr *) + +%token INT (* int64 values *) +%token LBL (* labels *) +%token GID (* global identifier *) +%token UID (* local identifier *) +%token STRING (* string literals *) + +%start prog +%% + +prog: + | ds=decls EOF + { ds } + +decls: + | ds = decls_rev + { { tdecls = List.rev ds.tdecls + ; gdecls = List.rev ds.gdecls + ; fdecls = List.rev ds.fdecls + ; edecls = List.rev ds.edecls + } } + +decls_rev: + | (* empty *) + { { tdecls = [] ; gdecls = [] ; fdecls = [] ; edecls = [] } } + | ds=decls_rev f=fdecl + { { ds with fdecls = f :: ds.fdecls } } + | ds=decls_rev g=gdecl + { { ds with gdecls = g :: ds.gdecls } } + | ds=decls_rev t=tdecl + { { ds with tdecls = t :: ds.tdecls } } + | ds=decls_rev e=edecl + { { ds with edecls = e :: ds.edecls } } + +fdecl: + | DEFINE t=ty l=GID LPAREN a=arg_list RPAREN + LBRACE eb=entry_block bs=block_list RBRACE + { (l, { f_ty = (List.map fst a, t) + ; f_param = List.map snd a + ; f_cfg = (eb, bs) + } + ) } + +gdecl: + | g=GID EQUALS GLOBAL t=ty gi=ginit + { (g, (t,gi)) } + +tdecl: + | tid=UID EQUALS TYPE t=ty + { (tid, t) } + +edecl: + | DECLARE rt=ty g=GID LPAREN ts=separated_list(COMMA, ty) RPAREN + { (g, Fun (ts,rt)) } + | g=GID EQUALS EXTERNAL GLOBAL t=ty + { (g, t) } + +nonptr_ty: + | VOID { Void } + | I1 { I1 } + | I8 { I8 } + | I64 { I64 } + | LBRACE ts=ty_list RBRACE + { Struct ts } + | LBRACKET i=INT CROSS t=ty RBRACKET + { Array (i,t) } + | rt=ty LPAREN ts=ty_list RPAREN + { Fun (ts, rt) } + | t=UID + { Namedt t } + +ty: + | t=ty STAR + { Ptr t } + | t=nonptr_ty + { t } + +ty_list_rev: + | t=ty + { [t] } + | ts=ty_list_rev COMMA t=ty + { t::ts } + +ty_list: + | ts=ty_list_rev + { List.rev ts } + +arg: + | t=ty u=UID { (t,u) } + +arg_list_rev: + | (* empty *) + { [] } + | a=arg + { [a] } + | args=arg_list_rev COMMA a=arg + { a::args } + +arg_list: + | a=arg_list_rev + { List.rev a } + +operand: + | NULL + { Null } + | i=INT + { Const (Int64.of_int i) } + | g=GID + { Gid g } + | u=UID + { Id u } + +ty_operand_list_rev: + | (* empty *) + { [] } + | t=ty o=operand + { [(t,o)] } + | tos=ty_operand_list_rev COMMA t=ty o=operand + { (t,o)::tos } + +ty_operand_list: + | tos=ty_operand_list_rev + { List.rev tos } + +i_operand_list_rev: + | (* empty *) + { [] } + | I64 o=operand + { [o] } + | I32 o=operand + { [o] } + | os=i_operand_list_rev COMMA I64 o=operand + { o::os } + | os=i_operand_list_rev COMMA I32 o=operand + { o::os } + +i_operand_list: + | os=i_operand_list_rev + { List.rev os } + +terminator: + | RET t=ty o=operand + { Ret (t, Some o) } + | RET t=ty + { Ret (t, None) } + | BR LABEL l=UID + { Br l } + | BR I1 o=operand COMMA LABEL l1=UID COMMA LABEL l2=UID + { Cbr (o,l1,l2) } + +block: + | is=insn_list t=terminator + { { insns = is; term=(gensym "tmn", t) } } + +block_list_rev: + | (* empty *) + { [] } + | bs=block_list_rev l=LBL COLON b=block + { (l,b) :: bs } + +block_list: + | bs=block_list_rev + { List.rev bs } + +entry_block: + | ENTRY COLON b=block + { b } + | b=block + { b } + +bop: + | OR { Or } + | ADD { Add } + | SUB { Sub } + | MUL { Mul } + | SHL { Shl } + | XOR { Xor } + | AND { And } + | LSHR { Lshr } + | ASHR { Ashr } + +cnd: + | EQ { Eq } + | NE { Ne } + | SLT { Slt } + | SLE { Sle } + | SGT { Sgt } + | SGE { Sge } + +insn: + | u=UID EQUALS b=bop t=ty o1=operand COMMA o2=operand + { (u, Binop (b,t,o1,o2)) } + | u=UID EQUALS ALLOCA t=ty + { (u, Alloca t) } + | u=UID EQUALS LOAD ty COMMA t=ty o=operand + { (u, Load (t,o)) } + | STORE t1=ty o1=operand COMMA t2=ty o2=operand + { (gensym "store", Store (t1,o1,o2)) } + | u=UID EQUALS ICMP c=cnd t=ty o1=operand COMMA o2=operand + { (u, Icmp (c,t,o1,o2)) } + | CALL t=ty o=operand LPAREN args=ty_operand_list RPAREN + { (gensym "call", Call (t, o, args)) } + | u=UID EQUALS CALL t=ty o=operand LPAREN args=ty_operand_list RPAREN + { (u, Call (t, o, args)) } + | u=UID EQUALS BITCAST t1=ty o=operand TO t2=ty + { (u, Bitcast (t1,o,t2)) } + | u=UID EQUALS GEP ty COMMA t=ty o=operand COMMA os=i_operand_list + { (u, Gep (t,o,os)) } + +insn_list: + | is=list(insn) + { is } + +gdecl_list_rev: + | (* empty *) + { [] } + | t=ty g=ginit + { [(t,g)] } + | gs=gdecl_list_rev COMMA t=ty g=ginit + { (t,g)::gs } + +gdecl_list: + | gs=gdecl_list_rev + { List.rev gs } + +ginit: + | NULL + { GNull } + | g=GID + { GGid g } + | i=INT + { GInt (Int64.of_int i) } + | s=STRING + { GString s } + | LBRACKET gs=gdecl_list RBRACKET + { GArray gs } + | LBRACE gs=gdecl_list RBRACE + { GStruct gs } + | BITCAST LPAREN t1=ty g=ginit TO t2=ty RPAREN + { GBitcast (t1, g, t2) } diff --git a/hw4/ll/llruntime.c b/hw4/ll/llruntime.c new file mode 100644 index 0000000..895fe36 --- /dev/null +++ b/hw4/ll/llruntime.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +/* TODO: if we enforce that all char literals are null-terminated, + and all allocated memory is zero-initialized, are these safe + when llvmlite program does not exhibit UB? */ + +void *ll_malloc(int64_t n, int64_t size) { + return calloc(n, size); +} + +int64_t ll_strlen(int8_t *s) { + return 0; +} + +int8_t *ll_strncopy(int8_t *dst, int8_t *src, int64_t i) { + int64_t src_size = ll_strlen(src); + int64_t dst_size = ll_strlen(dst); + if (i >= dst_size) + return dst; + else + return (int8_t*)strncpy((char *)dst + i, (char *)src, dst_size - i); +} + +void ll_puts(int8_t *s) { + puts((char *)s); +} + +int64_t ll_atol(int8_t *s) { + return atol((char *)s); +} + +int64_t ll_ltoa(int64_t i, int8_t *dst) { + int64_t size = ll_strlen(dst); + return snprintf((char *)dst, size, "%ld", (long)i); +} diff --git a/hw4/ll/llutil.ml b/hw4/ll/llutil.ml new file mode 100644 index 0000000..044d536 --- /dev/null +++ b/hw4/ll/llutil.ml @@ -0,0 +1,170 @@ +;; open Ll + +(* serializing --------------------------------------------------------------- *) + +let mapcat s f l = String.concat s @@ List.map f l +let prefix p f a = p ^ f a +let ( ^. ) s t = if s = "" || t = "" then "" else s ^ t +let pp = Printf.sprintf + +let rec string_of_ty : ty -> string = function + | Void -> "void" + | I1 -> "i1" + | I8 -> "i8" + | I64 -> "i64" + | Ptr ty -> pp "%s*" (string_of_ty ty) + | Struct ts -> pp "{ %s }" (mapcat ", " string_of_ty ts) + | Array (n, t) -> pp "[%s x %s]" (string_of_int n) (string_of_ty t) + | Fun (ts,t) -> pp "%s (%s)" (string_of_ty t) (mapcat ", " string_of_ty ts) + | Namedt s -> pp "%%%s" s + +let sot = string_of_ty + +let dptr = function + | Ptr t -> t + | _ -> failwith "PP: expected pointer type" + +let string_of_operand : operand -> string = function + | Null -> "null" + | Const i -> Int64.to_string i + | Gid g -> "@" ^ g + | Id u -> "%" ^ u + +let soo = string_of_operand + +let soop (t,v:ty * operand) : string = + pp "%s %s" (sot t) (soo v) + +let string_of_bop : bop -> string = function + | Add -> "add" | Sub -> "sub" | Mul -> "mul" + | Shl -> "shl" | Lshr -> "lshr" | Ashr -> "ashr" + | And -> "and" | Or -> "or" | Xor -> "xor" + +let string_of_cnd : cnd -> string = function + | Eq -> "eq" | Ne -> "ne" | Slt -> "slt" + | Sle -> "sle" | Sgt -> "sgt" | Sge -> "sge" + +let string_of_gep_index : operand -> string = function + | Const i -> "i32 " ^ Int64.to_string i + | o -> "i64 " ^ soo o + +let string_of_insn : insn -> string = function + | Binop (b, t, o1, o2) -> pp "%s %s %s, %s" + (string_of_bop b) (sot t) (soo o1) (soo o2) + | Alloca t -> pp "alloca %s" (sot t) + | Load (t, o) -> pp "load %s, %s %s" (sot (dptr t)) (sot t) (soo o) + | Store (t, os, od) -> pp "store %s %s, %s %s" + (sot t) (soo os) (sot (Ptr t)) (soo od) + | Icmp (c, t, o1, o2) -> pp "icmp %s %s %s, %s" + (string_of_cnd c) (sot t) (soo o1) (soo o2) + | Call (t, o, oa) -> pp "call %s %s(%s)" + (sot t) (soo o) (mapcat ", " soop oa) + | Bitcast (t1, o, t2) -> pp "bitcast %s %s to %s" (sot t1) (soo o) (sot t2) + | Gep (t, o, oi) -> pp "getelementptr %s, %s %s, %s" (sot (dptr t)) (sot t) (soo o) + (mapcat ", " string_of_gep_index oi) + +let string_of_named_insn (u,i:uid * insn) : string = + match i with + | Store _ | Call (Void, _, _) -> string_of_insn i + | _ -> pp "%%%s = %s" u (string_of_insn i) + +let string_of_terminator : terminator -> string = function + | Ret (_, None) -> "ret void" + | Ret (t, Some o) -> pp "ret %s %s" (sot t) (soo o) + | Br l -> pp "br label %%%s" l + | Cbr (o, l, m) -> pp "br i1 %s, label %%%s, label %%%s" (soo o) l m + +let string_of_block (b:block) : string = + (mapcat "\n" (prefix " " string_of_named_insn) b.insns ^. "\n") + ^ (prefix " " string_of_terminator) (snd b.term) + +let string_of_cfg (e,bs:cfg) : string = + let string_of_named_block (l,b) = l ^ ":\n" ^ string_of_block b in + string_of_block e ^ "\n" ^. mapcat "\n" string_of_named_block bs + +let string_of_named_fdecl (g,f:gid * fdecl) : string = + let string_of_arg (t,u) = pp "%s %%%s" (sot t) u in + let ts, t = f.f_ty in + pp "define %s @%s(%s) {\n%s\n}\n" (sot t) g + (mapcat ", " string_of_arg List.(combine ts f.f_param)) + (string_of_cfg f.f_cfg) + +let rec string_of_ginit : ginit -> string = function + | GNull -> "null" + | GGid g -> pp "@%s" g + | GInt i -> Int64.to_string i + | GString s -> pp "c\"%s\\00\"" s + | GArray gis -> pp "[ %s ]" (mapcat ", " string_of_gdecl gis) + | GStruct gis -> pp "{ %s }" (mapcat ", " string_of_gdecl gis) + | GBitcast (t1,g,t2) -> pp "bitcast (%s %s to %s)" (sot t1) (string_of_ginit g) (sot t2) + +and string_of_gdecl (t,gi:gdecl) : string = + pp "%s %s" (sot t) (string_of_ginit gi) + +let string_of_named_gdecl (g,gd:gid * gdecl) : string = + pp "@%s = global %s" g (string_of_gdecl gd) + +let string_of_named_tdecl (n,t:tid * ty) : string = + pp "%%%s = type %s" n (sot t) + +let string_of_named_edecl (g,t:gid * ty) : string = + match t with + | Fun (ts, rt) -> pp "declare %s @%s(%s)" (string_of_ty rt) g + (mapcat ", " string_of_ty ts) + | _ -> pp "@%s = external global %s" g (string_of_ty t) + +let string_of_prog (p:prog) : string = + (mapcat "\n" string_of_named_tdecl p.tdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_gdecl p.gdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_fdecl p.fdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_edecl p.edecls) + +(* comparison for testing ----------------------------------------------------- *) + +(* delete dummy uids before comparison *) +let compare_block (b:block) (c:block) : int = + let del_dummy (u,i) = + match i with + | Store (_, _, _) -> "", i + | Call (Void, _, _) -> "", i + | _ -> u, i + in + let del_term (u,t) = ("", t) + in + Stdlib.compare + {insns=List.map del_dummy b.insns; term=del_term b.term} + {insns=List.map del_dummy c.insns; term=del_term c.term} + + + +(* helper module for AST ------------------------------------------------------ *) + +module IR = struct + let define t gid args f_cfg = + let ats, f_param = List.split args in + gid, { f_ty=ats,t; f_param; f_cfg} + + (* ignore first label *) + let cfg (lbs:(lbl * block) list) : cfg = + match lbs with + | [] -> failwith "cfg: no blocks!" + | (_,b)::lbs -> b, lbs + + let entry insns term : (lbl * block) = "", { insns; term } + let label lbl insns term = lbl, { insns; term } + + (* terminators *) + let ret_void = Ret (Void, None) + let ret t op = Ret (t, Some op) + let br l = Br l + let cbr op l1 l2 = Cbr (op, l1, l2) +end + +module Parsing = struct + +let gensym, reset = + let c = ref 0 in + ( fun (s:string) -> incr c; Printf.sprintf "_%s__%d" s (!c) ) + , ( fun () -> c := 0 ) + +end diff --git a/hw4/main.ml b/hw4/main.ml new file mode 100644 index 0000000..e6c771d --- /dev/null +++ b/hw4/main.ml @@ -0,0 +1,50 @@ +open Ll +open Arg +open Assert +open Driver + +(* testing harness ---------------------------------------------------------- *) +exception Ran_tests +let suite = ref (Studenttests.provided_tests @ Gradedtests.graded_tests) + +let execute_tests () = + let outcome = run_suite !suite in + Printf.printf "%s\n" (outcome_to_string outcome); + raise Ran_tests + + +(* command-line arguments --------------------------------------------------- *) +let args = + [ ("--test", Unit execute_tests, "run the test suite, ignoring other file inputs") + ; ("-op", Set_string Platform.output_path, "set the path to the output files directory [default='output']") + ; ("-o", Set_string executable_filename, "set the name of the resulting executable [default='a.out']") + ; ("-S", Clear assemble, "stop after generating .s files; do generate .o files") + ; ("-c", Clear link, "stop after generating .o files; do not generate executables") + ; ("--interpret-ll", Set interpret_ll, "runs each LL program through the LL interpreter") + ; ("--print-ll", Set print_ll_flag, "prints the program LL code") + ; ("--print-x86", Set print_x86_flag, "prints the program's assembly code") + ; ("--clang", Set clang, "compiles to assembly using clang, not the Compiler Design backend") + ; ("--execute-x86", Set execute_x86, "run the resulting executable file") + ; ("--print-ast", Set print_ast_flag , "print the program's AST as ML code") + ; ("--print-oat", Set print_oat_flag , "print the program's OAT code") + ; ("-v", Unit Platform.enable_verbose, "enables more verbose compilation output") + ] + + +(* Files found on the command line *) +let files = ref [] + +let main () = + Platform.configure_os (); + Platform.create_output_dir (); + try + Arg.parse args (fun filename -> files := filename :: !files) + "Compiler Design main test harness\n\ + USAGE: ./main.native [options] \n\ + see README for details about using the compiler"; + + process_files !files + + with Ran_tests -> () + +;; main () diff --git a/hw4/oatprograms/abs.oat b/hw4/oatprograms/abs.oat new file mode 100644 index 0000000..4f9df75 --- /dev/null +++ b/hw4/oatprograms/abs.oat @@ -0,0 +1,13 @@ +int abs(int x) { + if (x < 0) { + return -x; + } else if (x > 0) { + return x; + } else { + return 0; + } +} +int program (int argc, string[] argv) { + print_int(abs(10) + abs(-10) + abs(0)); + return 0; +} diff --git a/hw4/oatprograms/arrayargs.oat b/hw4/oatprograms/arrayargs.oat new file mode 100644 index 0000000..ef8be3e --- /dev/null +++ b/hw4/oatprograms/arrayargs.oat @@ -0,0 +1,20 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +int program (int argc, string[] argv) { + var x = new int[3]; + for (var i=0; i<3; i = i+1;) { + x[i] = i; + } + var y = new int[3]; + for (var i=0; i<3; i = i+1;) { + y[i] = i+3; + } + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw4/oatprograms/arrayargs1.oat b/hw4/oatprograms/arrayargs1.oat new file mode 100644 index 0000000..74ec125 --- /dev/null +++ b/hw4/oatprograms/arrayargs1.oat @@ -0,0 +1,16 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +global x = new int[]{1, 2, 3}; +global y = new int[]{4, 5, 6}; + + +int program (int argc, string[] argv) { + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw4/oatprograms/arrayargs2.oat b/hw4/oatprograms/arrayargs2.oat new file mode 100644 index 0000000..1e31732 --- /dev/null +++ b/hw4/oatprograms/arrayargs2.oat @@ -0,0 +1,14 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +int program (int argc, string[] argv) { + var x = new int[3]; + var y = new int[3]; + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw4/oatprograms/arrayargs3.oat b/hw4/oatprograms/arrayargs3.oat new file mode 100644 index 0000000..b4e18a7 --- /dev/null +++ b/hw4/oatprograms/arrayargs3.oat @@ -0,0 +1,17 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +global x = new int[]{1, 2, 3}; +global y = new int[]{4, 5, 6}; + + +int program (int argc, string[] argv) { + f(x, y, true)[0] = 17; /* non-trivial lhs path */ + var z = f(x, y, true)[0] + f(y, x, false)[0]; /* non-trivial expression paths */ + return z; +} diff --git a/hw4/oatprograms/arrayargs4.oat b/hw4/oatprograms/arrayargs4.oat new file mode 100644 index 0000000..3a5cf10 --- /dev/null +++ b/hw4/oatprograms/arrayargs4.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[3]{i -> 0}; + return 0; +} diff --git a/hw4/oatprograms/binary_gcd.oat b/hw4/oatprograms/binary_gcd.oat new file mode 100644 index 0000000..ea13088 --- /dev/null +++ b/hw4/oatprograms/binary_gcd.oat @@ -0,0 +1,26 @@ +int binary_gcd (int x, int y) { + if (x == y) { return x; } + if (x == 0) { return y; } + if (y == 0) { return x; } + if ((~x [&] 1) == 1) { + if ((y [&] 1) == 1) { + return binary_gcd(x >> 1, y); + } + else { + return binary_gcd(x >> 1, y >> 1) << 1; + } + } + if ((~y [&] 1) == 1) { + return binary_gcd(x, y >> 1); + } + if (x > y) { + return binary_gcd((x - y) >> 1, y); + } + return binary_gcd((y - x) >> 1, x); +} + +int program (int argc, string[] argv) { + var x = 21; + var y = 15; + return binary_gcd(x, y); +} diff --git a/hw4/oatprograms/binary_search.oat b/hw4/oatprograms/binary_search.oat new file mode 100644 index 0000000..192c264 --- /dev/null +++ b/hw4/oatprograms/binary_search.oat @@ -0,0 +1,65 @@ +int euclid_division (int numerator, int denominator) { + if (denominator < 0) + { + return -(euclid_division(numerator, -(denominator))); + } + + var quotient = 0; + var remainder = numerator; + + if (numerator < 0) + { + remainder = -(numerator); + + while (remainder >= denominator) + { + quotient = quotient + 1; + remainder = remainder - denominator; + } + + if ( remainder == 0 ) { return -(quotient); } + else { + return -(quotient) - 1; + } + } + + while (remainder >= denominator) + { + quotient = quotient + 1; + remainder = remainder - denominator; + } + return quotient; +} + +bool binary_search (int[] input, int key, int min, int max) { + if (max < min) { + return false; + } + + var midpt = euclid_division((max + min), 2); + + if (input[midpt] > key) + { + return binary_search(input, key, min, (midpt - 1)); + } + if (input[midpt] < key) + { + return binary_search(input, key, (midpt + 1), max); + } else { + return true; + } +} + +int program (int argc, string[] argv) { + var test_array = new int[100]; + for (var i=0; i < 100; i=i+1;) { test_array[i] = 2 * i + 1; } + var even = binary_search (test_array, 80, 0, 99); + var odd = binary_search (test_array, 81, 0, 99); + + if (!(even & odd) & (even | odd)) + { + print_string("Correct!"); + } + + return 0; +} \ No newline at end of file diff --git a/hw4/oatprograms/bsort.oat b/hw4/oatprograms/bsort.oat new file mode 100644 index 0000000..a4544c9 --- /dev/null +++ b/hw4/oatprograms/bsort.oat @@ -0,0 +1,41 @@ +void bubble_sort(int[] numbers, int array_size) +{ + var temp=0; + var i = (array_size - 1); + + for (; i > 0; i=i-1;) + { + for (var j = 1; j <= i; j=j+1;) + { + if (numbers[j-1] > numbers[i]) + { + temp = numbers[j-1]; + numbers[j-1] = numbers[i]; + numbers[i] = temp; + } + } + } + + return; +} + +int program (int argc, string[] argv) { + var a = new int[8]; + + a[0] = 121; + a[1] = 125; + a[2] = 120; + a[3] = 111; + a[4] = 116; + a[5] = 110; + a[6] = 117; + a[7] = 119; + + print_string (string_of_array (a)); + print_string (" "); + bubble_sort (a, 8); + print_string (string_of_array (a)); + + return -1; +} + diff --git a/hw4/oatprograms/calculator.oat b/hw4/oatprograms/calculator.oat new file mode 100644 index 0000000..c4152cf --- /dev/null +++ b/hw4/oatprograms/calculator.oat @@ -0,0 +1,149 @@ +int[] new_stack() { + var s = new int[7]; + s[0] = 5; + s[1] = 0; /* current index of stack ptr (offset 2) */ + return s; +} + +int peek_stack(int[] s) { + var index = 1 + s[1]; + return s[index]; +} + +int[] pop_stack(int[] s) { + var cur_index = s[1]; + if(cur_index > 0) { + cur_index = cur_index - 1; + } + + s[1] = cur_index; + return maybe_new_stack(s); +} + +int[] push_stack(int[] s, int v) { + var cur_index = 2 + s[1]; + s[cur_index] = v; + s[1] = cur_index - 1; + + return maybe_new_stack(s); +} + +int[] maybe_new_stack(int[] s) { + /* if index of s > half the size, double the size of s */ + /* if index of s < quarter the size, half the size of s */ + + return s; + + var cur_index = s[1]; + var cur_size = s[0]; + + if(cur_size <= 5) { + /* min size is 5 */ + return s; + } + + if(cur_index > (cur_size << 1)) { + /* double size of s */ + var new_s = new int[2 + cur_size * 2]; + cur_size = cur_size * 2; + new_s[0] = cur_size; + new_s[1] = cur_index; + + /* copy over values */ + for(var i = 0; i <= cur_index; i = i + 1;) { + new_s[2 + i] = s[2 + i]; + } + + return new_s; + } else if(cur_index < ((cur_size << 1) << 1)) { + /* halve s */ + var new_s = new int[2 + cur_size << 1]; + cur_size = cur_size << 1; + new_s[0] = cur_size; + new_s[1] = cur_index; + + /* copy over values */ + for(var i = 0; i <= cur_index; i = i + 1;) { + new_s[2 + i] = s[2 + i]; + } + + return new_s; + } + + return s; +} + +int get_val(int i) { + /* turns a char_code i into a value v */ + return i - 48; +} + +int int_of_string(string s) { + var arr = array_of_string(s); + var len = length_of_string(s); + + var sum = 0; + for(var i = 0; i < len; i = i + 1;) { + sum = sum * 10; + var val = get_val(arr[i]); + sum = sum + val; + } + + return sum; +} + + + +int program (int argc, string[] argv) { + /* a stack based calculator. feed in input numbers and operands + and - */ + /* will calculate result. a reverse polish notation calculator */ + + var str = "\n"; + + var stack = new_stack(); + + for(var i = 1; i < argc; i = i + 1;) { + var current_item = argv[i]; + + var did_op = false; + + var len = length_of_string(current_item); + if(len == 1) { + var arr = array_of_string(current_item); + did_op = true; + if(arr[0] == 43) { + /* plus op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 + x2); + } else if(arr[0] == 45) { + /* minus op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 - x2); + } else if(arr[0] == 120) { + /* times op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 * x2); + } else { + did_op = false; + } + } + + if(!did_op) { + /* didn't do op! we have a number maybe */ + var v = int_of_string(current_item); + stack = push_stack(stack, v); + } + } + + print_int(peek_stack(stack)); + return peek_stack(stack); +} diff --git a/hw4/oatprograms/count_sort.oat b/hw4/oatprograms/count_sort.oat new file mode 100644 index 0000000..1197eb8 --- /dev/null +++ b/hw4/oatprograms/count_sort.oat @@ -0,0 +1,59 @@ + +int min(int[] arr, int len) { + var min = arr[0]; + for (var i = 0; i < len; i = i + 1;) { + if (arr[i] < min) { + min = arr[i]; + } + } + return min; +} + +int max(int[] arr, int len) { + var max = arr[0]; + for (var i = 0; i < len; i = i + 1;) { + if (arr[i] > max) { + max = arr[i]; + } + } + return max; +} + +int[] count_sort(int[] arr, int len) { + var min = min(arr, len); + var max = max(arr, len); + + var counts = new int[max - min + 1]; + + for (var i = 0; i < len; i = i + 1;) { + counts[arr[i] - min] = counts[arr[i] - min] + 1; + } + + var i = min; + var j = 0; + + var out = new int[len]; + + while (i <= max) { + + if (counts[i - min] > 0) { + out[j] = i; + counts[i - min] = counts[i - min] - 1; + j = j + 1; + } else { + i = i + 1; + } + } + return out; +} + +int program(int argc, string[] argv) { + var arr = new int[]{65, 70, 72, 90, 65, 65, 69, 89, 67}; + var len = 9; + + print_string(string_of_array(arr)); + print_string("\n"); + var sorted = count_sort(arr, len); + print_string(string_of_array(sorted)); + return 0; +} diff --git a/hw4/oatprograms/easy_p1.oat b/hw4/oatprograms/easy_p1.oat new file mode 100644 index 0000000..3e77270 --- /dev/null +++ b/hw4/oatprograms/easy_p1.oat @@ -0,0 +1,4 @@ +int f ( ) { + return 0 ; +} + diff --git a/hw4/oatprograms/easy_p2.oat b/hw4/oatprograms/easy_p2.oat new file mode 100644 index 0000000..943c398 --- /dev/null +++ b/hw4/oatprograms/easy_p2.oat @@ -0,0 +1,5 @@ +int f ( int x ) { + var x = 0; + x = x + x - x * x >> x << x [|] x [&] -~x >>> x; + return x; +} diff --git a/hw4/oatprograms/easy_p3.oat b/hw4/oatprograms/easy_p3.oat new file mode 100644 index 0000000..530ced8 --- /dev/null +++ b/hw4/oatprograms/easy_p3.oat @@ -0,0 +1,22 @@ +string bar (int x, string y) { + var s = "This is a string"; + var array = new int[]{1, 3}; + var y = array[0]; + return s; +} + +void proc1 () { + proc2 ( ); + return; +} + +void proc2 ( ) { + proc1 ( ); + return; +} + +bool foo ( int x, int[] y ) { + var s = bar (x, "compilerdesign"); + proc1 (); + return true; +} diff --git a/hw4/oatprograms/easy_p4.oat b/hw4/oatprograms/easy_p4.oat new file mode 100644 index 0000000..c9e13e7 --- /dev/null +++ b/hw4/oatprograms/easy_p4.oat @@ -0,0 +1,40 @@ +/* This is a test case: level 0 + + /* level 1 */ + + + /* level 1 + /* level 2 */ + */ + + "This is a commented string." +*/ + +string f ( ) { + var s = + new string[][] + { + new string []{ + "s00:\n+\n=2*\n", + "s01:this is not a comment in string.*", + "s02:\"\\t\\n\\\\?\"" + }, + new string[]{ + "s10:\133\134", + "s11", + "s12" + } + }; + + return s[0][1]; +} + +int[][] g (int [][] x) { + var y = new int[][]{ new int[]{0, 1}, new int[]{2, 3} }; + var i = 0; + + x[0][0] = i + y[1][1]; /* + g(x)[1][0]; */ + i = -!~x[0][0] ; /* comments */ + + return x; +} diff --git a/hw4/oatprograms/easy_p5.oat b/hw4/oatprograms/easy_p5.oat new file mode 100644 index 0000000..a9231fc --- /dev/null +++ b/hw4/oatprograms/easy_p5.oat @@ -0,0 +1,14 @@ +global i = 19; +global b1 = true; +global b2 = false; +global str = "This is a string!"; +global arr1 = new int[]{0,1,2}; +global arr2 = new int[][]{ new int[]{10,11}, new int[]{20,21}, new int[]{30,31}}; +global arr3 = new string[]{"String1", "String2", "String3"}; + +global arr4 = new string[][] + { + new string[]{"String00","String01"}, + new string[]{"String10","String11"}, + new string[]{"String20","String21"} + }; diff --git a/hw4/oatprograms/easy_p6.oat b/hw4/oatprograms/easy_p6.oat new file mode 100644 index 0000000..b16eb74 --- /dev/null +++ b/hw4/oatprograms/easy_p6.oat @@ -0,0 +1,12 @@ +global y = 0; +global z = 0; + +void f (int x, int y) { + var x = 0; + return; +} + +void g (int x, int y) { + var z = 0; + return; +} diff --git a/hw4/oatprograms/easy_p7.oat b/hw4/oatprograms/easy_p7.oat new file mode 100644 index 0000000..bc0f929 --- /dev/null +++ b/hw4/oatprograms/easy_p7.oat @@ -0,0 +1,7 @@ +global j = new int[]{1,2,3,4}; +int[] f () { + var a = new int[][]{1, 2}; + var i = new int[4]; + var arr1 = new int[3]; + return new int[2]; +} diff --git a/hw4/oatprograms/easyrun1.oat b/hw4/oatprograms/easyrun1.oat new file mode 100644 index 0000000..32327bc --- /dev/null +++ b/hw4/oatprograms/easyrun1.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 17; +} diff --git a/hw4/oatprograms/easyrun10.oat b/hw4/oatprograms/easyrun10.oat new file mode 100644 index 0000000..e94ae0b --- /dev/null +++ b/hw4/oatprograms/easyrun10.oat @@ -0,0 +1,19 @@ +int program (int argc, string[] argv) { + var x = new int[][]{new int[]{1}, + new int[]{2}, + new int[]{3}, + new int[]{4}}; + var ans = 0; + + for(var i=0;i<4;i=i+1;) { + ans = x[i][0] - ans; + } + + if((5 [&] ~5 [|] 0) != 0) { + return ans; + } else { + return -ans; + } + + return ans; +} diff --git a/hw4/oatprograms/easyrun2.oat b/hw4/oatprograms/easyrun2.oat new file mode 100644 index 0000000..d18f435 --- /dev/null +++ b/hw4/oatprograms/easyrun2.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 17 + 18; +} diff --git a/hw4/oatprograms/easyrun3.oat b/hw4/oatprograms/easyrun3.oat new file mode 100644 index 0000000..f57521a --- /dev/null +++ b/hw4/oatprograms/easyrun3.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var x = 0; + var i = 0; + + while (i < 10) { + x = (x + i) * i; + i = i + 1; + } + + return x; +} diff --git a/hw4/oatprograms/easyrun4.oat b/hw4/oatprograms/easyrun4.oat new file mode 100644 index 0000000..523f3b7 --- /dev/null +++ b/hw4/oatprograms/easyrun4.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + var x = 0; + for (var i=0; i<3; i = i+1;) { + x = x + 2; + } + return x; +} diff --git a/hw4/oatprograms/easyrun5.oat b/hw4/oatprograms/easyrun5.oat new file mode 100644 index 0000000..2ddb08f --- /dev/null +++ b/hw4/oatprograms/easyrun5.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var x = 100 >> 3; + var y = 100 << 3; + + if (x-y <= 0) { + return -x-y; + } else { + return x-y; + } + +} diff --git a/hw4/oatprograms/easyrun6.oat b/hw4/oatprograms/easyrun6.oat new file mode 100644 index 0000000..f2234cb --- /dev/null +++ b/hw4/oatprograms/easyrun6.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(!true | -4 + 5 > 0 & 6 * 4 < 25) { + return 9; + } else { + return 4; + } +} diff --git a/hw4/oatprograms/easyrun7.oat b/hw4/oatprograms/easyrun7.oat new file mode 100644 index 0000000..f6e053b --- /dev/null +++ b/hw4/oatprograms/easyrun7.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(((~5 [&] 6) >= (2 [|] 0))) { + return 23; + } else { + return 46; + } +} diff --git a/hw4/oatprograms/easyrun8.oat b/hw4/oatprograms/easyrun8.oat new file mode 100644 index 0000000..21cbce6 --- /dev/null +++ b/hw4/oatprograms/easyrun8.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(6 != 5) { + return ~(5 << 17 >> 2 >>> 10) * 2 - 100 + 6; + } else { + return 2; + } +} diff --git a/hw4/oatprograms/easyrun9.oat b/hw4/oatprograms/easyrun9.oat new file mode 100644 index 0000000..282656f --- /dev/null +++ b/hw4/oatprograms/easyrun9.oat @@ -0,0 +1,10 @@ +int program (int argc, string[] argv) { + var x = new int[]{1,2,3,4}; + var ans = 0; + + for(var i=0;i<4;i=i+1;) { + ans = x[i] * ~x[i]; + } + + return ans; +} diff --git a/hw4/oatprograms/fac.oat b/hw4/oatprograms/fac.oat new file mode 100644 index 0000000..d162b63 --- /dev/null +++ b/hw4/oatprograms/fac.oat @@ -0,0 +1,13 @@ +int f(int i) { + var r = 0; + if (i == 0) { + r = 1; + } else { + r = i * f (i-1); + } + return r; +} + +int program (int argc, string[] argv) { + return f (5); +} diff --git a/hw4/oatprograms/fact.oat b/hw4/oatprograms/fact.oat new file mode 100644 index 0000000..cf1e754 --- /dev/null +++ b/hw4/oatprograms/fact.oat @@ -0,0 +1,14 @@ +int fact(int x) { + var acc = 1; + while (x > 0) { + acc = acc * x; + x = x - 1; + } + return acc; +} + +int program(int argc, string[] argv) { + print_string(string_of_int(fact(5))); + return 0; +} + diff --git a/hw4/oatprograms/fibo.oat b/hw4/oatprograms/fibo.oat new file mode 100644 index 0000000..e473097 --- /dev/null +++ b/hw4/oatprograms/fibo.oat @@ -0,0 +1,26 @@ +int fibR(int n) { + if(n == 0) {return 0;} + if(n == 1) {return 1;} + return fibR(n - 1) + fibR(n-2); +} + +int fibI(int n) { + var a = 0; + var b = 1; + if(n == 0) {return a;} + if(n == 1) {return b;} + while(n-2 > 0) { + var old = b; + b = b + a; + a = old; + n = n - 1; + } + return a + b; +} + +int program (int argc, string[] argv) +{ + var val = 1; + if(fibR(12) == 144 & fibI(12) == 144) {val = 0;} + return val; +} diff --git a/hw4/oatprograms/float_multiply.oat b/hw4/oatprograms/float_multiply.oat new file mode 100644 index 0000000..2548138 --- /dev/null +++ b/hw4/oatprograms/float_multiply.oat @@ -0,0 +1,52 @@ +global float_len = 2; +int[] determine_shift(int[] float) +{ + var dec = float[1]; + var count = 0; + while(dec > 0) + { + var temp = float[0]; + float[0] = temp << 1; + dec = dec >>> 1; + count = count + 1; + } + var list = new int[2]; + list[0] = float[0] + float[1]; + list[1] = count; + return list; +} + +int[] multiply_floats(int[] f1, int[] f2) +{ + var f1_shifted = determine_shift(f1); + var f2_shifted = determine_shift(f2); + var product = f1_shifted[0] * f2_shifted[0]; + var num_left_shifts = f1_shifted[1] + f2_shifted[1]; + var remainder = 0; + for(var i = 0; i < num_left_shifts; i=i+1;) + { + var lsb = product [&] 1; + var shifted_lsb = lsb << i; + product = product >>> 1; + remainder = remainder + shifted_lsb; + } + var ans = new int[2]; + ans[0] = product; + ans[1] = remainder; + return ans; +} + +int program(int argc, string[] argv) +{ + var pi = new int[2]; + pi[0] = 3; + pi[1] = 14159; + var diameter = new int[2]; + diameter[0] = 20; + diameter[1] = 17; + var prod = multiply_floats(pi, diameter); + print_int(prod[0]); + print_string("."); + print_int(prod[1]); + return 0; +} \ No newline at end of file diff --git a/hw4/oatprograms/gcd.oat b/hw4/oatprograms/gcd.oat new file mode 100644 index 0000000..31b9063 --- /dev/null +++ b/hw4/oatprograms/gcd.oat @@ -0,0 +1,26 @@ +int gcd(int a, int b) { + while (b != 0) { + var t = b; + b = mod(a, b); + a = t; + } + + return a; +} + +int mod (int a, int b) { + + var t = a; + while (t - b >= 0) { + t = t - b; + } + + return t; +} + +int program (int argc, string[] argv) { + var a = 64; + var b = 48; + + return gcd(a, b); +} \ No newline at end of file diff --git a/hw4/oatprograms/globals1.oat b/hw4/oatprograms/globals1.oat new file mode 100644 index 0000000..d6a8c21 --- /dev/null +++ b/hw4/oatprograms/globals1.oat @@ -0,0 +1,5 @@ +global x = 42; + +int program(int argc, string[] args) { + return x; +} diff --git a/hw4/oatprograms/globals2.oat b/hw4/oatprograms/globals2.oat new file mode 100644 index 0000000..8d2705c --- /dev/null +++ b/hw4/oatprograms/globals2.oat @@ -0,0 +1,8 @@ +global y = true; + +int program(int argc, string[] args) { + if (y) { + return 17; + } + return 15; +} diff --git a/hw4/oatprograms/globals3.oat b/hw4/oatprograms/globals3.oat new file mode 100644 index 0000000..f611f99 --- /dev/null +++ b/hw4/oatprograms/globals3.oat @@ -0,0 +1,5 @@ +global arr = int[] null; + +int program(int argc, string[] args) { + return 17; +} diff --git a/hw4/oatprograms/globals4.oat b/hw4/oatprograms/globals4.oat new file mode 100644 index 0000000..24ab285 --- /dev/null +++ b/hw4/oatprograms/globals4.oat @@ -0,0 +1,5 @@ +global arr = new int[]{1, 2, 3, 4}; + +int program(int argc, string[] args) { + return 5; +} diff --git a/hw4/oatprograms/globals5.oat b/hw4/oatprograms/globals5.oat new file mode 100644 index 0000000..0ab9fd5 --- /dev/null +++ b/hw4/oatprograms/globals5.oat @@ -0,0 +1,5 @@ +global s = "hello!"; + +int program(int argc, string[] args) { + return 17; +} diff --git a/hw4/oatprograms/globals6.oat b/hw4/oatprograms/globals6.oat new file mode 100644 index 0000000..58435e1 --- /dev/null +++ b/hw4/oatprograms/globals6.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] args) { + var s = "hello!"; + return 15; +} diff --git a/hw4/oatprograms/globals7.oat b/hw4/oatprograms/globals7.oat new file mode 100644 index 0000000..7645ed2 --- /dev/null +++ b/hw4/oatprograms/globals7.oat @@ -0,0 +1,8 @@ +global arr = new int[] {}; + +int program (int argc, string[] argv) { + var x = new int[3]; + arr = x; + x[2] = 3; + return arr[2]; +} \ No newline at end of file diff --git a/hw4/oatprograms/gnomesort.oat b/hw4/oatprograms/gnomesort.oat new file mode 100644 index 0000000..039fc52 --- /dev/null +++ b/hw4/oatprograms/gnomesort.oat @@ -0,0 +1,35 @@ + +void gnomeSort(int[] a, int len) { + var i = 1; + var j = 2; + + while(i < len) { + if (a[i-1] <= a[i]) { + i = j; + j = j + 1; + } else { + var tmp = a[i-1]; + a[i-1] = a[i]; + a[i] = tmp; + i = i - 1; + + if (i == 0) { + i = j; + j = j + 1; + } + } + } + return; +} + +int program(int argc, string[] argv) { + var arr = new int[]{ 5, 200, 1, 65, 30, 99, 2, 0 }; + var len = 8; + + gnomeSort(arr, len); + for(var i=0; i<8; i=i+1;) { + print_int(arr[i]); + } + + return 0; +} \ No newline at end of file diff --git a/hw4/oatprograms/hashcode.oat b/hw4/oatprograms/hashcode.oat new file mode 100644 index 0000000..c0594fb --- /dev/null +++ b/hw4/oatprograms/hashcode.oat @@ -0,0 +1,25 @@ +/* Java string hash function */ +/* hash = s[0] * 31 ^ (n - 1) + s[1] * 31 ^(n - 2) + ... + s[n-1]*/ + +int program(int argc, string[] argv) { + var s = "aa"; + var h = hash(s); + print_int(h); + return 0; +} + +int hash(string s) { + var int_arr = array_of_string(s); + var length = length_of_string(s); + var hash = 0; + for(var i = 0; i < length; i= i+1;) { + var power = 1; + for(var j = length - i - 1; j > 0; j= j-1;) { + power = power * 31; + } + var char = int_arr[i]; + hash = hash + power * char; + + } + return hash; +} \ No newline at end of file diff --git a/hw4/oatprograms/heap.oat b/hw4/oatprograms/heap.oat new file mode 100644 index 0000000..bc7d8cf --- /dev/null +++ b/hw4/oatprograms/heap.oat @@ -0,0 +1,53 @@ +void min_heapify(int[] array, int i, int len) { + var l = i * 2; + var r = i + 1; + var tmp = 0; + var m = i; + + if (l < len) { + if (array[l] > array[m]) { + m = l; + } + } + + if (r < len) { + if (array[r] > array[m]) { + m = r; + } + } + + if (m != i) { + tmp = array[i]; + array[i] = array[m]; + array[m] = tmp; + + min_heapify(array, m, len); + } + + return; +} + +void make_min_heap(int[] array, int len) { + for (var i = len; i >= 1; i = i - 1;) { + min_heapify(array, i, len); + } + + return; +} + +int program(int argc, string[] argv) { + var array = new int[]{ 0, 9, 1, 2, 8, 10, 7, 3, 6, 4, 5 }; + var end_result = new int[]{ 0, 1, 4, 2, 8, 5, 7, 3, 6, 9, 10 }; + + make_min_heap(array, 10); + + var same = 0; + + for (var i = 0; i < 11; i = i + 1;) { + if (array[i] != end_result[i]) { + same = 1; + } + } + + return same; +} diff --git a/hw4/oatprograms/insertion_sort.oat b/hw4/oatprograms/insertion_sort.oat new file mode 100644 index 0000000..c4bc2ae --- /dev/null +++ b/hw4/oatprograms/insertion_sort.oat @@ -0,0 +1,38 @@ +int[] insert(int[] partial, int len, int insertee) { + var inserted = new int[len+1]; + for (var i=0; i < len+1; i=i+1;) { inserted[i] = -1; } + var not_yet_inserted = true; + if (insertee < partial[0]) { + not_yet_inserted = false; + inserted[0] = insertee; + } + for (var i = 0; i < len; i = i + 1;) { + if (not_yet_inserted) { + if (insertee > partial[i]) { + not_yet_inserted = false; + inserted[i+1] = insertee; + inserted[i] = partial[i]; + } else { + inserted[i] = partial[i]; + } + } else { + inserted[i+1] = partial[i]; + } + } + return inserted; +} + +int[] insort(int[] unsorted, int len) { + var out = new int[]{0}; + out[0] = unsorted[0]; + for (var i = 1; i < len; i = i + 1;) { + out = insert(out, i, unsorted[i]); + } + return out; +} + +int program(int argc, string[] argv) { + var array = new int[]{13, 42, 32, 3, 2, 6}; + var result = insort(array, 6); + return result[5]; +} diff --git a/hw4/oatprograms/is_prime.oat b/hw4/oatprograms/is_prime.oat new file mode 100644 index 0000000..8826357 --- /dev/null +++ b/hw4/oatprograms/is_prime.oat @@ -0,0 +1,31 @@ +global list = int[] {3, 5, 7, 8, 11, 16, 17, 21}; + +bool isPrime (int n) { + if (n < 2) { + return false; + } + + for (var i = 2; i < n; i = i + 1;) + { + var cur_num = n; + while (cur_num >= i) { + cur_num = cur_num - i; + } + + if (cur_num == 0) { + return false; + } + } + return true; +} + +int program (int argc, string[] argv) { + var answer = 0; + for (var i = 0; i < 8; i = i + 1;) + { + if(isPrime(list[i])) { + answer = answer + 1; + } + } + return answer; +} diff --git a/hw4/oatprograms/josh_joyce_test.oat b/hw4/oatprograms/josh_joyce_test.oat new file mode 100644 index 0000000..19e1b49 --- /dev/null +++ b/hw4/oatprograms/josh_joyce_test.oat @@ -0,0 +1,20 @@ +global arr1 = new int[]{1,2,3,4}; +global arr2 = new int[]{1,2,3,5}; + +int arrcheck(int[] ar1, int[] ar2, int len){ + var val = 0; + for(var i =0; i < len; i= i+1;){ + if (ar1[i] != ar2[i]) { + val = 1; + } + } + return val; +} + +int program(int argc, string[] argv) { + + var val = 1; + if(arrcheck(arr1, arr2, 4) == 1) {val = 0;} + return val; + +} diff --git a/hw4/oatprograms/kmp.oat b/hw4/oatprograms/kmp.oat new file mode 100644 index 0000000..7716f51 --- /dev/null +++ b/hw4/oatprograms/kmp.oat @@ -0,0 +1,68 @@ +/* Paul Lou and Tanner Haldeman */ +/* References: Algorithms (Sedgewick), https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm */ + +int[] construct_table(string w) { + var length = length_of_string(w); + var arr_of_w = array_of_string(w); + var t = new int[length]; + var curr = 2; + var next = 0; + + t[0] = -1; + t[1] = 0; + while (curr < length) { + if (arr_of_w[curr-1] == arr_of_w[next]) { + t[curr] = next + 1; + next = next + 1; + curr = curr + 1; + } + else if (next > 0) { + next = t[next]; + } + else { + t[curr] = 0; + curr = curr + 1; + } + } + + return t; +} + + +int kmp(string str, string w) { + var str_idx = 0; + var word_idx = 0; + var word_length = length_of_string(w); + var word_arr = array_of_string(w); + var str_arr = array_of_string(str); + var t = construct_table(w); + + while (str_idx + word_idx < length_of_string(str)) { + if (word_arr[word_idx] == str_arr[str_idx + word_idx]) { + if (word_idx == word_length - 1) { + return str_idx; + } + word_idx = word_idx + 1; + } + else { + if (t[word_idx] > -1) { + str_idx = str_idx + word_idx - t[word_idx]; + word_idx = t[word_idx]; + } + else { + str_idx = str_idx + 1; + word_idx = 0; + } + } + } + + return -1; +} + +int program(int argc, string[] argv) { + var str = "abcdabcdabcdcbab"; + var word = "dabcdc"; + + var ret = kmp(str, word); + return ret; +} diff --git a/hw4/oatprograms/lcs.oat b/hw4/oatprograms/lcs.oat new file mode 100644 index 0000000..2bc752b --- /dev/null +++ b/hw4/oatprograms/lcs.oat @@ -0,0 +1,43 @@ +/** + * Computes longest common subsequence of two strings a and b. + */ +global buf = new int[]{0}; + +string lcs(int i, int j, string a, string b) { + if (i < 0 | j < 0) { + return ""; + } + + var a_chars = array_of_string(a); + var b_chars = array_of_string(b); + + var last_char_a = a_chars[i]; + var last_char_b = b_chars[j]; + + if (last_char_a == last_char_b) { + var prev_lcs = lcs(i - 1, j - 1, a, b); + buf[0] = a_chars[i]; + var next_char = string_of_array(buf); + return string_cat(prev_lcs, next_char); + } + + var left_lcs = lcs(i, j - 1, a, b); + var right_lcs = lcs(i - 1, j, a, b); + + var left_len = length_of_string(left_lcs); + var right_len = length_of_string(right_lcs); + + if (left_len < right_len) { + return right_lcs; + } else { + return left_lcs; + } +} + +int program(int argc, string[] argv) { + var tomato = "TOMATO"; + var orating = "ORATING"; + print_string(lcs(5, 6, tomato, orating)); + return 0; +} + diff --git a/hw4/oatprograms/leastsquare.oat b/hw4/oatprograms/leastsquare.oat new file mode 100644 index 0000000..bb97a72 --- /dev/null +++ b/hw4/oatprograms/leastsquare.oat @@ -0,0 +1,40 @@ + +int program(int argc, string[] argv) { + var n = 500; + return leastsquare(n); +} + +/*finds the least number of squares to sum up to n*/ + +int leastsquare(int n) { + var cache = new int[]{n+1}; + cache[0] = 0; + cache[1] = 1; + cache[2] = 2; + cache[3] = 3; + for (var i = 4; i < n + 1; i=i+1;) { + /*set to some arbitrary high number*/ + cache[i] = i; + + for (var k = 1; k < n; k = k + 1;) { + var temp = k*k; + if (temp > i) { + + } else { + cache[i] = min(cache[i], 1 + cache[i - temp]); + } + } + } + return cache[n]; +} + + + + +int min(int y, int x) { + if (x > y) { + return y; + } else { + return x; + } +} diff --git a/hw4/oatprograms/lfsr.oat b/hw4/oatprograms/lfsr.oat new file mode 100644 index 0000000..f4ee995 --- /dev/null +++ b/hw4/oatprograms/lfsr.oat @@ -0,0 +1,44 @@ +global lfsr_iterations = 5; +global lfsr_length = 4; +global lfsr_init_values = new bool[]{true, false, true, false}; + +bool xor(bool x, bool y) { + return (x & !y) | (!x & y); +} + +string string_of_bool(bool b) { + if (b) { return "T"; } + else { return "F"; } +} + +void print_lfsr(bool[] lfsr_register, int len) { + for (var i = 0; i < len; i = i + 1;) { + print_string(string_of_bool(lfsr_register[i])); + } + return; +} + +int program(int argc, string[] argv) { + /* Initialize the working register */ + var lfsr_register = new bool[lfsr_length]; + for (var i=0; i < lfsr_length; i=i+1;) { + lfsr_register[i] = lfsr_init_values[i]; + } + + /* Do the computations */ + for (var i = 0; i < lfsr_iterations; i = i + 1;) { + var new_first = + xor(lfsr_register[lfsr_length - 1], lfsr_register[lfsr_length - 2]); + for (var j = lfsr_length - 1; j > 0; j = j - 1;) { + lfsr_register[j] = lfsr_register[j - 1]; + } + lfsr_register[0] = new_first; + } + + /* Print the initial and final bool arrays with a space separator */ + print_lfsr(lfsr_init_values, lfsr_length); + print_string(" "); + print_lfsr(lfsr_register, lfsr_length); + + return 0; +} diff --git a/hw4/oatprograms/lfsr2.oat b/hw4/oatprograms/lfsr2.oat new file mode 100644 index 0000000..80d6484 --- /dev/null +++ b/hw4/oatprograms/lfsr2.oat @@ -0,0 +1,15 @@ +global lfsr_length = 4; +global lfsr_init_values = new bool[]{true, false, true, false}; + +void print_lfsr(bool[] lfsr_register, int len) { + for (var i = 0; i < len; i = i + 1;) { + var x = lfsr_register[i]; + } + return; +} + +int program(int argc, string[] argv) { + /* Print the initial and final bool arrays with a space separator */ + print_lfsr(lfsr_init_values, lfsr_length); + return 0; +} diff --git a/hw4/oatprograms/lib10.oat b/hw4/oatprograms/lib10.oat new file mode 100644 index 0000000..19f9cf3 --- /dev/null +++ b/hw4/oatprograms/lib10.oat @@ -0,0 +1,7 @@ +int my_length_of_string (string str) { + return length_of_array (array_of_string (str)); +} + +int program (int argc, string[] argv) { + return my_length_of_string ("Hello?"); +} diff --git a/hw4/oatprograms/lib11.oat b/hw4/oatprograms/lib11.oat new file mode 100644 index 0000000..e152db9 --- /dev/null +++ b/hw4/oatprograms/lib11.oat @@ -0,0 +1,13 @@ +int program (int argc, string[] argv) { + var arr = array_of_string("1234967890"); + var sum = 0; + + for (var i=0; i<10; i=i+1;) { + arr[i] = i; + } + for (var i=0; i<10; i=i+1;) { + sum = sum + arr[i]; + } + + return sum; +} diff --git a/hw4/oatprograms/lib12.oat b/hw4/oatprograms/lib12.oat new file mode 100644 index 0000000..a0d9775 --- /dev/null +++ b/hw4/oatprograms/lib12.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr = oat_alloc_array(10); + return arr[10]; +} + diff --git a/hw4/oatprograms/lib13.oat b/hw4/oatprograms/lib13.oat new file mode 100644 index 0000000..a6e0132 --- /dev/null +++ b/hw4/oatprograms/lib13.oat @@ -0,0 +1,25 @@ +global str1 = "Hello "; + +string string_concat (string str1, string str2) { + var arr1 = array_of_string (str1); + var arr2 = array_of_string (str2); + var len1 = length_of_array (arr1); + var len2 = length_of_array (arr2); + var arr3 = new int[len1+len2]; + var i = 0; + for(var j=0; j= 0) & (j >= 0) & (i < len) & (j < len)) { + return count + board[i][j]; + } else { + return count; + } +} + +int val_at(int[][] board, int i, int j) { + var alive = board[i][j]; + var count = 0; + count = check(board, i-1, j-1, count); + count = check(board, i-1, j , count); + count = check(board, i-1, j+1, count); + + count = check(board, i , j-1, count); + count = check(board, i , j+1, count); + + count = check(board, i+1, j-1, count); + count = check(board, i+1, j , count); + count = check(board, i+1, j+1, count); + + if (alive == 1) { + if (count < 2) { + return 0; + } else if (count < 4) { + return 1; + } + return 0; + } + if (count == 3) { + return 1; + } else { + return 0; + } + return 0; +} + +int program (int argc, string[] argv) { + var board = new int[][]{ new int[]{0, 0, 0, 0}, + new int[]{0, 1, 1, 1}, + new int[]{1, 1, 1, 0}, + new int[]{0, 0, 0, 0} }; + + var new_board = new int[][]{ new int[]{0, 0, 0, 0}, + new int[]{0, 0, 0, 0}, + new int[]{0, 0, 0, 0}, + new int[]{0, 0, 0, 0} }; + for (var i=0; i < 4; i=i+1;) { + new_board[i] = new int[4]; + for (var j=0; j < 4; j=j+1;) { new_board[i][j] = val_at(board, i,j); } + } + + for (var i = 0; i < len; i = i+1;) { + for (var j = 0; j < len; j = j+1;) { + print_int(new_board[i][j]); + } + } + return 0; +} diff --git a/hw4/oatprograms/matrixmult.oat b/hw4/oatprograms/matrixmult.oat new file mode 100644 index 0000000..1560b5d --- /dev/null +++ b/hw4/oatprograms/matrixmult.oat @@ -0,0 +1,69 @@ + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +int program(int argc, string[] argv) +{ + var a = new int[][]{new int[]{1, 3, 4}, + new int[]{2, 0, 1}}; + var b = new int[][]{new int[]{1, 2, 3, 1}, + new int[]{2, 2, 2, 2}, + new int[]{3, 2, 1, 4}}; + var c = new int[][]{new int[]{0, 0, 0, 0}, + new int[]{0, 0, 0, 0}}; + + matrix_Mult(a, b, c); + prnNx4(c, 2); + + matrix_MultAlt(a, b, c); /* alternate form that calls dot3 */ + prnNx4(c, 2); + return 0; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void matrix_Mult(int[][] a1, int [][] a2, int [][] a3) +{ + for(var i = 0; i < 2; i=i+1;) { + for(var j = 0; j < 4; j=j+1;) { + for(var k = 0; k < 3; k=k+1;) { + a3[i][j] = a3[i][j] + a1[i][k] * a2[k][j]; + } + } + } + return; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void matrix_MultAlt(int[][] a1, int[][] a2, int[][] a3) +{ + for(var i = 0; i < 2; i=i+1;) { + for(var j = 0; j < 4; j=j+1;) { + a3[i][j] = dot3(a1, a2, i, j); + } + } + return; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +int dot3(int[][] a1, int[][] a2, int row, int col) +{ + var sum = 0; + for(var k = 0; k < 3; k=k+1;) { + sum = sum + a1[row][k] * a2[k][col]; + } + return sum; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void prnNx4 (int[][] ar, int n) +{ + for(var i = 0; i < n; i=i+1;) + { + for(var j = 0; j < 4; j=j+1;) + { + print_int(ar[i][j]); + print_string (" "); + } + print_string("\t"); + } + return; +} + diff --git a/hw4/oatprograms/maxsubsequence.oat b/hw4/oatprograms/maxsubsequence.oat new file mode 100644 index 0000000..5581eda --- /dev/null +++ b/hw4/oatprograms/maxsubsequence.oat @@ -0,0 +1,26 @@ +int maxsum(int[] arr, int size) { + var maxarr = new int[size]; + var maxs = 0; + maxarr[0] = arr[0]; + for(var i = 0; i < size; i = i+1;){ + for(var j = 0; j < i; j=j+1;){ + if(arr[i] > arr[j] & maxarr[i] < maxarr[j] + arr[i]){ + maxarr[i] = maxarr[j] + arr[i]; + } + } + if(maxs < maxarr[i]){ + maxs = maxarr[i]; + } + } + return maxs; +} + +int program (int argc, string[] argv) { + var array = new int[]{1,101,2,3,101,4,5}; + var max_ans = maxsum(array, 7); + return max_ans; +} + + + + diff --git a/hw4/oatprograms/msort.oat b/hw4/oatprograms/msort.oat new file mode 100644 index 0000000..a786960 --- /dev/null +++ b/hw4/oatprograms/msort.oat @@ -0,0 +1,68 @@ +int program (int argc, string[] argv) { + var i = 0; + var a = new int[]{126,125,124,123,122,121,120,119,118,117}; + print_string (string_of_array(a)); + oat_mergesort(a,0,9); + print_string (" "); + print_string (string_of_array(a)); + print_string (" "); + return i; +} + +void oat_mergesort(int[] a, int low, int high) +{ + var mid=0; + if(low>1; + oat_mergesort(a,low,mid); + oat_mergesort(a,mid+1,high); + merge(a,low,high,mid); + } + return; +} + +void merge(int[] a, int low, int high, int mid) +{ + var i=0; + var j=0; + var k=0; + var c=new int[50]; + i=low; + j=mid+1; + k=low; + while((i<=mid)&(j<=high)) + { + if(a[i]>1; + oat_mergesort(a,low,mid); + oat_mergesort(a,mid+1,high); + merge(a,low,high,mid); + } + return; +} + +void merge(int[] a, int low, int high, int mid) +{ + var i=0; + var j=0; + var k=0; + var c=new int[50]; + i=low; + j=mid+1; + k=low; + while((i<=mid)&(j<=high)) + { + if(a[i]= 0) { + t = t - b; + } + return t; +} + +int div (int a, int b) { + var result = 0; + var num = a; + var denom = b; + while (num > 0) { + num = num - denom; + result = result + 1; + } + return result; +} + +int no_of_factors(int n) { + var num_fact = 1; + var input = n; + for (var i = 2; i * i < input + 1; i=i+1;) { + var power = 0; + while (mod(n, i) == 0) { + n = div(n, i); + power = power + 1; + } + num_fact = num_fact * (power + 1); + } + if (n > 1) { + num_fact = num_fact * 2; + } + return num_fact; +} + +int program (int argc, string[] argv) { + return no_of_factors(6400); +} diff --git a/hw4/oatprograms/path1.oat b/hw4/oatprograms/path1.oat new file mode 100644 index 0000000..8de1752 --- /dev/null +++ b/hw4/oatprograms/path1.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = 17; + return x; +} diff --git a/hw4/oatprograms/path2.oat b/hw4/oatprograms/path2.oat new file mode 100644 index 0000000..c80300b --- /dev/null +++ b/hw4/oatprograms/path2.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var x = 17; + var y = 18; + return x + y; +} diff --git a/hw4/oatprograms/path3.oat b/hw4/oatprograms/path3.oat new file mode 100644 index 0000000..da7f0c9 --- /dev/null +++ b/hw4/oatprograms/path3.oat @@ -0,0 +1,5 @@ +global arr = new int[]{1, 2, 3, 4}; + +int program(int argc, string[] args) { + return arr[2]; +} diff --git a/hw4/oatprograms/phase2_1.oat b/hw4/oatprograms/phase2_1.oat new file mode 100644 index 0000000..d3c10cb --- /dev/null +++ b/hw4/oatprograms/phase2_1.oat @@ -0,0 +1,7 @@ +int x = 3; +string y = "hello"; + +int program(int argc, string[] argv) { + print_string(y); + return 0; +} diff --git a/hw4/oatprograms/qs_bs.oat b/hw4/oatprograms/qs_bs.oat new file mode 100644 index 0000000..3a42712 --- /dev/null +++ b/hw4/oatprograms/qs_bs.oat @@ -0,0 +1,52 @@ +int partition(int[] a, int low_ind, int hi_ind) { + var pivot = a[hi_ind]; + var i = low_ind - 1; + for (var j = low_ind; j < hi_ind; j=j+1;) { + if (a[j] <= pivot) { + i = i + 1; + var atemp1 = a[i]; + a[i] = a[j]; + a[j] = atemp1; + } + } + var atemp2 = a[i+1]; + a[i+1] = a[hi_ind]; + a[hi_ind] = atemp2; + return i+1; +} + +void quicksort(int[] a, int low_ind, int hi_ind) { + if (low_ind < hi_ind) { + var p = partition(a, low_ind, hi_ind); + quicksort(a, low_ind, p-1); + quicksort(a, p+1, hi_ind); + } + return ; +} + +int int_division (int a, int b) { + var btemp = 0; + var i = 0; + while (a > btemp) { + btemp = btemp + b; + i = i + 1; + } + return i; +} + +int binary_search (int[] a, int e, int max, int min) { + var mid = min + int_division (max - min, 2); + if (a[mid] == e) { + return mid; + } + if (a[mid] > e) { + return binary_search (a, e, mid - 1, min); + } + return binary_search (a, e, max, mid + 1); +} + +int program (int argc, string[] argv) { + var a = new int[] {5, 9, 6, 4, 2, 7, 10, 100, 1000, 99, 55, 999, 33, 4, 20}; + quicksort (a, 0, 14); + return binary_search (a, 10, 14, 0) + 7 * binary_search (a, 4, 14, 0) + 23 * binary_search (a, 999, 14, 0); +} \ No newline at end of file diff --git a/hw4/oatprograms/qsort.oat b/hw4/oatprograms/qsort.oat new file mode 100644 index 0000000..f3f439f --- /dev/null +++ b/hw4/oatprograms/qsort.oat @@ -0,0 +1,53 @@ + +void quick_sort( int[] a, int l, int r) +{ + var j=0; + + if( l < r ) + { + /* divide and conquer */ + j = partition( a, l, r); + quick_sort( a, l, j-1); + quick_sort( a, j+1, r); + } + + return; +} + +int partition( int[] a, int l, int r) { + var pivot=a[l]; + var i =l; + var j = r+1; + var t=0; + var done = 0; + + while(done==0) + { + i = i + 1; + while( a[i] <= pivot & i <= r ) { + i = i + 1; + } + j = j - 1; + while( a[j] > pivot ) { + j = j - 1; + } + if( i >= j ) { done=1; } + if (done==0) { + t = a[i]; a[i] = a[j]; a[j] = t; + } + } + t = a[l]; a[l] = a[j]; a[j] = t; + return j; +} + +int program (int argc, string[] argv) { + + var a = new int[]{ 107, 112, 121, 102, 123, 115, 104, 111, 109}; + + print_string (string_of_array (a)); + quick_sort( a, 0, 8); + print_string (string_of_array (a)); + + return 255; +} + diff --git a/hw4/oatprograms/regalloctest.oat b/hw4/oatprograms/regalloctest.oat new file mode 100644 index 0000000..46f2d2b --- /dev/null +++ b/hw4/oatprograms/regalloctest.oat @@ -0,0 +1,24 @@ +int program(int argc, string[] argv) { + var x = 0; + for (var i = 0; i < 10000000; i = i + 1;) { + var a = 0; + var b = a + i; + var c = b + i; + var d = c + i; + var e = d + i; + var f = e + i; + var g = f + i; + var h = g + i; + var j = h + i; + var k = j + i; + var l = k + i; + var m = l + i; + var n = m + i; + var o = n + i; + var p = o + i; + var q = p + i; + var r = q + i; + x = x + r; + } + return x; +} diff --git a/hw4/oatprograms/regalloctest2.oat b/hw4/oatprograms/regalloctest2.oat new file mode 100644 index 0000000..990c425 --- /dev/null +++ b/hw4/oatprograms/regalloctest2.oat @@ -0,0 +1,34 @@ +int foo(int x, int y, int z) { + var a = x + y; + var b = y + z; + return a + b; +} + +int program(int argc, string[] argv) { + var x = 0; + for (var i = 0; i < 10000000; i = i + 1;) { + var a = 0; + var b = a + i; + var c = b + i; + var d = c + i; + d = d + foo(a, b, c); + var e = d + i; + var f = e + i; + var g = f + i; + var h = g + i; + var j = h + i; + j = j + foo(f, g, h); + var k = j + i; + var l = k + i; + var m = l + i; + var n = m + i; + n = n + foo(k, l, m); + var o = n + i; + var p = o + i; + var q = p + i; + var r = q + i; + x = x + r; + } + print_int(x); + return 0; +} diff --git a/hw4/oatprograms/regex.oat b/hw4/oatprograms/regex.oat new file mode 100644 index 0000000..5364401 --- /dev/null +++ b/hw4/oatprograms/regex.oat @@ -0,0 +1,34 @@ +int reg_match(int[] str, int[] reg, int p1, int p2, int last) { + if (str[p1] == 0 & reg[p2] == 0) { + return 1; + } + if (str[p1] == 0 & reg[p2] != 0) { + return 0; + } + if (str[p1] != 0 & reg[p2] == 0) { + return 0; + } + if (reg[p2+1] == 42) { + return reg_match(str, reg, p1, p2+1, reg[p2]); + } + if (reg[p2] == 42) { + var result = reg_match(str, reg, p1, p2+1, 0); + if (result == 1) { + return 1; + } + if (str[p1] == last | last == 46) { + return reg_match(str, reg, p1+1, p2, last); + } + return 0; + } + if (str[p1] == reg[p2] | reg[p2] == 46) { + return reg_match(str, reg, p1+1, p2+1, 0); + } + return 0; +} + +int program(int argc, string[] argv) { + var str = new int[]{97, 98, 99, 99, 99, 99, 99, 100, 101, 102, 0}; + var reg = new int[]{97, 103, 42, 46, 99, 42, 99, 42, 100, 101, 42, 102, 0}; + return reg_match(str, reg, 0, 0, 0); +} diff --git a/hw4/oatprograms/reverse.oat b/hw4/oatprograms/reverse.oat new file mode 100644 index 0000000..d7ab3f9 --- /dev/null +++ b/hw4/oatprograms/reverse.oat @@ -0,0 +1,31 @@ +int mod_ten (int n) { + if (n < 10) { + return n; + } + + return mod_ten (n - 10); +} + +int div_ten (int n) { + var c = 0; + while (n >= 10) { + n = n - 10; + c = c + 1; + } + return c; +} + +int reversed (int n) { + var r = 0; + while (n != 0) { + var n_mod_ten = mod_ten(n); + r = (r * 10) + n_mod_ten; + n = div_ten(n); + } + return r; +} + +int program (int argc, string[] argv) { + var n = 321; + return reversed(n); +} \ No newline at end of file diff --git a/hw4/oatprograms/rod_cutting.oat b/hw4/oatprograms/rod_cutting.oat new file mode 100644 index 0000000..dfe09b6 --- /dev/null +++ b/hw4/oatprograms/rod_cutting.oat @@ -0,0 +1,62 @@ +bool arr_eq(int[] arr1, int[] arr2, int n) { + var flag = true; + for(var i = 0; i < n; i = i + 1;) { + flag = flag & (arr1[i] == arr2[i]); + } + return flag; +} + +void clear_arr(int[] arr, int length) { + for (var i = 0; i < length; i = i + 1;) { arr[i] = 0; } + return; +} + +/* Adapted from CLRS */ +int optimal_cuts (int[] prices, int length, int[] choices) { + var max_price = new int[length + 1]; + max_price[0] = 0; + var first_cut = new int[length + 1]; + clear_arr(first_cut, length + 1); + + for (var j = 1; j <= length; j = j+1;) { + var max_j = 0; + for (var i = 1; i <= j; i = i+1;) { + var new_soln = prices[i] + max_price[j - i]; + if (new_soln > max_j) { + max_j = new_soln; + first_cut[j] = i; + } + } + max_price[j] = max_j; + } + + var n = length; + /* First cut stores the largest optimal cut that can be made */ + /* We can recurse downwards to construct the final answer */ + while (n > 0) { + var cut = first_cut[n]; + choices[cut] = choices[cut] + 1; + n = n - cut; + } + + return max_price[length]; +} + +int program (int argc, string[] argv) { + var prices = new int[] {0, 1, 5, 11, 13, 15, 17, 17, 20, 24, 30}; + var length = 10; + var cuts = new int[length + 1]; + clear_arr(cuts, length + 1); + + var max_price = optimal_cuts(prices, length, cuts); + + var expected_max_price = 35; + var expected_cuts = new int[]{0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0}; + + if (expected_max_price == max_price & + arr_eq(expected_cuts, cuts, length + 1)) { + return max_price; + } else { + return 0; + } +} diff --git a/hw4/oatprograms/run1.oat b/hw4/oatprograms/run1.oat new file mode 100644 index 0000000..a1162e2 --- /dev/null +++ b/hw4/oatprograms/run1.oat @@ -0,0 +1,21 @@ +global i = 42; + +int f(int x) { + return x; +} + +int g(int[] y) { + return y[2]; +} + +int program (int argc, string[] argv) { + var garr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + var arr = new int[]{1, 2, 3, 4}; + var p=0; + + for (var j=0; j<100; j=j+1; ) { + p=p+1; + } + + return g(arr) + f(i) + f(arr[3]) + f(garr[1][1]) + f(p); +} diff --git a/hw4/oatprograms/run10.oat b/hw4/oatprograms/run10.oat new file mode 100644 index 0000000..9b83d8d --- /dev/null +++ b/hw4/oatprograms/run10.oat @@ -0,0 +1,9 @@ +int[] f (int[] arr) { + return arr; +} + +int program (int argc, string[] argv) { + var garr = new int[][] {new int[]{1, 2, 3}, new int[]{4, 5, 6}}; + var arr = f(garr[1]); + return arr[1]; +} diff --git a/hw4/oatprograms/run11.oat b/hw4/oatprograms/run11.oat new file mode 100644 index 0000000..55ade43 --- /dev/null +++ b/hw4/oatprograms/run11.oat @@ -0,0 +1,28 @@ +global i = 1; + +int f(int[] arr) { + return arr[3]; +} + +int[] g() { + var arr = new int[] {99, 1, 99, 99}; + return arr; +} + +int program (int argc, string[] argv) { + var arr1 = new int[] {99, 1, 99}; + var arr2 = new int[][] {new int[]{99,99,99}, + new int[]{99,1,99}, + new int[]{99,99,99}}; + + var c = 1; + var arr4 = g(); + var arr3 = new int[] {99, 99, 99, 1}; + c = c + i; + c = c + arr1[1]; + c = c + arr2[1][1]; + c = c + arr3[3]; + c = c + f(arr3); + c = c + arr4[1]; + return c; +} diff --git a/hw4/oatprograms/run13.oat b/hw4/oatprograms/run13.oat new file mode 100644 index 0000000..ddec733 --- /dev/null +++ b/hw4/oatprograms/run13.oat @@ -0,0 +1,7 @@ +int f(int x, int y) { + return x; +} + +int program (int argc, string[] argv) { + return f(1, 2); +} diff --git a/hw4/oatprograms/run14.oat b/hw4/oatprograms/run14.oat new file mode 100644 index 0000000..836a239 --- /dev/null +++ b/hw4/oatprograms/run14.oat @@ -0,0 +1,19 @@ +int f(int[] a) { + return a[1]; +} + +int g(int x) { + var arr = new int[3]; + for (var i = 0; i < 3; i=i+1;) { arr[i] = x; } + return arr[1]; +} + +int program (int argc, string[] argv) { + var a = new int[3]; + for (var i=0; i < 3; i=i+1;) { a[i] = i; } + var arr = new int[4]; + for (var i=0; i < 4; i=i+1;) { arr[i] = i*i; } + var arr0 = new int[3]; + for (var i=0; i < 3; i=i+1;) { arr0[i] = 2*i; } + return arr[3] + a[1] + f(arr0) + g(4); +} diff --git a/hw4/oatprograms/run15.oat b/hw4/oatprograms/run15.oat new file mode 100644 index 0000000..b2608af --- /dev/null +++ b/hw4/oatprograms/run15.oat @@ -0,0 +1,20 @@ +int f(int[][] a) { + return a[1][1]; +} + +int g(int x) { + var arr = new int[][]{new int[]{x, x, x}, new int[]{x, x, x}, new int[]{x, x, x}}; + return arr[1][1]; +} + +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{0,1,2},new int[]{0,1,2},new int[]{0,1,2}}; + var arr = new int[][]{new int[]{0*0, 0*1, 0*2, 0*3, 0*4}, + new int[]{1*0, 1*1, 1*2, 1*3, 1*4}, + new int[]{2*0, 2*1, 2*2, 2*3, 2*4}, + new int[]{3*0, 3*1, 3*2, 3*3, 3*4}}; + var arr0 = new int[][]{new int[]{0*0, 0*1, 0*2}, + new int[]{1*0, 1*1, 1*2}, + new int[]{2*0, 2*1, 2*2}}; + return arr[3][4] + a[1][2] + f(arr0) + g(4); +} diff --git a/hw4/oatprograms/run16.oat b/hw4/oatprograms/run16.oat new file mode 100644 index 0000000..077d1c2 --- /dev/null +++ b/hw4/oatprograms/run16.oat @@ -0,0 +1,9 @@ +int program (int argc, string[] argv) { + var x = 10; + var a = new int[][]{new int[]{x+0+0, x+0+1, x+0+2}, + new int[]{x+1+0, x+1+1, x+1+2}, + new int[]{x+2+0, x+2+1, x+2+2}}; + + var b = a; + return b[2][1]; +} diff --git a/hw4/oatprograms/run18.oat b/hw4/oatprograms/run18.oat new file mode 100644 index 0000000..793af78 --- /dev/null +++ b/hw4/oatprograms/run18.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{1, 100, 999}; + return a[2]; +} diff --git a/hw4/oatprograms/run19.oat b/hw4/oatprograms/run19.oat new file mode 100644 index 0000000..9c76a76 --- /dev/null +++ b/hw4/oatprograms/run19.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var i=999; + var a = new int[]{1, 100, 999}; + return a[2]; +} diff --git a/hw4/oatprograms/run2.oat b/hw4/oatprograms/run2.oat new file mode 100644 index 0000000..8a2fd49 --- /dev/null +++ b/hw4/oatprograms/run2.oat @@ -0,0 +1,18 @@ +global i=0; + +int f(int x, int y) { + var r = 0; + if (x >= 1) { + r = 1 + f (x-1, y); + } else { + r = x + y; + } + return r; +} + +int program (int argc, string[] argv) { + var x = 3; + var y = 3; + + return f(x, y)+i; +} diff --git a/hw4/oatprograms/run20.oat b/hw4/oatprograms/run20.oat new file mode 100644 index 0000000..6978566 --- /dev/null +++ b/hw4/oatprograms/run20.oat @@ -0,0 +1,6 @@ +int f() {return 19;} + +int program (int argc, string[] argv) { + var a = new int[]{1, 100, 19}; + return a[2]; +} diff --git a/hw4/oatprograms/run21.oat b/hw4/oatprograms/run21.oat new file mode 100644 index 0000000..58bfb4a --- /dev/null +++ b/hw4/oatprograms/run21.oat @@ -0,0 +1,5 @@ + +int program (int argc, string[] argv) { + var i= new int[]{99,0}; + return i[0]; +} diff --git a/hw4/oatprograms/run22.oat b/hw4/oatprograms/run22.oat new file mode 100644 index 0000000..1e4c461 --- /dev/null +++ b/hw4/oatprograms/run22.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var strs = new string[]{"abc", "def"}; + print_string (strs[0]); + return 0; +} diff --git a/hw4/oatprograms/run23.oat b/hw4/oatprograms/run23.oat new file mode 100644 index 0000000..7aa00e6 --- /dev/null +++ b/hw4/oatprograms/run23.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var strs = new string[][]{new string[]{"abc", "def"}, + new string[]{"789", "123"}}; + print_string (strs[1][1]); + return 0; +} diff --git a/hw4/oatprograms/run24.oat b/hw4/oatprograms/run24.oat new file mode 100644 index 0000000..a373076 --- /dev/null +++ b/hw4/oatprograms/run24.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{}; + return 0; +} diff --git a/hw4/oatprograms/run25.oat b/hw4/oatprograms/run25.oat new file mode 100644 index 0000000..330bc97 --- /dev/null +++ b/hw4/oatprograms/run25.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var a = new int[]{110, 110, 110}; + var str = string_of_array (a); + print_string (str); + return 0; +} diff --git a/hw4/oatprograms/run26.oat b/hw4/oatprograms/run26.oat new file mode 100644 index 0000000..4e1f768 --- /dev/null +++ b/hw4/oatprograms/run26.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 0; +} diff --git a/hw4/oatprograms/run27.oat b/hw4/oatprograms/run27.oat new file mode 100644 index 0000000..ad9574f --- /dev/null +++ b/hw4/oatprograms/run27.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var i=99; + return i; +} diff --git a/hw4/oatprograms/run28.oat b/hw4/oatprograms/run28.oat new file mode 100644 index 0000000..25d5676 --- /dev/null +++ b/hw4/oatprograms/run28.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var i=9; + var j=i+i; + return i+i*i-j>>2<<2>>>2; +} diff --git a/hw4/oatprograms/run29.oat b/hw4/oatprograms/run29.oat new file mode 100644 index 0000000..6fb41b6 --- /dev/null +++ b/hw4/oatprograms/run29.oat @@ -0,0 +1,6 @@ +global b=true; +int program (int argc, string[] argv) { + var i=0; + if (b) { i=1; } + return i; +} diff --git a/hw4/oatprograms/run3.oat b/hw4/oatprograms/run3.oat new file mode 100644 index 0000000..3484306 --- /dev/null +++ b/hw4/oatprograms/run3.oat @@ -0,0 +1,6 @@ +global arr = int[] null; + +int program (int argc, string[] argv) { + arr = new int[] {1,2}; + return arr[1]; +} diff --git a/hw4/oatprograms/run30.oat b/hw4/oatprograms/run30.oat new file mode 100644 index 0000000..cb9983f --- /dev/null +++ b/hw4/oatprograms/run30.oat @@ -0,0 +1,4 @@ +global i=9; +int program (int argc, string[] argv) { + return i; +} diff --git a/hw4/oatprograms/run31.oat b/hw4/oatprograms/run31.oat new file mode 100644 index 0000000..c358275 --- /dev/null +++ b/hw4/oatprograms/run31.oat @@ -0,0 +1,5 @@ +global i=9; +int program (int argc, string[] argv) { + var j = i; + return j; +} diff --git a/hw4/oatprograms/run32.oat b/hw4/oatprograms/run32.oat new file mode 100644 index 0000000..ade21f7 --- /dev/null +++ b/hw4/oatprograms/run32.oat @@ -0,0 +1,12 @@ +global i=11; +int f () { + var i=12; + return i; +} +int g() { + var i=10; + return i; +} +int program (int argc, string[] argv) { + return f() + g() + i; +} diff --git a/hw4/oatprograms/run33.oat b/hw4/oatprograms/run33.oat new file mode 100644 index 0000000..7fe7413 --- /dev/null +++ b/hw4/oatprograms/run33.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var b = new bool[]{true, false}; + var i = 0; + if (b[0]) { i = 1; } + return i; +} diff --git a/hw4/oatprograms/run34.oat b/hw4/oatprograms/run34.oat new file mode 100644 index 0000000..7b187f5 --- /dev/null +++ b/hw4/oatprograms/run34.oat @@ -0,0 +1,12 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{0,1,2,3}, + new int[]{4,5,6,7}, + new int[]{8,9,10,11}}; + var s=0; + for(var i=0; i<3; i=i+1;) { + for(var j=0; j<4; j=j+1;) { + s=s+a[i][j]; + } + } + return s; +} diff --git a/hw4/oatprograms/run35.oat b/hw4/oatprograms/run35.oat new file mode 100644 index 0000000..8462f77 --- /dev/null +++ b/hw4/oatprograms/run35.oat @@ -0,0 +1,14 @@ +global a= int[][] null; + +int program (int argc, string[] argv) { + a = new int[][]{new int[]{0,1,2,3}, + new int[]{4,5,6,7}, + new int[]{8,9,10,11}}; + var s=0; + for(var i=0; i<3; i=i+1;) { + for(var j=0; j<4; j=j+1;) { + s=s+a[i][j]; + } + } + return s; +} diff --git a/hw4/oatprograms/run36.oat b/hw4/oatprograms/run36.oat new file mode 100644 index 0000000..3058e90 --- /dev/null +++ b/hw4/oatprograms/run36.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{0,0}; + return a[1]; +} diff --git a/hw4/oatprograms/run37.oat b/hw4/oatprograms/run37.oat new file mode 100644 index 0000000..221d5c6 --- /dev/null +++ b/hw4/oatprograms/run37.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return a[0][1]; +} diff --git a/hw4/oatprograms/run38.oat b/hw4/oatprograms/run38.oat new file mode 100644 index 0000000..5739949 --- /dev/null +++ b/hw4/oatprograms/run38.oat @@ -0,0 +1,12 @@ +int f1() { return f2(); } +int f2() { return f3(); } +int f3() { return f4(); } +int f4() { return f5(); } +int f5() { return f6(); } +int f6() { return f7(); } +int f7() { return f8(); } +int f8() { return f9(); } +int f9() { return 31; } +int program (int argc, string[] argv) { + return f1(); +} diff --git a/hw4/oatprograms/run39.oat b/hw4/oatprograms/run39.oat new file mode 100644 index 0000000..397da9c --- /dev/null +++ b/hw4/oatprograms/run39.oat @@ -0,0 +1,12 @@ +int f1(int i) { return f2(i); } +int f2(int i) { return f3(i); } +int f3(int i) { return f4(i); } +int f4(int i) { return f5(i); } +int f5(int i) { return f6(i); } +int f6(int i) { return f7(i); } +int f7(int i) { return f8(i); } +int f8(int i) { return f9(i); } +int f9(int i) { return i; } +int program (int argc, string[] argv) { + return f1(argc); +} diff --git a/hw4/oatprograms/run4.oat b/hw4/oatprograms/run4.oat new file mode 100644 index 0000000..77c9593 --- /dev/null +++ b/hw4/oatprograms/run4.oat @@ -0,0 +1,6 @@ +global arr = int[] null; + +int program (int argc, string[] argv) { + arr = new int[]{17,42}; + return arr[1]; +} diff --git a/hw4/oatprograms/run40.oat b/hw4/oatprograms/run40.oat new file mode 100644 index 0000000..0af7b53 --- /dev/null +++ b/hw4/oatprograms/run40.oat @@ -0,0 +1,10 @@ +global i=8; +int f() { + var j=0; + j=g(); + return j; +} +int g() {return i;} +int program(int argc, string[] argv) { + return f(); +} diff --git a/hw4/oatprograms/run41.oat b/hw4/oatprograms/run41.oat new file mode 100644 index 0000000..ce3c276 --- /dev/null +++ b/hw4/oatprograms/run41.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5+x6+x7+x8; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw4/oatprograms/run42.oat b/hw4/oatprograms/run42.oat new file mode 100644 index 0000000..afaa70d --- /dev/null +++ b/hw4/oatprograms/run42.oat @@ -0,0 +1,16 @@ +int program(int argc, string[] argv) { + var a1=new int[][]{new int[1],new int[1],new int[1]}; + var a2=new int[][]{new int[1],new int[1],new int[1]}; + var a3=new int[][]{new int[1],new int[1],new int[1]}; + var a4=new int[][]{new int[1],new int[1],new int[1]}; + var a5=new int[]{0, 1, 2}; + a2[0] = a5; + a2[0][0] = 2; + a1 = a2; + a3 = a1; + a1 = a4; + a2 = a3; + a4 = a2; + a3 = a4; + return a3[0][0]; +} diff --git a/hw4/oatprograms/run43.oat b/hw4/oatprograms/run43.oat new file mode 100644 index 0000000..04e74a7 --- /dev/null +++ b/hw4/oatprograms/run43.oat @@ -0,0 +1,35 @@ +global a = int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] null; + +int program (int argc, string[] argv) { + a = new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][]{ + new int[][][][][][][][][][][]{ + new int[][][][][][][][][][]{ + new int[][][][][][][][][]{ + new int[][][][][][][][]{ + new int[][][][][][][]{ + new int[][][][][][]{ + new int[][][][][]{ + new int[][][][]{ + new int[][][]{ + new int[][]{ + new int[]{42}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + return a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]; +} diff --git a/hw4/oatprograms/run44.oat b/hw4/oatprograms/run44.oat new file mode 100644 index 0000000..3addb73 --- /dev/null +++ b/hw4/oatprograms/run44.oat @@ -0,0 +1,19 @@ +global str = string[][][][][][][][][][] null; + +int program (int argc, string[] argv) { + str = new string[][][][][][][][][][]{ + new string[][][][][][][][][]{ + new string[][][][][][][][]{ + new string[][][][][][][]{ + new string[][][][][][]{ + new string[][][][][]{ + new string[][][][]{ + new string[][][]{ + new string[][]{ + new string[]{ + "hello"}}}}}}}}}}; + + print_string (str[0][0][0][0][0][0][0][0][0][0]); + return 0; +} + diff --git a/hw4/oatprograms/run45.oat b/hw4/oatprograms/run45.oat new file mode 100644 index 0000000..02eade4 --- /dev/null +++ b/hw4/oatprograms/run45.oat @@ -0,0 +1,37 @@ +global a = string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] null; + + +int program (int argc, string[] argv) { + a = new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][]{ + new string[][][][][][][][][][][]{ + new string[][][][][][][][][][]{ + new string[][][][][][][][][]{ + new string[][][][][][][][]{ + new string[][][][][][][]{ + new string[][][][][][]{ + new string[][][][][]{ + new string[][][][]{ + new string[][][]{ + new string[][]{ + new string[]{"42"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + print_string (a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]); + return 0; +} diff --git a/hw4/oatprograms/run46.oat b/hw4/oatprograms/run46.oat new file mode 100644 index 0000000..12dcdf0 --- /dev/null +++ b/hw4/oatprograms/run46.oat @@ -0,0 +1,37 @@ + +int program (int argc, string[] argv) { +var a = + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][]{ + new string[][][][][][][][][][][]{ + new string[][][][][][][][][][]{ + new string[][][][][][][][][]{ + new string[][][][][][][][]{ + new string[][][][][][][]{ + new string[][][][][][]{ + new string[][][][][]{ + new string[][][][]{ + new string[][][]{ + new string[][]{ + new string[]{"42"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + + print_string (a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]); + return 0; +} diff --git a/hw4/oatprograms/run47.oat b/hw4/oatprograms/run47.oat new file mode 100644 index 0000000..631b9fc --- /dev/null +++ b/hw4/oatprograms/run47.oat @@ -0,0 +1,13 @@ +global a = 1; + +int f() { + a = a + 1; + return a; +} + +int program (int argc, string[] argv) { + var b = new int[f()]; + b[0] = 0; + b[1] = 1; + return a + b[0] + b[1]; +} diff --git a/hw4/oatprograms/run48.oat b/hw4/oatprograms/run48.oat new file mode 100644 index 0000000..0eaf3bb --- /dev/null +++ b/hw4/oatprograms/run48.oat @@ -0,0 +1,13 @@ +global a = 1; + +int f() { + a = a + 1; + return a; +} + +int program (int argc, string[] argv) { + var b = new int[f()]; + b[0] = f(); + b[1] = f(); + return a + b[0] + b[1]; +} diff --git a/hw4/oatprograms/run49.oat b/hw4/oatprograms/run49.oat new file mode 100644 index 0000000..b53b94f --- /dev/null +++ b/hw4/oatprograms/run49.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + print_string ("abc"); + return 0; +} diff --git a/hw4/oatprograms/run5.oat b/hw4/oatprograms/run5.oat new file mode 100644 index 0000000..2dfbfec --- /dev/null +++ b/hw4/oatprograms/run5.oat @@ -0,0 +1,6 @@ +global arr= int[][] null; + +int program (int argc, string[] argv) { + arr = new int[][] {new int[]{1,2}, new int[]{3,4}}; + return arr[1][1]; +} diff --git a/hw4/oatprograms/run50.oat b/hw4/oatprograms/run50.oat new file mode 100644 index 0000000..3f26739 --- /dev/null +++ b/hw4/oatprograms/run50.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + print_string ("abcde"); + return 0; +} diff --git a/hw4/oatprograms/run51.oat b/hw4/oatprograms/run51.oat new file mode 100644 index 0000000..19af8e5 --- /dev/null +++ b/hw4/oatprograms/run51.oat @@ -0,0 +1,8 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5+x6+x7+x8; +} +int program (int argc, string[] argv) { + var x = f(1,2,3,4,5,-5,-4,-3); + print_int(x); + return 41; +} diff --git a/hw4/oatprograms/run52.oat b/hw4/oatprograms/run52.oat new file mode 100644 index 0000000..8347c0c --- /dev/null +++ b/hw4/oatprograms/run52.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw4/oatprograms/run53.oat b/hw4/oatprograms/run53.oat new file mode 100644 index 0000000..5e9a98d --- /dev/null +++ b/hw4/oatprograms/run53.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var str = string_of_array (new int[]{110, 110, 110}); + print_string (str); + return 0; +} diff --git a/hw4/oatprograms/run54.oat b/hw4/oatprograms/run54.oat new file mode 100644 index 0000000..238febe --- /dev/null +++ b/hw4/oatprograms/run54.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw4/oatprograms/run55.oat b/hw4/oatprograms/run55.oat new file mode 100644 index 0000000..34c756c --- /dev/null +++ b/hw4/oatprograms/run55.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw4/oatprograms/run56.oat b/hw4/oatprograms/run56.oat new file mode 100644 index 0000000..8c9daa5 --- /dev/null +++ b/hw4/oatprograms/run56.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x4; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw4/oatprograms/run6.oat b/hw4/oatprograms/run6.oat new file mode 100644 index 0000000..d30dd17 --- /dev/null +++ b/hw4/oatprograms/run6.oat @@ -0,0 +1,6 @@ +global arr= int[][] null; + +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return arr[0][0]; +} diff --git a/hw4/oatprograms/run60.oat b/hw4/oatprograms/run60.oat new file mode 100644 index 0000000..65469d6 --- /dev/null +++ b/hw4/oatprograms/run60.oat @@ -0,0 +1,6 @@ +global i = 3; + +int program(int argc, string[] argv) { + i = 42; + return i; +} diff --git a/hw4/oatprograms/run61.oat b/hw4/oatprograms/run61.oat new file mode 100644 index 0000000..c62c899 --- /dev/null +++ b/hw4/oatprograms/run61.oat @@ -0,0 +1,6 @@ +global s = "42"; + +int program(int argc, string[] argv) { + print_string(s); + return 0; +} diff --git a/hw4/oatprograms/run7.oat b/hw4/oatprograms/run7.oat new file mode 100644 index 0000000..3c7afe2 --- /dev/null +++ b/hw4/oatprograms/run7.oat @@ -0,0 +1,6 @@ +global arr = int[][][] null; + +int program (int argc, string[] argv) { + arr = new int[][][]{new int[][]{new int[]{1,2}, new int[]{3,4}}, new int[][]{new int[]{5}}, new int[][]{new int[]{10,20}, new int[]{30,40}}}; + return arr[2][0][1]; +} diff --git a/hw4/oatprograms/run8.oat b/hw4/oatprograms/run8.oat new file mode 100644 index 0000000..548ca08 --- /dev/null +++ b/hw4/oatprograms/run8.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr= new int[] {1,2}; + + return arr[1]; +} diff --git a/hw4/oatprograms/run9.oat b/hw4/oatprograms/run9.oat new file mode 100644 index 0000000..197f527 --- /dev/null +++ b/hw4/oatprograms/run9.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr=new int[][] {new int []{1,2}, new int[]{3,4}}; + + return arr[1][1]; +} diff --git a/hw4/oatprograms/runtime-fail1.oat b/hw4/oatprograms/runtime-fail1.oat new file mode 100644 index 0000000..a0cdc50 --- /dev/null +++ b/hw4/oatprograms/runtime-fail1.oat @@ -0,0 +1,6 @@ +global arr = int[][] null; + +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return arr[1][3]; +} diff --git a/hw4/oatprograms/runtime-fail2.oat b/hw4/oatprograms/runtime-fail2.oat new file mode 100644 index 0000000..4d54f38 --- /dev/null +++ b/hw4/oatprograms/runtime-fail2.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{}; + return a[0]; +} diff --git a/hw4/oatprograms/runtime-fail3.oat b/hw4/oatprograms/runtime-fail3.oat new file mode 100644 index 0000000..2ad327c --- /dev/null +++ b/hw4/oatprograms/runtime-fail3.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{0,0}; + return a[-1]; +} diff --git a/hw4/oatprograms/runtime-fail4.oat b/hw4/oatprograms/runtime-fail4.oat new file mode 100644 index 0000000..5e27495 --- /dev/null +++ b/hw4/oatprograms/runtime-fail4.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{0,0}, new int[]{0,0}}; + return a[1][3]; +} diff --git a/hw4/oatprograms/selectionsort.oat b/hw4/oatprograms/selectionsort.oat new file mode 100644 index 0000000..71b9252 --- /dev/null +++ b/hw4/oatprograms/selectionsort.oat @@ -0,0 +1,38 @@ +int getminindex(int[] a, int s, int b) +{ + var i=s; + var min=a[s]; + var mi=s; + for(; i < b; i=i+1;) + { + if ( a[i] < min ) { min = a[i]; mi = i; } + } + return mi; +} + +void selectionsort(int[] a, int s) +{ + var t=0; + var mi=0; + for(var i=0; i= w | j >= h) { + return 100; + } + if (i == w-1 & j == h-1) { + dp[i][j] = matrix[i][j]; + return dp[i][j]; + } + if (dp[i][j] != 0) { + return dp[i][j]; + } + var go_down_val = shortest_path_dp(matrix, dp, i, j+1, w, h); + var go_right_val = shortest_path_dp(matrix, dp, i+1, j, w, h); + if (go_down_val < go_right_val) { + dp[i][j] = go_down_val + matrix[i][j]; + } else { + dp[i][j] = go_right_val + matrix[i][j]; + } + return dp[i][j]; +} + +int program(int argc, string[] argv) { + var matrix = new int[][5]; + for (var i = 0; i < 5; i=i+1;) { + matrix[i] = new int[5]; + } + for (var i = 0; i < 5; i=i+1;) { + for (var j = 0; j < 5; j=j+1;) { + matrix[i][j] = 2*(i+1) + (j+1); + } + } + matrix[0][4] = 50; + matrix[1][3] = 50; + matrix[2][2] = 50; + return shortest_path(matrix, 5, 5); +} \ No newline at end of file diff --git a/hw4/oatprograms/sieve.oat b/hw4/oatprograms/sieve.oat new file mode 100644 index 0000000..56ee38f --- /dev/null +++ b/hw4/oatprograms/sieve.oat @@ -0,0 +1,30 @@ +int sieve(int n) { + var arr = new bool[n]; + for (var i=0; i < n; i=i+1;) { arr[i] = true; } + + arr[0] = false; + arr[1] = false; + + for(var i = 0; i < n; i=i+1;) { + if(arr[i]){ + for(var j = i * 2; j < n; j=j+i;){ + arr[j] = false; + } + } + } + +var count = 0; + for(var i = 0; i < n; i=i+1;){ + if(arr[i]) { + count = count + 1; + } + } + + return count; + +} + +int program(int argc, string[] argv) { + var n = 100; + return sieve(n); +} diff --git a/hw4/oatprograms/sqrt.oat b/hw4/oatprograms/sqrt.oat new file mode 100644 index 0000000..9eed049 --- /dev/null +++ b/hw4/oatprograms/sqrt.oat @@ -0,0 +1,44 @@ +global l2 = int[]{8, 9, 10, 11, 12, 13, 14, 15}; + +int sqrt (int n) { + if (n < 0) { + return 0; + } + + var s = 0; + while (n > 0) { + var d = s * s; + if (d > n) { + n = -1; + } else { + s = s + 1; + } + } + return s - 1; +} + +int sum (int[] l) { + var sum = 0; + for (var i = 0; i < 8; i = i + 1;) { + sum = sum + l[i]; + } + return sum; +} + +int program (int argc, string[] argv) { + var l1 = new int[8]; + l1[0] = 0; + l1[1] = 1; + l1[2] = 2; + l1[3] = 3; + l1[4] = 4; + l1[5] = 5; + l1[6] = 6; + l1[7] = 7; + + var s1 = sum(l1); + var s2 = sum(l2); + var s = s1 + s2; + var rt = sqrt(s); + return rt; +} \ No newline at end of file diff --git a/hw4/oatprograms/tc1.oat b/hw4/oatprograms/tc1.oat new file mode 100644 index 0000000..7d1dd22 --- /dev/null +++ b/hw4/oatprograms/tc1.oat @@ -0,0 +1 @@ +global i = true; diff --git a/hw4/oatprograms/tc10.oat b/hw4/oatprograms/tc10.oat new file mode 100644 index 0000000..82952d5 --- /dev/null +++ b/hw4/oatprograms/tc10.oat @@ -0,0 +1,3 @@ +bool f(int[] a){ + return !a; +} diff --git a/hw4/oatprograms/tc11.oat b/hw4/oatprograms/tc11.oat new file mode 100644 index 0000000..9892ac1 --- /dev/null +++ b/hw4/oatprograms/tc11.oat @@ -0,0 +1,3 @@ +int f() { + return !0; +} diff --git a/hw4/oatprograms/tc12.oat b/hw4/oatprograms/tc12.oat new file mode 100644 index 0000000..1cb5a9c --- /dev/null +++ b/hw4/oatprograms/tc12.oat @@ -0,0 +1,5 @@ +void f() {return;} +void g() { + int i = f(); + return; +} diff --git a/hw4/oatprograms/tc13.oat b/hw4/oatprograms/tc13.oat new file mode 100644 index 0000000..2cb74ea --- /dev/null +++ b/hw4/oatprograms/tc13.oat @@ -0,0 +1,6 @@ +int f() {return 0;} + +int g() { + f(); + return 0; +} diff --git a/hw4/oatprograms/tc14.oat b/hw4/oatprograms/tc14.oat new file mode 100644 index 0000000..f81d7eb --- /dev/null +++ b/hw4/oatprograms/tc14.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{"hello"}; + return 0; +} diff --git a/hw4/oatprograms/tc15.oat b/hw4/oatprograms/tc15.oat new file mode 100644 index 0000000..63751e7 --- /dev/null +++ b/hw4/oatprograms/tc15.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new string[]{1}; + return 0; +} diff --git a/hw4/oatprograms/tc16.oat b/hw4/oatprograms/tc16.oat new file mode 100644 index 0000000..0a9ee44 --- /dev/null +++ b/hw4/oatprograms/tc16.oat @@ -0,0 +1,5 @@ +int f ( int x ) { + var x = 0; + x = x + x - x * x >> x << x | x & -~!x >>> x; + return x; +} diff --git a/hw4/oatprograms/tc17.oat b/hw4/oatprograms/tc17.oat new file mode 100644 index 0000000..deb1c95 --- /dev/null +++ b/hw4/oatprograms/tc17.oat @@ -0,0 +1,4 @@ +void f() { + var x = length_of_array(3); + return; +} diff --git a/hw4/oatprograms/tc18.oat b/hw4/oatprograms/tc18.oat new file mode 100644 index 0000000..815a7ab --- /dev/null +++ b/hw4/oatprograms/tc18.oat @@ -0,0 +1,3 @@ +int g() { + return f(); +} diff --git a/hw4/oatprograms/tc19.oat b/hw4/oatprograms/tc19.oat new file mode 100644 index 0000000..92fd7f4 --- /dev/null +++ b/hw4/oatprograms/tc19.oat @@ -0,0 +1,4 @@ +int f(int x, int y) {return 0;} +int g() { + return f(0); +} diff --git a/hw4/oatprograms/tc2.oat b/hw4/oatprograms/tc2.oat new file mode 100644 index 0000000..9e21e6c --- /dev/null +++ b/hw4/oatprograms/tc2.oat @@ -0,0 +1 @@ +global a = int[] null; diff --git a/hw4/oatprograms/tc20.oat b/hw4/oatprograms/tc20.oat new file mode 100644 index 0000000..39cdb24 --- /dev/null +++ b/hw4/oatprograms/tc20.oat @@ -0,0 +1,5 @@ +void f(int x, int y) {return;} +int g() { + f(0,1,2); + return 0; +} diff --git a/hw4/oatprograms/tc3.oat b/hw4/oatprograms/tc3.oat new file mode 100644 index 0000000..eb88f43 --- /dev/null +++ b/hw4/oatprograms/tc3.oat @@ -0,0 +1,5 @@ +bool f(int a) { + var b = true; + if (a) { b=true; } else { b=false; } + return b; +} diff --git a/hw4/oatprograms/tc4.oat b/hw4/oatprograms/tc4.oat new file mode 100644 index 0000000..2aa04a5 --- /dev/null +++ b/hw4/oatprograms/tc4.oat @@ -0,0 +1,3 @@ +int f() { + return false + 1; +} diff --git a/hw4/oatprograms/tc5.oat b/hw4/oatprograms/tc5.oat new file mode 100644 index 0000000..200f638 --- /dev/null +++ b/hw4/oatprograms/tc5.oat @@ -0,0 +1,3 @@ +int f() { + return (false * true); +} diff --git a/hw4/oatprograms/tc6.oat b/hw4/oatprograms/tc6.oat new file mode 100644 index 0000000..5bf7f21 --- /dev/null +++ b/hw4/oatprograms/tc6.oat @@ -0,0 +1,3 @@ +int f(int i) {return i;} + +int g(int j) {return g(true);} diff --git a/hw4/oatprograms/tc7.oat b/hw4/oatprograms/tc7.oat new file mode 100644 index 0000000..fbf91fa --- /dev/null +++ b/hw4/oatprograms/tc7.oat @@ -0,0 +1,6 @@ +int f() {return 0;} + +int g() { + for(; f(); ){} + return 0; +} diff --git a/hw4/oatprograms/tc8.oat b/hw4/oatprograms/tc8.oat new file mode 100644 index 0000000..c290fc6 --- /dev/null +++ b/hw4/oatprograms/tc8.oat @@ -0,0 +1,5 @@ +void f() { + var a = int[]{1}; + while (a) {} + return; +} diff --git a/hw4/oatprograms/tc9.oat b/hw4/oatprograms/tc9.oat new file mode 100644 index 0000000..cfd5675 --- /dev/null +++ b/hw4/oatprograms/tc9.oat @@ -0,0 +1,4 @@ +int f() { + var a = 1; + return; +} diff --git a/hw4/oatprograms/tc_ok1.oat b/hw4/oatprograms/tc_ok1.oat new file mode 100644 index 0000000..b1642b8 --- /dev/null +++ b/hw4/oatprograms/tc_ok1.oat @@ -0,0 +1 @@ +int f (int f) {return f;} diff --git a/hw4/oatprograms/tc_ok2.oat b/hw4/oatprograms/tc_ok2.oat new file mode 100644 index 0000000..aaa2314 --- /dev/null +++ b/hw4/oatprograms/tc_ok2.oat @@ -0,0 +1 @@ +int f() {var f=0; return f;} diff --git a/hw4/oatprograms/tc_ok4.oat b/hw4/oatprograms/tc_ok4.oat new file mode 100644 index 0000000..1b7a1d3 --- /dev/null +++ b/hw4/oatprograms/tc_ok4.oat @@ -0,0 +1,5 @@ +int f() { + var i = 0; + var arr = new int[3]{j -> 0}; + return i; +} diff --git a/hw4/oatprograms/tc_ok5.oat b/hw4/oatprograms/tc_ok5.oat new file mode 100644 index 0000000..bf9c71a --- /dev/null +++ b/hw4/oatprograms/tc_ok5.oat @@ -0,0 +1,6 @@ +global i = true; + +int f() { + var i = 0; + return i; +} diff --git a/hw4/oatprograms/tc_ok6.oat b/hw4/oatprograms/tc_ok6.oat new file mode 100644 index 0000000..29b6aa2 --- /dev/null +++ b/hw4/oatprograms/tc_ok6.oat @@ -0,0 +1,27 @@ +int f() { + var i1 = 3 + 4; + var i2 = 3 * 4; + var i3 = 3 - 4; + + var b1 = 3 == 4; + var b2 = 3 != 4; + var b6 = 3 < 4; + var b7 = 3 <= 4; + var b8 = 3 > 4; + var b9 = 3 >= 4; + + var i4 = 3 [&] 4; + var b10 = true & false; + + var i5 = 3 [|] 4; + var b11 = true | false; + + var i6 = 3 << 4; + var i7 = 3 >> 4; + var i8 = 3 >>> 4; + + var i9 = - 3; + var i10 = ~ 4; + var b12 = !false; + return 0; +} diff --git a/hw4/oatprograms/tc_ok7.oat b/hw4/oatprograms/tc_ok7.oat new file mode 100644 index 0000000..40fbba1 --- /dev/null +++ b/hw4/oatprograms/tc_ok7.oat @@ -0,0 +1,7 @@ +int f() { + return g(); +} + +int g() { + return f(); +} diff --git a/hw4/oatprograms/tc_ok8.oat b/hw4/oatprograms/tc_ok8.oat new file mode 100644 index 0000000..73e78f1 --- /dev/null +++ b/hw4/oatprograms/tc_ok8.oat @@ -0,0 +1,10 @@ +int f() { + var a1 = new int[]{1, 2, 3}; + var b = new string[]{"a", "b", "c", "d"}; + var s = string_of_array(a1); + var a2 = array_of_string("abc"); + print_string("hello"); + print_int(3); + print_bool(true); + return 0; +} diff --git a/hw4/oatprograms/toascii.oat b/hw4/oatprograms/toascii.oat new file mode 100644 index 0000000..57478c2 --- /dev/null +++ b/hw4/oatprograms/toascii.oat @@ -0,0 +1,67 @@ +/* +Takes a .gim graphics file; +prints a simple ascii representation of the colors. +Optimized for light-text-on-dark-background terminals +(inverts the colors), and subsamples the height by .5 +to better maintain aspect ratio of square files. +*/ + +int program (int argc, string[] argv) { + var s = argv[1]; + var width = get_width(s); + var height = get_height(s); + var bytes = load_image(s); + print_string(string_of_int(width)); + print_string("x"); + print_string(string_of_int(height)); + print_string("\n"); + var rowlen = 0; + var row = new int[width]; + var off = 1; + for (var i=0; i < width*height; i=i+1;) { + /*print_string(string_of_int(i)); + print_string("x"); + print_string(string_of_int(rowlen)); + print_string("x"); + print_string(string_of_int(width)); + print_string("x"); + print_string(string_of_int(bytes[i])); + print_string("\n");*/ + if (bytes[i] > 230) { + row[rowlen] = 64; /* @ */ + } else if (bytes[i] > 204) { + row[rowlen] = 37; /* % */ + } else if (bytes[i] > 179) { + row[rowlen] = 35; /* # */ + } else if (bytes[i] > 153) { + row[rowlen] = 42; /* * */ + } else if (bytes[i] > 128) { + row[rowlen] = 43; /* + */ + } else if (bytes[i] > 102) { + row[rowlen] = 61; /* = */ + } else if (bytes[i] > 77) { + row[rowlen] = 58; /* : */ + } else if (bytes[i] > 51) { + row[rowlen] = 45; /* - */ + } else if (bytes[i] > 26) { + row[rowlen] = 46; /* . */ + } else { + row[rowlen] = 32; /* */ + } + if (rowlen == width-1) { + var test = off [&] 1; + if (test == 1) { + print_string(string_of_array(row)); + print_string("\n"); + off = 0; + + } else { + off = 1; + } + rowlen = 0; + } else { + rowlen = rowlen + 1; + } + } + return 0; +} diff --git a/hw4/oatprograms/toposort.oat b/hw4/oatprograms/toposort.oat new file mode 100644 index 0000000..94ecac0 --- /dev/null +++ b/hw4/oatprograms/toposort.oat @@ -0,0 +1,51 @@ +/* 0 is white, 1 is gray, 2 is black */ +global color = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global startTimes = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global finishTimes = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global topoSort = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global numVertices = 16; +global index = 15; + +void dfs(int[][] adj) { + + for (var i = 0; i < numVertices; i=i+1;) { + if (color[i] == 0) { + dfsHelper(adj, i, 0); + } + } + return; +} + +void dfsHelper(int[][] adj, int s, int t) { + color[s] = 1; + startTimes[s] = t; + + var stringRep = string_of_array(adj[s]); + var length = length_of_string(stringRep); + + for (var i = 0; i < length; i=i+1;) { + var neighbor = adj[s][i]; + if (color[neighbor] == 0) { + dfsHelper(adj, neighbor, t + 1); + } + } + + color[s] = 2; + finishTimes[s] = t + 1; + topoSort[index] = s; + index = index - 1; + + return; +} + +int program(int argc, string[] argv) { + /* Graph taken from https://i.stack.imgur.com/zuLmn.png */ + var adjList = new int[][]{new int[]{7, 10, 13, 14}, new int[]{2, 9, 13}, new int[]{10, 12, 13, 14}, new int[]{6, 8, 9, 11}, new int[]{7}, new int[]{6, 7, 9, 10}, new int[]{15}, new int[]{14}, new int[]{15}, new int[]{11, 14}, new int[]{14}, new int[]{}, new int[]{}, new int[]{}, new int[]{}, new int[]{}}; + dfs(adjList); + for (var i = 0; i < numVertices; i=i+1;) { + print_int(topoSort[i]); + print_string (" "); + } + print_string ("-"); + return 0; +} diff --git a/hw4/oatprograms/union_find.oat b/hw4/oatprograms/union_find.oat new file mode 100644 index 0000000..c550a9e --- /dev/null +++ b/hw4/oatprograms/union_find.oat @@ -0,0 +1,58 @@ +int[] create_ufind(int len) +{ + var arr = new int[len]; + for(var i = 0; i < len; i = i + 1;) + { + arr[i] = i; + } + return arr; + +} + +void union(int[] comps, int u, int v) +{ + var cU = find(comps, u); + var cV = find(comps, v); + + if(cU == cV) + { + return; + } + + comps[cU] = cV; + return; +} + +int find(int[] comps, int u) +{ + var root = u; + while(root != comps[root]) + { + root = comps[root]; + } + + while(u != root) + { + var parent = comps[u]; + comps[u] = root; + u = parent; + + } + + return root; + +} + +int program (int argc, string[] argv) { + var uf = create_ufind(8); + union(uf, 0, 7); + union(uf, 1, 6); + union(uf, 2, 5); + union(uf, 5, 0); + + for(var i = 0; i < 8; i = i + 1;){ + print_int(find(uf, i)); + print_string(" "); + } + return 0; +} diff --git a/hw4/oatprograms/xor_bool.oat b/hw4/oatprograms/xor_bool.oat new file mode 100644 index 0000000..d8b6b5c --- /dev/null +++ b/hw4/oatprograms/xor_bool.oat @@ -0,0 +1,17 @@ +bool xor(bool x, bool y) { + return (x & !y) | (!x & y); +} + +int to_int(bool b) { + if (b) { + return 1; + } else { + return 0; + } +} + +int program(int argc, string[] argv) { + var t = true; + var f = false; + return to_int(xor(t, t)); +} \ No newline at end of file diff --git a/hw4/oatprograms/xor_shift.oat b/hw4/oatprograms/xor_shift.oat new file mode 100644 index 0000000..3b81f31 --- /dev/null +++ b/hw4/oatprograms/xor_shift.oat @@ -0,0 +1,27 @@ +int xor (int x, int y) { + return ~(x [&] y) [&] (x [|] y); +} + +int xor_shift_plus (int[] s) { + var x = s[0]; + var y = s[1]; + + s[0] = y; + x = xor(x, x << 23); + x = xor(x, x >> 17); + x = xor(x, xor(y, y >> 26)); + s[1] = x; + + return x + y; +} + +int program (int argc, string[] argv) { + var seed = new int[2]; + for (var i=0; i < 2; i=i+1;) { seed[i] = 100 * (i + 1); } + + print_int(xor_shift_plus(seed)); + print_string("\n"); + print_int(xor_shift_plus(seed)); + + return 0; +} \ No newline at end of file diff --git a/hw4/parser.mly b/hw4/parser.mly new file mode 100644 index 0000000..2d08289 --- /dev/null +++ b/hw4/parser.mly @@ -0,0 +1,149 @@ +%{ +open Ast + +let loc (startpos:Lexing.position) (endpos:Lexing.position) (elt:'a) : 'a node = + { elt ; loc=Range.mk_lex_range startpos endpos } + +%} + +/* Declare your tokens here. */ +%token EOF +%token INT +%token NULL +%token STRING +%token IDENT + +%token TINT /* int */ +%token TVOID /* void */ +%token TSTRING /* string */ +%token IF /* if */ +%token ELSE /* else */ +%token WHILE /* while */ +%token RETURN /* return */ +%token VAR /* var */ +%token SEMI /* ; */ +%token COMMA /* , */ +%token LBRACE /* { */ +%token RBRACE /* } */ +%token PLUS /* + */ +%token DASH /* - */ +%token STAR /* * */ +%token EQEQ /* == */ +%token EQ /* = */ +%token LPAREN /* ( */ +%token RPAREN /* ) */ +%token LBRACKET /* [ */ +%token RBRACKET /* ] */ +%token TILDE /* ~ */ +%token BANG /* ! */ +%token GLOBAL /* global */ + +%left PLUS DASH +%left STAR +%nonassoc BANG +%nonassoc TILDE +%nonassoc LBRACKET +%nonassoc LPAREN + +/* ---------------------------------------------------------------------- */ + +%start prog +%start exp_top +%start stmt_top +%type exp_top +%type stmt_top + +%type prog +%type exp +%type stmt +%type block +%type ty +%% + +exp_top: + | e=exp EOF { e } + +stmt_top: + | s=stmt EOF { s } + +prog: + | p=list(decl) EOF { p } + +decl: + | GLOBAL name=IDENT EQ init=gexp SEMI + { Gvdecl (loc $startpos $endpos { name; init }) } + | frtyp=ret_ty fname=IDENT LPAREN args=arglist RPAREN body=block + { Gfdecl (loc $startpos $endpos { frtyp; fname; args; body }) } + +arglist: + | l=separated_list(COMMA, pair(ty,IDENT)) { l } + +ty: + | TINT { TInt } + | r=rtyp { TRef r } + +%inline ret_ty: + | TVOID { RetVoid } + | t=ty { RetVal t } + +%inline rtyp: + | TSTRING { RString } + | t=ty LBRACKET RBRACKET { RArray t } + +%inline bop: + | PLUS { Add } + | DASH { Sub } + | STAR { Mul } + | EQEQ { Eq } + +%inline uop: + | DASH { Neg } + | BANG { Lognot } + | TILDE { Bitnot } + +gexp: + | t=rtyp NULL { loc $startpos $endpos @@ CNull t } + | i=INT { loc $startpos $endpos @@ CInt i } + +lhs: + | id=IDENT { loc $startpos $endpos @@ Id id } + | e=exp LBRACKET i=exp RBRACKET + { loc $startpos $endpos @@ Index (e, i) } + +exp: + | i=INT { loc $startpos $endpos @@ CInt i } + | t=rtyp NULL { loc $startpos $endpos @@ CNull t } + | e1=exp b=bop e2=exp { loc $startpos $endpos @@ Bop (b, e1, e2) } + | u=uop e=exp { loc $startpos $endpos @@ Uop (u, e) } + | id=IDENT { loc $startpos $endpos @@ Id id } + | e=exp LBRACKET i=exp RBRACKET + { loc $startpos $endpos @@ Index (e, i) } + | e=exp LPAREN es=separated_list(COMMA, exp) RPAREN + { loc $startpos $endpos @@ Call (e,es) } + | LPAREN e=exp RPAREN { e } + +vdecl: + | VAR id=IDENT EQ init=exp { (id, init) } + +stmt: + | d=vdecl SEMI { loc $startpos $endpos @@ Decl(d) } + | p=lhs EQ e=exp SEMI { loc $startpos $endpos @@ Assn(p,e) } + | e=exp LPAREN es=separated_list(COMMA, exp) RPAREN SEMI + { loc $startpos $endpos @@ SCall (e, es) } + | ifs=if_stmt { ifs } + | RETURN SEMI { loc $startpos $endpos @@ Ret(None) } + | RETURN e=exp SEMI { loc $startpos $endpos @@ Ret(Some e) } + | WHILE LPAREN e=exp RPAREN b=block + { loc $startpos $endpos @@ While(e, b) } + +block: + | LBRACE stmts=list(stmt) RBRACE { stmts } + +if_stmt: + | IF LPAREN e=exp RPAREN b1=block b2=else_stmt + { loc $startpos $endpos @@ If(e,b1,b2) } + +else_stmt: + | (* empty *) { [] } + | ELSE b=block { b } + | ELSE ifs=if_stmt { [ ifs ] } diff --git a/hw4/progasts.ml b/hw4/progasts.ml new file mode 100644 index 0000000..6b7e4db --- /dev/null +++ b/hw4/progasts.ml @@ -0,0 +1,10 @@ +open Ast + +let easy_p1_ast = [ Gfdecl (no_loc ({ frtyp = RetVal TInt; fname = "f"; args = [ ]; body = [ no_loc (Ret (Some (no_loc (CInt 0L)))) ] })) ] +let easy_p2_ast = [ Gfdecl (no_loc ({ frtyp = RetVal TInt; fname = "f"; args = [ (TInt,"x") ]; body = [ no_loc (Decl ("x", no_loc (CInt 0L))) ; no_loc (Assn (no_loc (Id ("x")),no_loc (Bop (IOr,no_loc (Bop (Shl,no_loc (Bop (Shr,no_loc (Bop (Sub,no_loc (Bop (Add,no_loc (Id ("x")),no_loc (Id ("x")))),no_loc (Bop (Mul,no_loc (Id ("x")),no_loc (Id ("x")))))),no_loc (Id ("x")))),no_loc (Id ("x")))),no_loc (Bop (IAnd,no_loc (Id ("x")),no_loc (Bop (Sar,no_loc (Uop (Neg, no_loc (Uop (Bitnot, no_loc (Id ("x")))))),no_loc (Id ("x")))))))))) ; no_loc (Ret (Some (no_loc (Id ("x"))))) ] })) ] +let easy_p3_ast = [ Gfdecl (no_loc ({ frtyp = RetVal (TRef RString); fname = "bar"; args = [ (TInt,"x") ; (TRef RString,"y") ]; body = [ no_loc (Decl ("s",no_loc (CStr "This is a string"))) ; no_loc (Decl ("array", no_loc (CArr (TInt, [ no_loc (CInt 1L) ; no_loc (CInt 3L) ])))) ; no_loc (Decl ("y", no_loc (Index (no_loc (Id ("array")), no_loc (CInt 0L))))) ; no_loc (Ret (Some (no_loc (Id ("s"))))) ] })) ; Gfdecl (no_loc ({ frtyp = RetVoid; fname = "proc1"; args = [ ]; body = [ no_loc (SCall (no_loc (Id "proc2"), [])) ; no_loc (Ret (None)) ] })) ; Gfdecl (no_loc ({ frtyp = RetVoid; fname = "proc2"; args = [ ]; body = [ no_loc (SCall (no_loc (Id "proc1"), [ ])); no_loc (Ret (None)) ] })) ; Gfdecl (no_loc ({ frtyp = RetVal TBool; fname = "foo"; args = [ (TInt,"x") ; (TRef (RArray TInt),"y") ]; body = [ no_loc (Decl ("s", no_loc (Call (no_loc (Id "bar"), [ no_loc (Id ("x")) ; no_loc (CStr "compilerdesign") ])))) ; no_loc (SCall (no_loc (Id "proc1"), [ ])) ; no_loc (Ret (Some (no_loc (CBool true)))) ] })) ] +let easy_p4_ast = [ Gfdecl (no_loc ({ frtyp = RetVal (TRef RString); fname = "f"; args = [ ]; body = [ no_loc (Decl ("s", no_loc (CArr (TRef (RArray (TRef RString)), [ no_loc (CArr (TRef RString, [ no_loc (CStr "s00:\n+\n=2*\n") ; no_loc (CStr "s01:this is not a comment in string.*") ; no_loc (CStr "s02:\"\\t\\n\\\\?\"") ])) ; no_loc (CArr (TRef RString, [ no_loc (CStr "s10:\133\134") ; no_loc (CStr "s11") ; no_loc (CStr "s12") ])) ])))) ; no_loc (Ret (Some (no_loc (Index (no_loc (Index (no_loc (Id ("s")), no_loc (CInt 0L))), no_loc (CInt 1L)))))) ] })) ; Gfdecl (no_loc ({ frtyp = RetVal (TRef (RArray (TRef (RArray TInt)))); fname = "g"; args = [ (TRef (RArray (TRef (RArray TInt))),"x") ]; body = [ no_loc (Decl ("y", no_loc (CArr (TRef (RArray TInt), [ no_loc (CArr (TInt, [ no_loc (CInt 0L) ; no_loc (CInt 1L) ])) ; no_loc (CArr (TInt, [ no_loc (CInt 2L) ; no_loc (CInt 3L) ])) ])))) ; no_loc (Decl ("i", no_loc (CInt 0L))) ; no_loc (Assn (no_loc (Index (no_loc (Index (no_loc (Id ("x")),no_loc (CInt 0L))) ,no_loc (CInt 0L))),no_loc (Bop (Add,no_loc (Id ("i")),no_loc (Index (no_loc (Index (no_loc (Id ("y")), no_loc (CInt 1L))), no_loc (CInt 1L))))))) ; no_loc (Assn (no_loc (Id ("i")),no_loc (Uop (Neg, no_loc (Uop (Lognot, no_loc (Uop (Bitnot, no_loc (Index (no_loc (Index (no_loc (Id ("x")), no_loc (CInt 0L))), no_loc (CInt 0L))))))))))) ; no_loc (Ret (Some (no_loc (Id ("x"))))) ] })) ] +let easy_p5_ast = [ Gvdecl (no_loc { name="i"; init=no_loc (CInt 19L)}) ; Gvdecl (no_loc { name="b1"; init=no_loc (CBool true)}) ; Gvdecl (no_loc { name="b2"; init=no_loc (CBool false)}) ; Gvdecl (no_loc { name="str"; init=no_loc (CStr "This is a string!")}) ; Gvdecl (no_loc { name="arr1"; init=no_loc (CArr (TInt, [ no_loc (CInt 0L) ; no_loc (CInt 1L) ; no_loc (CInt 2L) ]))}) ; Gvdecl (no_loc { name="arr2"; init=no_loc (CArr (TRef (RArray TInt), [ no_loc (CArr (TInt, [ no_loc (CInt 10L) ; no_loc (CInt 11L) ])) ; no_loc (CArr (TInt, [ no_loc (CInt 20L) ; no_loc (CInt 21L) ])) ; no_loc (CArr (TInt, [ no_loc (CInt 30L) ; no_loc (CInt 31L) ])) ]))}) ; Gvdecl (no_loc { name="arr3"; init=no_loc (CArr (TRef RString, [ no_loc (CStr "String1") ; no_loc (CStr "String2") ; no_loc (CStr "String3") ]))}) ; Gvdecl (no_loc { name="arr4"; init=no_loc (CArr (TRef (RArray (TRef RString)), [ no_loc (CArr (TRef RString, [ no_loc (CStr "String00") ; no_loc (CStr "String01") ])) ; no_loc (CArr (TRef RString, [ no_loc (CStr "String10") ; no_loc (CStr "String11") ])) ; no_loc (CArr (TRef RString, [ no_loc (CStr "String20") ; no_loc (CStr "String21") ])) ]))}) ] +let easy_p6_ast = [ Gvdecl (no_loc { name="y"; init=no_loc (CInt 0L)}) ; Gvdecl (no_loc { name="z"; init=no_loc (CInt 0L)}) ; Gfdecl (no_loc ({ frtyp = RetVoid; fname = "f"; args = [ (TInt,"x") ; (TInt,"y") ]; body = [ no_loc (Decl ("x", no_loc (CInt 0L))) ; no_loc (Ret (None)) ] })) ; Gfdecl (no_loc ({ frtyp = RetVoid; fname = "g"; args = [ (TInt,"x") ; (TInt,"y") ]; body = [ no_loc (Decl ("z", no_loc (CInt 0L) )) ; no_loc (Ret (None)) ] })) ] +let easy_p7_ast = [ Gvdecl ({ elt = { name = "j"; init = { elt = CArr (TInt,[ { elt = CInt 1L; loc = ("hw4programs/easy_p7.oat", (0, 21), (0, 22)) } ; { elt = CInt 2L; loc = ("hw4programs/easy_p7.oat", (0, 23), (0, 24)) } ; { elt = CInt 3L; loc = ("hw4programs/easy_p7.oat", (0, 25), (0, 26)) } ; { elt = CInt 4L; loc = ("hw4programs/easy_p7.oat", (0, 27), (0, 28)) } ]); loc = ("hw4programs/easy_p7.oat", (0, 11), (0, 29)) } }; loc = ("hw4programs/easy_p7.oat", (0, 0), (0, 30)) }) ; Gfdecl ({ elt = { frtyp = RetVal (TRef ((RArray (TInt)))); fname = "f"; args = [ ]; body = [ { elt = Decl (("a", { elt = CArr (TRef ((RArray (TInt))),[ { elt = CInt 1L; loc = ("hw4programs/easy_p7.oat", (2, 22), (2, 23)) } ; { elt = CInt 2L; loc = ("hw4programs/easy_p7.oat", (2, 25), (2, 26)) } ]); loc = ("hw4programs/easy_p7.oat", (2, 10), (2, 27)) })); loc = ("hw4programs/easy_p7.oat", (2, 2), (2, 28)) } ; { elt = Decl (("i", { elt = NewArr (TInt,{ elt = CInt 4L; loc = ("hw4programs/easy_p7.oat", (3, 18), (3, 19)) }); loc = ("hw4programs/easy_p7.oat", (3, 10), (3, 20)) })); loc = ("hw4programs/easy_p7.oat", (3, 2), (3, 21)) } ; { elt = Decl (("arr1", { elt = NewArr (TInt,{ elt = CInt 3L; loc = ("hw4programs/easy_p7.oat", (4, 21), (4, 22)) }); loc = ("hw4programs/easy_p7.oat", (4, 13), (4, 23)) })); loc = ("hw4programs/easy_p7.oat", (4, 2), (4, 24)) } ; { elt = Ret (Some ({ elt = NewArr (TInt,{ elt = CInt 2L; loc = ("hw4programs/easy_p7.oat", (5, 17), (5, 18)) }); loc = ("hw4programs/easy_p7.oat", (5, 9), (5, 19)) })); loc = ("hw4programs/easy_p7.oat", (5, 2), (5, 20)) } ] }; loc = ("hw4programs/easy_p7.oat", (1, 0), (6, 1)) }) ] + diff --git a/hw4/runtime.c b/hw4/runtime.c new file mode 100644 index 0000000..94fd6ee --- /dev/null +++ b/hw4/runtime.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +/* Oat Internal Functions --------------------------------------------------- */ + +int64_t* oat_alloc_array (int64_t size) { + assert (size >= 0); + int64_t *arr = (int64_t*)calloc(size+1, sizeof(int64_t)); + arr[0] = size; + return arr; +} + +/* Oat Builtin Functions ---------------------------------------------------- */ + +int64_t* array_of_string (char *str) { + int64_t len, i, *arr; + + assert (NULL != str); + + len = strlen(str); + assert (len >= 0); + + arr = (int64_t*)malloc(sizeof(int64_t) * (len+1)); + arr[0] = len; + for (i=0; i= 0); + + str = malloc(sizeof(char) * (len+1)); + + for (i=0; iunit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = (unit -> unit) + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = (assertion test) list + + +(**************) +(* Assertions *) +exception Timeout + +let timeout_assert (time : int) (a : assertion) : assertion = + fun () -> + let handler = Sys.Signal_handle (fun _ -> raise Timeout) in + let old = Sys.signal Sys.sigalrm handler in + let reset_sigalrm () = Sys.set_signal Sys.sigalrm old in + ignore (Unix.alarm time); + try begin a (); reset_sigalrm () end + with Timeout -> reset_sigalrm (); failwith @@ Printf.sprintf "Timed out after %d seconds" time + | exc -> reset_sigalrm (); raise exc + +let timeout_test (time : int) (t : assertion test) : assertion test = + let map_timeout l = List.map (fun (i, a) -> (i, timeout_assert time a)) l in + match t with + | GradedTest (s, i, ls) -> GradedTest (s, i, map_timeout ls) + | Test (s, ls) -> Test (s, map_timeout ls) + +let timeout_suite (time : int) (s : suite) : suite = + List.map (timeout_test time) s + +let timeout_assert_const (a: assertion) : assertion = + timeout_assert 10 a + +let assert_eq v1 v2 : assertion = + timeout_assert_const (fun () -> if v1 <> v2 then failwith "not equal" else ()) + +let assert_eqf f v2 : assertion = + timeout_assert_const (fun () -> if (f ()) <> v2 then failwith "not equal" else ()) + +let assert_eqfs f v2 : assertion = + timeout_assert_const (fun () -> + let s1 = f () in + if s1 <> v2 then failwith @@ Printf.sprintf "not equal\n\texpected:%s\n\tgot:%s\n" v2 s1 + else ()) + + +let assert_fail : assertion = fun () -> failwith "assert fail" + + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = (result test) list + +let run_assertion (f:assertion) : result = + try + f (); + Pass + with + | Failure m -> Fail m + | e -> Fail ("test threw exception: " ^ (Printexc.to_string e)) + +let run_test (t:assertion test) : result test = + let run_case (cn, f) = (cn, run_assertion f) in + begin match t with + | GradedTest (n,s,cases) -> + Printf.eprintf "Running test %s\n%!" n; + GradedTest(n,s,List.map run_case cases) + + | Test (n, cases) -> + Printf.eprintf "Running test %s\n%!" n; + Test(n, List.map run_case cases) + end + +let run_suite (s:suite):outcome = + List.map run_test s + + + + + +(***********************) +(* Reporting functions *) + +let result_test_to_string (name_pts:string) (r:result test): string = + let string_of_case (name, res) = + begin match res with + | Pass -> "passed - " ^ name + | Fail msg -> "FAILED - " ^ name ^ ": " ^ msg + end + in + begin match r with + | GradedTest (_, _, cases) + | Test (_, cases) -> + name_pts ^ + (List.fold_left (fun rest -> fun case -> rest ^ "\n" ^ (string_of_case case)) "" cases) + end + +(* returns (name_pts, passed, failed, total, points_earned, max_given, max_hidden) *) +let get_results (t:result test) = + let num_passed cases = + List.fold_left (fun cnt (_,r) -> match r with Pass -> cnt + 1 | _ -> cnt) 0 cases in + let num_failed cases = + List.fold_left (fun cnt (_,r) -> match r with Fail _ -> cnt + 1 | _ -> cnt) 0 cases in + begin match t with + | GradedTest (name,pts,cases) -> + let passed = num_passed cases in + let failed = num_failed cases in + let total = List.length cases in + if total > 0 then + let points_earned = ((float_of_int passed) /. (float_of_int total)) *. (float_of_int pts) in + let name_pts = Printf.sprintf "%s (%1.f/%d points)" name points_earned pts in + (name_pts, passed, failed, total, points_earned, pts, 0) + else + let name_pts = Printf.sprintf "%s (?/%d points)" name pts in + (name_pts, passed, failed, total, 0.0, 0, pts) + | Test(name, cases) -> + let total = List.length cases in + let passed = num_passed cases in + let failed = num_failed cases in + (name, passed, failed, total, 0.0, 0, 0) + end + +let outcome_to_string (o:outcome):string = + let sep = "\n---------------------------------------------------\n" in + let helper (passed, failed, total, pts, maxg, maxh, str) (t:result test) = + let (name_pts, p, f, tot, s, mg, mh) = get_results t in + (passed + p, failed + f, total + tot, s +. pts, maxg + mg, maxh + mh, + str ^ "\n" ^ ( + if f > 0 then (result_test_to_string name_pts t) else + if tot > 0 then (name_pts ^ ":\n OK") else + (name_pts ^ ":\n Hidden") + ) + ) in + let (p,f,tot,pts,maxg, maxh,str) = List.fold_left helper (0,0,0,0.0,0,0,"") o in + str ^ sep ^ (Printf.sprintf "Passed: %d/%d\nFailed: %d/%d\nScore: %1.f/%d (given)\n ?/%d (hidden)" p tot f tot pts maxg maxh) + + + + diff --git a/hw4/util/assert.mli b/hw4/util/assert.mli new file mode 100644 index 0000000..57926a3 --- /dev/null +++ b/hw4/util/assert.mli @@ -0,0 +1,54 @@ +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +exception Timeout + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = unit -> unit + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = assertion test list + +(**************) +(* Assertions *) + +val assert_eq : 'a -> 'a -> assertion + +val assert_eqf : (unit -> 'a) -> 'a -> assertion + +val assert_eqfs : (unit -> string) -> string -> assertion + +val assert_fail : assertion + +val timeout_assert : int -> assertion -> assertion + +val timeout_test : int -> assertion test -> assertion test + +val timeout_suite : int -> suite -> suite + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = result test list + +val run_assertion : assertion -> result + +val run_test : assertion test -> result test + +val run_suite : suite -> outcome + +(***********************) +(* Reporting functions *) + +val result_test_to_string : string -> result test -> string + +(* val get_results result test -> (string * int * int * int * float * int * int) *) +val outcome_to_string : outcome -> string diff --git a/hw4/util/platform.ml b/hw4/util/platform.ml new file mode 100644 index 0000000..84c4a17 --- /dev/null +++ b/hw4/util/platform.ml @@ -0,0 +1,210 @@ +(* -------------------------------------------------------------------------- *) +(** Assembling and linking for X86. Depends on the underlying OS platform *) + +open Printf +open Unix + +exception PlatformError of string * string + +(* paths -------------------------------------------------------------------- *) +let path_sep = "/" + +let dot_path = "./" + +let output_path = ref "output" + +let libs = ref [] + +let lib_paths = ref [] + +let lib_search_paths = ref [] + +let include_paths = ref [] + +let executable_name = ref "a.out" + +(* unix utility scripts ----------------------------------------------------- *) +let pp_cmd = ref "cpp -E " + +let rm_cmd = ref "rm -rf " + +(* -------------------------------------------------------------------------- *) +(* Platform specific configuration: Unix/Linux vs. Mac OS X *) + +let os = + let ic = Unix.open_process_in "uname -s" in + let uname = input_line ic in + let () = close_in ic in + uname + + +(* One of "Darwin" or "Linux" *) + +let linux = ref false + +let mangle name = if !linux then name else "_" ^ name + +let osx_target_triple = "x86_64-apple-macosx10.13.0" + +let linux_target_triple = "x86_64-unknown-linux" + +let target_triple = ref osx_target_triple + +let platform_flags = ref "" + +(* Set the link commands properly, ensure output directory exists *) +let configure_os () = + if os = "Linux" + then ( + linux := true ; + target_triple := linux_target_triple ; + platform_flags := "" ) + else if os = "Darwin" + then ( + linux := false ; + target_triple := osx_target_triple ; + platform_flags := "-fno-asynchronous-unwind-tables -mstackrealign" ) + else failwith @@ "Unsupported OS detected: " ^ os + + +(* verbose compiler output -------------------------------------------------- *) +let verbose = ref false + +let verb msg = + if !verbose + then ( + print_string msg ; + flush Stdlib.stdout ) + + +let verb_os () = + verb + @@ Printf.sprintf + "* PLATFORM: %s TRIPLE: %s FLAGS %s\n" + os + !target_triple + !platform_flags + + +let enable_verbose () = + verbose := true ; + verb_os () + + +(* create the output directory, which is assumed to exist *) +let create_output_dir () = + try ignore (stat !output_path) with + | Unix_error (ENOENT, _, _) -> + verb @@ Printf.sprintf "creating output directory: %s\n" !output_path ; + mkdir !output_path 0o755 + + +(* clang invocation stuff --------------------------------------------------- *) +let common_flags = "-Wno-override-module" + +let clang_ll_mode = "-S" + +let as_mode = "-c" + +let opt_level = ref "-O1 -Wall" + +let clang args = Printf.sprintf "clang %s -o " (String.concat " " args) + +let clang_cmd () = + clang [ clang_ll_mode; !opt_level; common_flags; !platform_flags ] + + +let as_cmd () = clang [ as_mode; !opt_level; common_flags; !platform_flags ] + +let link_cmd () = clang [ common_flags; !opt_level; !platform_flags ] + +(* filename munging --------------------------------------------------------- *) +let path_to_basename_ext (path : string) : string * string = + (* The path is of the form ... "foo/bar/baz/.ext" *) + let paths = Str.split (Str.regexp_string path_sep) path in + let _ = + if List.length paths = 0 then failwith @@ sprintf "bad path: %s" path + in + let filename = List.hd (List.rev paths) in + match Str.split (Str.regexp_string ".") filename with + | [ root ] -> + (root, "") + | [ root; ext ] -> + (root, ext) + | _ -> + failwith @@ sprintf "bad filename: %s" filename + + +(* compilation and shell commands-------------------------------------------- *) + +(* Platform independent shell command *) +let sh (cmd : string) (ret : string -> int -> 'a) : 'a = + verb (sprintf "* %s\n" cmd) ; + match system cmd with + | WEXITED i -> + ret cmd i + | WSIGNALED i -> + raise (PlatformError (cmd, sprintf "Signaled with %d." i)) + | WSTOPPED i -> + raise (PlatformError (cmd, sprintf "Stopped with %d." i)) + + +(* Generate a file name that does not already exist. + basedir includes the path separator +*) +let gen_name (basedir : string) (basen : string) (baseext : string) : string = + let rec nocollide ofs = + let nfn = + sprintf + "%s/%s%s%s" + basedir + basen + (if ofs = 0 then "" else "_" ^ string_of_int ofs) + baseext + in + try + ignore (stat nfn) ; + nocollide (ofs + 1) + with + | Unix_error (ENOENT, _, _) -> + nfn + in + nocollide 0 + + +let raise_error cmd i = + if i <> 0 then raise (PlatformError (cmd, sprintf "Exited with status %d." i)) + + +let ignore_error _ _ = () + +let preprocess (dot_oat : string) (dot_i : string) : unit = + sh + (sprintf + "%s%s %s %s" + !pp_cmd + (List.fold_left (fun s i -> s ^ " -I" ^ i) "" !include_paths) + dot_oat + dot_i) + raise_error + + +let clang_compile (dot_ll : string) (dot_s : string) : unit = + sh (sprintf "%s%s %s" (clang_cmd ()) dot_s dot_ll) raise_error + + +let assemble (dot_s : string) (dot_o : string) : unit = + sh (sprintf "%s%s %s" (as_cmd ()) dot_o dot_s) raise_error + + +let link (mods : string list) (out_fn : string) : unit = + sh + (sprintf + "%s%s %s %s %s %s" + (link_cmd ()) + out_fn + (String.concat " " (mods @ !lib_paths)) + (List.fold_left (fun s i -> s ^ " -L" ^ i) "" !lib_search_paths) + (List.fold_left (fun s i -> s ^ " -I" ^ i) "" !include_paths) + (List.fold_left (fun s l -> s ^ " -l" ^ l) "" !libs)) + raise_error diff --git a/hw4/util/range.ml b/hw4/util/range.ml new file mode 100644 index 0000000..9a78d1a --- /dev/null +++ b/hw4/util/range.ml @@ -0,0 +1,56 @@ +open Lexing + +type pos = int * int (* Line number and column *) + +type t = string * pos * pos + +let line_of_pos (l, _) = l + +let col_of_pos (_, c) = c + +let mk_pos line col = (line, col) + +let file_of_range (f, _, _) = f + +let start_of_range (_, s, _) = s + +let end_of_range (_, _, e) = e + +let mk_range f s e = (f, s, e) + +let valid_pos (l, c) = l >= 0 && c >= 0 + +let merge_range ((f, s1, e1) as r1) ((f', s2, e2) as r2) = + if f <> f' + then + failwith + @@ Printf.sprintf "merge_range called on different files: %s and %s" f f' + else if not (valid_pos s1) + then r2 + else if not (valid_pos s2) + then r1 + else mk_range f (min s1 s2) (max e1 e2) + + +let string_of_range (f, (sl, sc), (el, ec)) = + Printf.sprintf "%s:[%d.%d-%d.%d]" f sl sc el ec + + +let ml_string_of_range (f, (sl, sc), (el, ec)) = + Printf.sprintf "(\"%s\", (%d, %d), (%d, %d))" f sl sc el ec + + +let norange = ("__internal", (0, 0), (0, 0)) + +(* Creates a Range.pos from the Lexing.position data *) +let pos_of_lexpos (p : position) : pos = + mk_pos p.pos_lnum (p.pos_cnum - p.pos_bol) + + +let mk_lex_range (p1 : position) (p2 : position) : t = + mk_range p1.pos_fname (pos_of_lexpos p1) (pos_of_lexpos p2) + + +(* Expose the lexer state as a Range.t value *) +let lex_range lexbuf : t = + mk_lex_range (lexeme_start_p lexbuf) (lexeme_end_p lexbuf) diff --git a/hw4/util/range.mli b/hw4/util/range.mli new file mode 100644 index 0000000..9603713 --- /dev/null +++ b/hw4/util/range.mli @@ -0,0 +1,53 @@ +(* Ranges and utilities on ranges. *) + +(* A range represents a segment of text in a given file; it has a + * beginning and ending position specified in terms of line and column + * numbers. A range is associated with tokens during lexing to allow + * the compiler to give better error messages during lexing and + * parsing. + *) + +(* a position in the source file; line number and column *) +type pos = int * int + +(* a range of positions in a particular file *) +type t = string * pos * pos + +(* line of position *) +val line_of_pos : pos -> int + +(* column of position *) +val col_of_pos : pos -> int + +(* new position with given line and col *) +val mk_pos : int -> int -> pos + +(* the filename a range is in *) +val file_of_range : t -> string + +(* the beginning of the range *) +val start_of_range : t -> pos + +(* the end of the range *) +val end_of_range : t -> pos + +(* create a new range from the given filename and start, end positions *) +val mk_range : string -> pos -> pos -> t + +(* merge two ranges together *) +val merge_range : t -> t -> t + +(* pretty-print a range *) +val string_of_range : t -> string + +(* print a range as an ocaml value *) +val ml_string_of_range : t -> string + +(* use to tag generated AST nodes where range does not apply *) +val norange : t + +val pos_of_lexpos : Lexing.position -> pos + +val mk_lex_range : Lexing.position -> Lexing.position -> t + +val lex_range : Lexing.lexbuf -> t diff --git a/hw4/x86/testX86.ml b/hw4/x86/testX86.ml new file mode 100644 index 0000000..1b23983 --- /dev/null +++ b/hw4/x86/testX86.ml @@ -0,0 +1,34 @@ +open X86 +open Cunit + +let hello_label = mk_lbl_named "hellostr" +let puts_label = mk_lbl_named "_puts" (* gcc on linux/mac uses _ to munge names *) + +let main_seq = [ + Push (esp); + Mov (ebp, esp); + + Add (esp, Imm (-8l)); (* Not sure why this has to be 8 *) + Mov (stack_offset 0l, Lbl hello_label); + Call (Lbl puts_label); + + Mov (esp, ebp); + Pop (ebp); + Ret +] + +let main_bb = { + (mk_insn_block (mk_lbl_named "_main") main_seq) with + global = true +} + +let hello_data = { + link = false; + label = (mk_lbl_named "hellostr"); + value = GStringz "Hello, world!" +} + +let cu = [Data hello_data; Code main_bb] + +let _ = + print_endline (string_of_cunit cu) diff --git a/hw4/x86/x86.ml b/hw4/x86/x86.ml new file mode 100644 index 0000000..802ee18 --- /dev/null +++ b/hw4/x86/x86.ml @@ -0,0 +1,165 @@ +(* X86lite language representation. *) + +(* assembler syntax --------------------------------------------------------- *) + +(* Labels for code blocks and global data. *) +type lbl = string + +type quad = int64 + +(* Immediate operands *) +type imm = Lit of quad + | Lbl of lbl + +(* Registers: + instruction pointer: rip + arguments: rdi, rsi, rdx, rcx, r09, r08 + callee-save: rbx, rbp, r12-r15 +*) +type reg = Rip + | Rax | Rbx | Rcx | Rdx | Rsi | Rdi | Rbp | Rsp + | R08 | R09 | R10 | R11 | R12 | R13 | R14 | R15 + +type operand = Imm of imm (* immediate *) + | Reg of reg (* register *) + | Ind1 of imm (* indirect: displacement *) + | Ind2 of reg (* indirect: (%reg) *) + | Ind3 of (imm * reg) (* indirect: displacement(%reg) *) + +(* Condition Codes *) +type cnd = Eq | Neq | Gt | Ge | Lt | Le + +type opcode = Movq | Pushq | Popq + | Leaq + | Incq | Decq | Negq | Notq + | Addq | Subq | Imulq | Xorq | Orq | Andq + | Shlq | Sarq | Shrq + | Jmp | J of cnd + | Cmpq | Set of cnd + | Callq | Retq + +(* An instruction is an opcode plus its operands. + Note that arity and other constraints about the operands + are not checked. *) +type ins = opcode * operand list + +type data = Asciz of string + | Quad of imm + +type asm = Text of ins list (* code *) + | Data of data list (* data *) + +(* labeled blocks of data or code *) +type elem = { lbl: lbl; global: bool; asm: asm } + +type prog = elem list + +(* Provide some syntactic sugar for writing x86 code in OCaml files. *) +module Asm = struct + let (~$) i = Imm (Lit (Int64.of_int i)) (* int64 constants *) + let (~$$) l = Imm (Lbl l) (* label constants *) + let (~%) r = Reg r (* registers *) + + (* helper functions for building blocks of data or code *) + let data l ds = { lbl = l; global = true; asm = Data ds } + let text l is = { lbl = l; global = false; asm = Text is } + let gtext l is = { lbl = l; global = true; asm = Text is } +end + +(* pretty printing ----------------------------------------------------------- *) + +let string_of_reg : reg -> string = function + | Rip -> "%rip" + | Rax -> "%rax" | Rbx -> "%rbx" | Rcx -> "%rcx" | Rdx -> "%rdx" + | Rsi -> "%rsi" | Rdi -> "%rdi" | Rbp -> "%rbp" | Rsp -> "%rsp" + | R08 -> "%r8 " | R09 -> "%r9 " | R10 -> "%r10" | R11 -> "%r11" + | R12 -> "%r12" | R13 -> "%r13" | R14 -> "%r14" | R15 -> "%r15" + +let string_of_byte_reg : reg -> string = function + | Rip -> failwith "%rip used as byte register" + | Rax -> "%al" | Rbx -> "%bl" | Rcx -> "%cl" | Rdx -> "%dl" + | Rsi -> "%sil" | Rdi -> "%dil" | Rbp -> "%bpl" | Rsp -> "%spl" + | R08 -> "%r8b" | R09 -> "%r9b" | R10 -> "%r10b" | R11 -> "%r11b" + | R12 -> "%r12b" | R13 -> "%r13b" | R14 -> "%r14b" | R15 -> "%r15b" + +let string_of_lbl (l:lbl) : string = l + +let string_of_imm : imm -> string = function + | Lit i -> Int64.to_string i + | Lbl l -> string_of_lbl l + +let string_of_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_byte_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_byte_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_jmp_operand : operand -> string = function + | Imm i -> string_of_imm i + | Reg r -> "*" ^ string_of_reg r + | Ind1 i -> "*" ^ string_of_imm i + | Ind2 r -> "*" ^ "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> "*" ^ string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_cnd : cnd -> string = function + | Eq -> "e" | Neq -> "ne" | Gt -> "g" + | Ge -> "ge" | Lt -> "l" | Le -> "le" + +let string_of_opcode : opcode -> string = function + | Movq -> "movq" | Pushq -> "pushq" | Popq -> "popq" + | Leaq -> "leaq" + | Incq -> "incq" | Decq -> "decq" | Negq -> "negq" | Notq -> "notq" + | Addq -> "addq" | Subq -> "subq" | Imulq -> "imulq" + | Xorq -> "xorq" | Orq -> "orq" | Andq -> "andq" + | Shlq -> "shlq" | Sarq -> "sarq" | Shrq -> "shrq" + | Jmp -> "jmp" | J c -> "j" ^ string_of_cnd c + | Cmpq -> "cmpq" | Set c -> "set" ^ string_of_cnd c + | Callq -> "callq" | Retq -> "retq" + +let map_concat s f l = String.concat s @@ List.map f l + +let string_of_shift op = function + | [ Imm i ; dst ] as args -> + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " string_of_operand args + | [ Reg Rcx ; dst ] -> + Printf.sprintf "\t%s\t%%cl, %s" (string_of_opcode op) (string_of_operand dst) + | args -> failwith (Printf.sprintf "shift instruction has invalid operands: %s\n" + (map_concat ", " string_of_operand args)) + +let string_of_ins (op, args: ins) : string = + match op with + | Shlq | Sarq | Shrq -> string_of_shift op args + | _ -> + let f = match op with + | J _ | Jmp | Callq -> string_of_jmp_operand + | Set _ -> string_of_byte_operand + | _ -> string_of_operand + in + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " f args + +let string_of_data : data -> string = function + | Asciz s -> "\t.asciz\t" ^ "\"" ^ (String.escaped s) ^ "\"" + | Quad i -> "\t.quad\t" ^ string_of_imm i + +let string_of_asm : asm -> string = function + | Text is -> "\t.text\n" ^ map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n" ^ map_concat "\n" string_of_data ds + +let string_of_elem {lbl; global; asm} : string = + let sec, body = match asm with + | Text is -> "\t.text\n", map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n", map_concat "\n" string_of_data ds + in + let glb = if global then "\t.globl\t" ^ string_of_lbl lbl ^ "\n" else "" in + sec ^ glb ^ string_of_lbl lbl ^ ":\n" ^ body + +let string_of_prog (p:prog) : string = + String.concat "\n" @@ List.map string_of_elem p diff --git a/hw5/Makefile b/hw5/Makefile new file mode 100644 index 0000000..b15400c --- /dev/null +++ b/hw5/Makefile @@ -0,0 +1,26 @@ +INCLUDES= util,x86,grading,ll +LIBS = unix,str +SUBMIT := frontend.ml typechecker.ml team.txt + +HWNAME := hw05 +ZIPNAME := $(HWNAME)-submit.zip + + +all: main.native + +.PHONY: test +test: main.native + ./main.native --test + +.PHONY: main.native +main.native: + ocamlbuild -pkg num -Is $(INCLUDES) -libs $(LIBS) main.native -use-menhir -yaccflag --explain + +zip: $(SUBMIT) + zip '$(ZIPNAME)' $(SUBMIT) + +.PHONY: clean +clean: + ocamlbuild -clean + rm -rf output a.out + diff --git a/hw5/README b/hw5/README new file mode 100644 index 0000000..dbaa201 --- /dev/null +++ b/hw5/README @@ -0,0 +1,69 @@ +Using main.native for testing: + +* To run the automated test harness do: + - on OS X: ./main.native --test + - on Linux: ./main.native -linux --test + +* To compile ll files using the 341 backend: + ./main.native path/to/foo.ll + + - creates output/foo.s backend assembly code + - creates output/foo.o assembled object file + - creates a.out linked executable + + NOTE: by default the .s and .o files are created in + a directory called output, and the filenames are + chosen so that multiple runs of the compiler will + not overwrite previous outputs. foo.ll will be + compiled first to foo.s then foo_1.s, foo_2.s, etc. + + +* To compile ll files using the clang backend: + ./main.native --clang path/to/foo.ll + +* Useful flags: + + --print-ll + echoes the ll program to the terminal + + --print-x86 + echoes the resulting .s file to the terminal + + --simulate-x86 + runs the resulting .s file through the reference + x86 simulator and outputs the result to the console + + --execute-x86 + runs the resulting a.out file natively + (applies to either the 341 backend or clang-compiled code) + + -v + generates verbose output, showing which commands are used + for linking, etc. + + -op + change the output path [DEFAULT=output] + + -o + change the generated executable's name [DEFAULT=a.out] + + -S + stop after generating .s files + + -c + stop after generating .o files + + -h or --help + display the list of options + +* Example uses: + +Run the test case /programs/factrect.ll using the 341 backend: + + +./main.native --execute-x86 programs/factrect.ll +--------------------------------------------------------------- Executing: a.out +* a.out returned 120 + + +Run the test diff --git a/hw5/ast.ml b/hw5/ast.ml new file mode 100644 index 0000000..69a3400 --- /dev/null +++ b/hw5/ast.ml @@ -0,0 +1,94 @@ + +type 'a node = { elt : 'a; loc : Range.t } + +(** val no_loc : 'a1 -> 'a1 node **) + +let no_loc x = + { elt = x; loc = Range.norange } + +type id = string + +type ty = +| TBool +| TInt +| TRef of rty +| TNullRef of rty +and rty = +| RString +| RStruct of id +| RArray of ty +| RFun of ty list * ret_ty +and ret_ty = +| RetVoid +| RetVal of ty + +type unop = +| Neg +| Lognot +| Bitnot + +type binop = +| Add +| Sub +| Mul +| Eq +| Neq +| Lt +| Lte +| Gt +| Gte +| And +| Or +| IAnd +| IOr +| Shl +| Shr +| Sar + +type exp = +| CNull of rty +| CBool of bool +| CInt of int64 +| CStr of string +| Id of id +| CArr of ty * exp node list +| NewArr of ty * exp node * id * exp node +| Index of exp node * exp node +| Length of exp node +| CStruct of id * (id * exp node) list +| Proj of exp node * id +| Call of exp node * exp node list +| Bop of binop * exp node * exp node +| Uop of unop * exp node + + +type cfield = id * exp node + +type vdecl = id * exp node + +type stmt = +| Assn of exp node * exp node +| Decl of vdecl +| Ret of exp node option +| SCall of exp node * exp node list +| If of exp node * stmt node list * stmt node list +| Cast of rty * id * exp node * stmt node list * stmt node list +| For of vdecl list * exp node option * stmt node option * stmt node list +| While of exp node * stmt node list + +type block = stmt node list + +type gdecl = { name : id; init : exp node } + +type fdecl = { frtyp : ret_ty; fname : id; args : (ty * id) list; body : block } + +type field = { fieldName : id; ftyp : ty } + +type tdecl = id * field list + +type decl = +| Gvdecl of gdecl node +| Gfdecl of fdecl node +| Gtdecl of tdecl node + +type prog = decl list diff --git a/hw5/astlib.ml b/hw5/astlib.ml new file mode 100644 index 0000000..6bba09e --- /dev/null +++ b/hw5/astlib.ml @@ -0,0 +1,492 @@ +(* astlib.ml *) + +(* Helper functions of abstract syntax of trees. *) +(******************************************************************************) + +open Format +open Ast +open Range + +(* Precedence for expressions and operators *) +(* Higher precedences bind more tightly *) + +let prec_of_binop = function +| Mul -> 100 +| Add | Sub -> 90 +| Shl | Shr | Sar -> 80 +| Lt | Lte | Gt | Gte -> 70 +| Eq | Neq -> 60 +| And -> 50 +| Or -> 40 +| IAnd -> 30 +| IOr -> 20 + +let prec_of_unop = function _ -> 110 + +let prec_of_exp = function +| Bop (o,_,_) -> prec_of_binop o +| Uop (o,_) -> prec_of_unop o +| _ -> 130 + + +(* Pretty Printer for AST *) +let string_of_unop = function +| Neg -> "-" +| Lognot -> "!" +| Bitnot -> "~" + +let string_of_binop = function +| Mul -> "*" +| Add -> "+" +| Sub -> "-" +| Shl -> "<<" +| Shr -> ">>" +| Sar -> ">>>" +| Lt -> "<" +| Lte -> "<=" +| Gt -> ">" +| Gte -> ">=" +| Eq -> "==" +| Neq -> "!=" +| And -> "&" +| Or -> "|" +| IAnd -> "[&]" +| IOr -> "[|]" + +let print_id_aux fmt (x:id) = pp_print_string fmt x + +let rec print_list_aux fmt sep pp l = + begin match l with + | [] -> () + | [h] -> pp fmt h + | h::tl -> pp fmt h; sep (); + print_list_aux fmt sep pp tl + end + +let rec print_ty_aux fmt t = + let pps = pp_print_string fmt in + match t with + | TBool -> pps "bool" + | TInt -> pps "int" + | TRef r -> print_rty_aux fmt r + | TNullRef r -> pps "("; print_rty_aux fmt r; pps ")?" + +and print_ret_ty_aux fmt t = + let pps = pp_print_string fmt in + begin match t with + | RetVoid -> pps "void" + | RetVal t -> print_ty_aux fmt t + end + +and print_rty_aux fmt r = + let pps = pp_print_string fmt in + begin match r with + | RString -> pps "string" + | RArray t -> print_ty_aux fmt t; pps "[]" + | RStruct id -> pps id + | RFun (ts, t) -> pps "("; + print_list_aux fmt (fun () -> pps ", ") print_ty_aux ts; + pps ")"; pps "->"; print_ret_ty_aux fmt t + end + +and print_exp_aux level fmt e = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let this_level = prec_of_exp e.elt in + + if this_level < level then pps "("; + begin match e.elt with + | CNull r -> print_rty_aux fmt r; pps "null" + | CBool v -> pps (if v then "true" else "false") + | CInt v -> pps (Int64.to_string v) + | CStr v -> pps (Printf.sprintf "%S" v) + | CArr (ty,vs) -> begin + pps "new "; print_ty_aux fmt ty; pps "[]"; + pps "{"; + pp_open_hbox fmt (); + print_list_aux fmt (fun () -> pps ","; pp_print_space fmt()) (print_exp_aux 0) vs; + pp_close_box fmt (); + pps "}"; + end + | Length l -> pps "length( "; print_exp_aux this_level fmt l; pps " )" + | Id id -> print_id_aux fmt id + | Index (e,i) -> print_exp_aux this_level fmt e; pps "["; print_exp_aux 0 fmt i; pps "]" + | Call (e, es) -> print_exp_aux this_level fmt e; print_exps_aux "(" ")" fmt es + | NewArr (ty, e1, u, e2) -> + pps "new"; print_ty_aux fmt ty; + pps "["; print_exp_aux this_level fmt e1; + pps "{"; pps u; pps "->"; print_exp_aux this_level fmt e2 + | Bop (o,l,r) -> + pp_open_box fmt 0; + print_exp_aux this_level fmt l; + ppsp (); pps (string_of_binop o); ppsp (); + print_exp_aux this_level fmt r; + pp_close_box fmt () + | Uop (o,v) -> + pp_open_box fmt 0; + pps (string_of_unop o); + print_exp_aux this_level fmt v; + pp_close_box fmt () + | Proj (e, id) -> + pp_open_box fmt 0; + print_exp_aux this_level fmt e; + ppsp (); pps "."; ppsp (); pps id; + pp_close_box fmt () + | CStruct (t, l) -> + pps "new "; pps t; + pp_open_box fmt 0; + pps "{"; + List.iter (fun s -> print_cfield_aux this_level fmt s; pps "; ") l; + pps "}"; + pp_close_box fmt () + end; if this_level < level then pps ")" + +and print_cfield_aux l fmt (name, exp) = + pp_open_box fmt 0; + pp_print_string fmt name; + pp_print_string fmt "="; print_exp_aux l fmt exp; + pp_close_box fmt (); + +and print_exps_aux l r fmt es = + let pps = pp_print_string fmt in + pps l; + pp_open_hvbox fmt 0; + print_list_aux fmt + (fun () -> pps ","; pp_print_space fmt()) + (fun fmt -> fun e -> print_exp_aux 0 fmt e) es; + pp_close_box fmt (); + pps r + +let print_vdecl_aux semi fmt (id, init) = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + pp_open_hbox fmt (); + pps "var "; print_id_aux fmt id; + ppsp (); pps " ="; ppsp (); + print_exp_aux 0 fmt init; pps semi; + pp_close_box fmt () + +let rec print_block_aux fmt stmts = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let ppnl = pp_force_newline fmt in + + if (List.length stmts) > 0 then + begin pps "{"; ppnl (); pps " "; + pp_open_vbox fmt 0; + print_list_aux fmt (fun () -> ppsp ()) print_stmt_aux stmts; + pp_close_box fmt (); + ppnl (); pps "}" + end + else pps "{ }" + +and print_cond_aux fmt b_then opt_b_else = + let pps = pp_print_string fmt in + print_block_aux fmt b_then; + begin match opt_b_else with + | [] -> () + | b_else -> pps " else "; print_block_aux fmt b_else + end + +and print_stmt_aux fmt s = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + + begin match s.elt with + | Decl d -> print_vdecl_aux ";" fmt d + + | Assn (p,e) -> + pp_open_box fmt 0; + print_exp_aux 0 fmt p; + pps " ="; ppsp (); + print_exp_aux 0 fmt e; + pps ";"; pp_close_box fmt () + + | SCall (e, es) -> + print_exp_aux 0 fmt e; print_exps_aux "(" ")" fmt es; pps ";" + + | Ret (eo) -> + pps "return"; + begin match eo with + | None -> () + | Some e -> pps " "; print_exp_aux 0 fmt e + end; pps ";" + + | If (e, b_then, opt_b_else) -> + pps "if ("; print_exp_aux 0 fmt e; pps ") "; + print_cond_aux fmt b_then opt_b_else + + | Cast(t, id, e, b_null, b_notnull) -> + pps "ifnull ("; print_id_aux fmt id; pps "="; print_exp_aux 0 fmt e; + pps ") "; + print_cond_aux fmt b_null b_notnull + + | While(e, b) -> + pps "while ("; print_exp_aux 0 fmt e; pps ") "; + print_block_aux fmt b + + | For(decls, eo, so, body) -> + pps "for ("; pp_open_hvbox fmt 0; + print_list_aux fmt (fun () -> pps ","; ppsp ()) (print_vdecl_aux "") decls; + pps ";"; ppsp (); + begin match eo with + | None -> (); + | Some e -> print_exp_aux 0 fmt e; + end; + pps ";"; ppsp (); + begin match so with + | None -> () + | Some s -> print_stmt_aux fmt s + end; pp_close_box fmt (); + pps ") "; print_block_aux fmt body + end + +let print_fdecl_aux fmt {elt={frtyp; fname; args; body}} = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let ppnl = pp_force_newline fmt in + + print_ret_ty_aux fmt frtyp; + pps @@ Printf.sprintf " %s(" fname; + pp_open_hbox fmt (); + print_list_aux fmt (fun () -> pps ","; ppsp ()) + (fun fmt -> fun (t, id) -> + print_ty_aux fmt t; + pps " "; + print_id_aux fmt id; + ) args; + pp_close_box fmt (); + pps ") "; print_block_aux fmt body; ppnl () + +let print_gdecl_aux fmt (gd:Ast.gdecl) = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + pp_open_hbox fmt (); + pps @@ Printf.sprintf "global %s =" gd.name; ppsp (); + print_exp_aux 0 fmt gd.init; pps ";"; + pp_close_box fmt () + +let print_field fmt f = + let pps = pp_print_string fmt in + pp_open_hbox fmt (); + print_ty_aux fmt f.ftyp; pps " "; pps f.fieldName; + pp_close_box fmt () + +let print_tdecl_aux fmt ((id, l):Ast.tdecl) = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + pp_open_hbox fmt (); + pps @@ Printf.sprintf "struct %s =" id; ppsp (); + pps "{"; + List.iter (fun s -> print_field fmt s; pps "; ") l; + pps "}"; + pp_close_box fmt () + +let print_decl_aux fmt g = + begin match g with + | Gvdecl d -> print_gdecl_aux fmt d.elt + | Gfdecl f -> print_fdecl_aux fmt f + | Gtdecl t -> print_tdecl_aux fmt t.elt + end + +let print_prog_aux fmt p = + let ppnl = pp_force_newline fmt in + pp_open_vbox fmt 0; + List.iter (fun g -> print_decl_aux fmt g; ppnl (); ppnl ()) p; + pp_close_box fmt () + +let print ppx x : unit = + pp_open_hvbox std_formatter 0; + ppx std_formatter x; + pp_close_box std_formatter (); + pp_print_newline std_formatter () + +let string_of ppx x : string = + pp_open_hvbox str_formatter 0; + ppx str_formatter x; + pp_close_box str_formatter (); + flush_str_formatter () + +let print_prog (p:prog) : unit = print print_prog_aux p +let string_of_prog (p:prog) : string = string_of print_prog_aux p + +let print_stmt (s:stmt node) : unit = print print_stmt_aux s +let string_of_stmt (s:stmt node) : string = string_of print_stmt_aux s + +let print_block (b:block) : unit = print print_block_aux b +let string_of_block (b:block) : string = string_of print_block_aux b + +let print_exp (e:exp node) : unit = print (print_exp_aux 0) e +let string_of_exp (e:exp node) : string = string_of (print_exp_aux 0) e + +let print_ty (t:ty) : unit = print print_ty_aux t +let string_of_ty (t:ty) : string = string_of print_ty_aux t + +(* AST to ML *) + +let sp = Printf.sprintf + +let ml_string_of_list (f: 'a -> string) (l: 'a list) : string = + sp "[ %s ]" (String.concat " ; " (List.map f l)) + +let ml_string_of_option (f: 'a -> string) (o: 'a option) : string = + begin match o with + | None -> sp "None" + | Some x -> sp "Some (%s)" (f x) + end + +(* TODO Change ml string printing for loc *) + +let ml_string_of_node (f: 'a -> string) ({elt;loc}: 'a node) = + sp "{ elt = %s; loc = %s }" (f elt) (Range.ml_string_of_range loc) + +let rec ml_string_of_ty (t:ty) : string = + match t with + | TBool -> "TBool" + | TInt -> "TInt" + | TRef r -> sp "TRef (%s)" (ml_string_of_reft r) + | TNullRef r -> sp "TNullRef (%s)" (ml_string_of_reft r) + +and ml_string_of_ret_ty r = + match r with + | RetVoid -> "TVoid" + | RetVal t -> ml_string_of_ty t + + +and ml_string_of_reft (r:rty) : string = + match r with + | RString -> "RString" + | RArray t -> sp "(RArray (%s))" (ml_string_of_ty t) + | RStruct id -> sp "(RStruct (%s))" id + | RFun (ts, t) -> sp "RFun (%s, %s)" + (ml_string_of_list ml_string_of_ty ts) + (ml_string_of_ret_ty t) + + +let ml_string_of_id : id -> string = (sp "\"%s\"") + +let ml_string_of_binop : binop -> string = function + | Add -> "Add" + | Sub -> "Sub" + | Mul -> "Mul" + | Eq -> "Eq" + | Neq -> "Neq" + | Lt -> "Lt" + | Lte -> "Lte" + | Gt -> "Gt" + | Gte -> "Gte" + | And -> "And" + | Or -> "Or" + | IAnd -> "IAnd" + | IOr -> "IOr" + | Shl -> "Shl" + | Shr -> "Shr" + | Sar -> "Sar" + +let ml_string_of_unop : unop -> string = function + | Neg -> "Neg" + | Lognot -> "Lognot" + | Bitnot -> "Bitnot" + +let rec ml_string_of_exp_aux (e: exp) : string = + begin match e with + | CNull r -> sp "CNull %s" (ml_string_of_reft r) + | CBool b -> sp "CBool %b" b + | CInt i -> sp "CInt %LiL" i + | CStr s -> sp "CStr %S" s + | CArr (t,cs) -> sp "CArr (%s,%s)" + (ml_string_of_ty t) + (ml_string_of_list ml_string_of_exp cs) + | CStruct (id, l) -> sp "CStruct (%s, %s)" + id + (ml_string_of_list ml_string_of_field l) + | Id id -> sp "Id %s" (ml_string_of_id id) + | Index (e, i) -> sp "Index (%s, %s)" + (ml_string_of_exp e) (ml_string_of_exp i) + | Call (e, exps) -> sp "Call (%s, %s)" + (ml_string_of_exp e) + (ml_string_of_list ml_string_of_exp exps) + | NewArr (t,e1,u,e2) -> sp "NewArr (%s,%s,%s,%s)" + (ml_string_of_ty t) (ml_string_of_exp e1) (ml_string_of_id u) (ml_string_of_exp e2) + | Proj(exp, id) -> sp "Proj (%s,%s)" (ml_string_of_exp exp) (ml_string_of_id id) + | Bop (b, e1, e2) -> sp "Bop (%s,%s,%s)" + (ml_string_of_binop b) (ml_string_of_exp e1) (ml_string_of_exp e2) + | Uop (u, e) -> sp "Uop (%s, %s)" + (ml_string_of_unop u) (ml_string_of_exp e) + | Length (e) -> sp "Length (%s)" (ml_string_of_exp e) + end + +and ml_string_of_exp (e:exp node) : string = + ml_string_of_node ml_string_of_exp_aux e + +and ml_string_of_field ((id, exp) : cfield) : string = + sp "%s = %s;" (ml_string_of_id id) (ml_string_of_exp exp) + +let ml_string_of_vdecl_aux (id,init:vdecl) : string = + sp "(%s, %s)" + (ml_string_of_id id) (ml_string_of_exp init) + +let ml_string_of_vdecl (d:vdecl node) : string = + ml_string_of_node ml_string_of_vdecl_aux d + +let rec ml_string_of_stmt_aux (s:stmt) : string = + match s with + | Assn (p, e) -> sp "Assn (%s,%s)" (ml_string_of_exp p) (ml_string_of_exp e) + | Decl d -> sp "Decl (%s)" (ml_string_of_vdecl_aux d) + | Ret e -> sp "Ret (%s)" (ml_string_of_option ml_string_of_exp e) + | SCall (exp, exps) -> + sp "SCall (%s, %s)" (ml_string_of_exp exp) (ml_string_of_list ml_string_of_exp exps) + | If (e,b1,b2) -> sp "If (%s,%s,%s)" + (ml_string_of_exp e) (ml_string_of_block b1) (ml_string_of_block b2) + | Cast (r, id, exp, null, notnull) -> + sp "Cast (%s,%s,%s,%s,%s)" + (ml_string_of_reft r) id (ml_string_of_exp exp) + (ml_string_of_block null) (ml_string_of_block notnull) + | For (d,e,s,b) -> sp "For (%s,%s,%s,%s)" + (ml_string_of_list ml_string_of_vdecl_aux d) + (ml_string_of_option ml_string_of_exp e) + (ml_string_of_option ml_string_of_stmt s) (ml_string_of_block b) + | While (e,b) -> sp "While (%s,%s)" (ml_string_of_exp e) (ml_string_of_block b) + +and ml_string_of_stmt (s:stmt node) : string = + ml_string_of_node ml_string_of_stmt_aux s + +and ml_string_of_block (b:block) : string = + ml_string_of_list ml_string_of_stmt b + +let ml_string_of_args : (ty * id) list -> string = + ml_string_of_list (fun (t,i) -> + sp "(%s,%s)" (ml_string_of_ty t) (ml_string_of_id i)) + +let rec ml_string_of_fdecl_aux (f:fdecl) : string = + sp "{ rtyp = %s; name = %s; args = %s; body = %s }" + (ml_string_of_ret_ty f.frtyp) (ml_string_of_id f.fname) + (ml_string_of_args f.args) (ml_string_of_block f.body) + +and ml_string_of_fdecl (f:fdecl node) : string = + ml_string_of_node ml_string_of_fdecl_aux f + +let ml_string_of_gdecl_aux (gd:gdecl) : string = + sp "{ name = %s; init = %s }" + (ml_string_of_id gd.name) (ml_string_of_exp gd.init) + +let ml_string_of_gdecl (d:gdecl node) : string = + ml_string_of_node ml_string_of_gdecl_aux d + +let ml_string_of_field {fieldName; ftyp} : string = + sp "{ fname = %s; typ = %s }" + (ml_string_of_id fieldName) (ml_string_of_ty ftyp) + +let ml_string_of_tdecl_aux (id,fs) : string = + sp "(id = %s, fs = (%s))" (ml_string_of_id id) (ml_string_of_list ml_string_of_field fs) + +let ml_string_of_tdecl (t:tdecl node) : string = + ml_string_of_node ml_string_of_tdecl_aux t + +let ml_string_of_decl : decl -> string = function + | Gvdecl d -> sp "Gvdecl (%s)" (ml_string_of_gdecl d) + | Gfdecl f -> sp "Gfdecl (%s)" (ml_string_of_fdecl f) + | Gtdecl t -> sp "Gtdecl (%s)" (ml_string_of_tdecl t) + +let ml_string_of_prog : prog -> string = + ml_string_of_list ml_string_of_decl diff --git a/hw5/backend.ml b/hw5/backend.ml new file mode 100644 index 0000000..beebfd6 --- /dev/null +++ b/hw5/backend.ml @@ -0,0 +1,479 @@ +(* ll ir compilation -------------------------------------------------------- *) + +open Ll +open X86 + +(* Overview ----------------------------------------------------------------- *) + +(* We suggest that you spend some time understinging this entire file and + how it fits with the compiler pipeline before making changes. The suggested + plan for implementing the compiler is provided on the project web page. +*) + + +(* helpers ------------------------------------------------------------------ *) + +(* Map LL comparison operations to X86 condition codes *) +let compile_cnd = function + | Ll.Eq -> X86.Eq + | Ll.Ne -> X86.Neq + | Ll.Slt -> X86.Lt + | Ll.Sle -> X86.Le + | Ll.Sgt -> X86.Gt + | Ll.Sge -> X86.Ge + +let imm_of_int (n:int) = Imm (Lit (Int64.of_int n)) + +(* Compute an indirect address that is a fixed byte offset from %rbp *) +let rbp_offset (offset:int) : X86.operand = + let amt = Int64.of_int offset in + Ind3 (Lit amt, Rbp) + +(* locals and layout -------------------------------------------------------- *) + +(* One key problem in compiling the LLVM IR is how to map its local + identifiers to X86 abstractions. For the best performance, one + would want to use an X86 register for each LLVM %uid. However, + since there are an unlimited number of %uids and only 16 registers, + doing so effectively is quite difficult. We will see later in the + course how _register allocation_ algorithms can do a good job at + this. + + A simpler, but less performant, implementation is to map each %uid + in the LLVM source to a _stack slot_ (i.e. a region of memory in + the stack). Since LLVMlite, unlike real LLVM, permits %uid locals + to store only 64-bit data, each stack slot is an 8-byte value. + + [ NOTE: For compiling LLVMlite, even i1 data values should be + represented as a 8-byte quad. This greatly simplifies code + generation. ] + + We call the datastructure that maps each %uid to its stack slot a + 'stack layout'. A stack layout maps a uid to an X86 operand for + accessing its contents. For this compilation strategy, the operand + is always an offset from %rbp (in bytes) that represents a storage slot in + the stack. +*) + +type layout = (uid * X86.operand) list + +(* A context contains the global type declarations (needed for getelementptr + calculations) and a stack layout. *) +type ctxt = { tdecls : (tid * ty) list + ; layout : layout + } + +(* useful for looking up items in tdecls or layouts *) +let lookup m x = List.assoc x m + + +(* compiling operands ------------------------------------------------------ *) + +(* LLVM IR instructions support several kinds of operands. + + LL local %uids live in stack slots, whereas global ids live at + global addresses that must be computed from a label. Constants are + immediately available, and the operand Null is the 64-bit 0 value. + + NOTE: two important facts about global identifiers: + + (1) You should use (Platform.mangle gid) to obtain a string + suitable for naming a global label on your platform (OS X expects + "_main" while linux expects "main"). + + (2) 64-bit assembly labels are not allowed as immediate operands. + That is, the X86 code: movq _gid %rax which looks like it should + put the address denoted by _gid into %rax is not allowed. + Instead, you need to compute an %rip-relative address using the + leaq instruction: leaq _gid(%rip). + + One strategy for compiling instruction operands is to use a + designated register (or registers) for holding the values being + manipulated by the LLVM IR instruction. You might find it useful to + implement the following helper function, whose job is to generate + the X86 instruction that moves an LLVM operand into a designated + destination (usually a register). +*) +let compile_operand ctxt dest : Ll.operand -> ins = + function + | Null -> Asm.(Movq, [~$0; dest]) + | Const i -> Asm.(Movq, [Imm (Lit i); dest]) + | Gid id -> Asm.(Leaq, [Ind3 (Lbl (Platform.mangle id), Rip); dest]) + | Id id -> Asm.(Movq, [lookup ctxt.layout id; dest]) + + +(* compiling call ---------------------------------------------------------- *) + +(* You will probably find it helpful to implement a helper function that + generates code for the LLVM IR call instruction. + + The code you generate should follow the x64 System V AMD64 ABI + calling conventions, which places the first six 64-bit (or smaller) + values in registers and pushes the rest onto the stack. Note that, + since all LLVM IR operands are 64-bit values, the first six + operands will always be placed in registers. (See the notes about + compiling fdecl below.) + + [ NOTE: It is the caller's responsibility to clean up arguments + pushed onto the stack, so you must free the stack space after the + call returns. ] + + [ NOTE: Don't forget to preserve caller-save registers (only if + needed). ] +*) + + +let arg_reg : int -> (X86.operand) option = function + | 0 -> Some (Reg Rdi) + | 1 -> Some (Reg Rsi) + | 2 -> Some (Reg Rdx) + | 3 -> Some (Reg Rcx) + | 4 -> Some (Reg R08) + | 5 -> Some (Reg R09) + | n -> None + +let compile_call ctxt fop args = + let op_to_rax = compile_operand ctxt (Reg Rax) in + let call_code, op = match fop with + | Gid g -> [], Imm (Lbl (Platform.mangle g)) + | Id _ -> [op_to_rax fop], (Reg Rax) + | _ -> failwith "call function operand was not a local or global id" + in + + let arg_code = + let (_, register_arg_code, stack_arg_code) = + List.fold_left (fun (i, r, s) (_,op) -> + let r, s = match arg_reg i with + | Some reg -> r @ (op_to_rax op :: Asm.([Movq, [~%Rax; reg]])), s + | None -> r, (op_to_rax op :: Asm.([Pushq, [~%Rax]])) @ s + in (i+1, r, s) + ) (0, [], []) args + in register_arg_code @ stack_arg_code + in + + arg_code @ call_code @ + (X86.Callq, [op]) :: + (if (List.length args) > 6 then + Asm.([Addq, [imm_of_int (8 * ((List.length args) - 6)); ~%Rsp]]) + else []) + +(* compiling getelementptr (gep) ------------------------------------------- *) + +(* The getelementptr instruction computes an address by indexing into + a datastructure, following a path of offsets. It computes the + address based on the size of the data, which is dictated by the + data's type. + + To compile getelmentptr, you must generate x86 code that performs + the appropriate arithemetic calculations. +*) + +(* [size_ty] maps an LLVMlite type to a size in bytes. + (needed for getelementptr) + + - the size of a struct is the sum of the sizes of each component + - the size of an array of t's with n elements is n * the size of t + - all pointers, I1, and I64 are 8 bytes + - the size of a named type is the size of its definition + + - Void, i8, and functions have undefined sizes according to LLVMlite. + Your function should simply return 0 in those cases +*) +let rec size_ty (tdecls:(tid * ty) list) (t:Ll.ty) : int = + begin match t with + | Void | I8 | Fun _ -> 0 + | I1 | I64 | Ptr _ -> 8 (* Target 64-bit only subset of X86 *) + | Struct ts -> List.fold_left (fun acc t -> acc + (size_ty tdecls t)) 0 ts + | Array (n, t) -> n * (size_ty tdecls t) + | Namedt id -> size_ty tdecls (List.assoc id tdecls) + end + +(* Compute the size of the offset (in bytes) of the nth element of a region + of memory whose types are given by the list. Also returns the nth type. *) +let index_into tdecls (ts:ty list) (n:int) : int * ty = + let rec loop ts n acc = + begin match (ts, n) with + | (u::_, 0) -> (acc, u) + | (u::us, n) -> loop us (n-1) (acc + (size_ty tdecls u)) + | _ -> failwith "index_into encountered bogus index" + end + in loop ts n 0 + + +(* Generates code that computes a pointer value. + + 1. op must be of pointer type: t* + + 2. the value of op is the base address of the calculation + + 3. the first index in the path is treated as the index into an array + of elements of type t located at the base address + + 4. subsequent indices are interpreted according to the type t: + + - if t is a struct, the index must be a constant n and it + picks out the n'th element of the struct. [ NOTE: the offset + within the struct of the n'th element is determined by the + sizes of the types of the previous elements ] + + - if t is an array, the index can be any operand, and its + value determines the offset within the array. + + - if t is any other type, the path is invalid + + 5. if the index is valid, the remainder of the path is computed as + in (4), but relative to the type f the sub-element picked out + by the path so far +*) +let compile_gep (ctxt:ctxt) (op : Ll.ty * Ll.operand) (path: Ll.operand list) : ins list = + let op_to_rax = compile_operand ctxt (Reg Rax) in + let rec loop ty path code = + match (ty, path) with + | (_, []) -> List.rev code + + | (Struct ts, Const n::rest) -> + let (offset, u) = index_into ctxt.tdecls ts (Int64.to_int n) in + loop u rest @@ Asm.(Addq, [~$offset; ~%Rax])::code + + | (Array(_, u), Const n::rest) -> + (* Statically calculate the offset *) + let offset = (size_ty ctxt.tdecls u) * (Int64.to_int n) in + loop u rest @@ Asm.(Addq, [~$offset; ~%Rax])::code + + | (Array(_, u), offset_op::rest) -> + loop u rest @@ + Asm.([ Addq, [~%Rcx; ~%Rax] + ; Imulq, [imm_of_int @@ size_ty ctxt.tdecls u; ~%Rax] ]) + @ (op_to_rax offset_op) :: + Asm.(Movq, [~%Rax; ~%Rcx]) + :: code + + | (Namedt t, p) -> loop (List.assoc t ctxt.tdecls) p code + + | _ -> failwith "compile_gep encountered unsupported getelementptr data" in + + match op with + | (Ptr t, op) -> loop (Array(0, t)) path [op_to_rax op] + | _ -> failwith "compile_gep got incorrect parameters" + + +(* compiling instructions -------------------------------------------------- *) + +(* The result of compiling a single LLVM instruction might be many x86 + instructions. We have not determined the structure of this code + for you. Some of the instructions require only a couple of assembly + instructions, while others require more. We have suggested that + you need at least compile_operand, compile_call, and compile_gep + helpers; you may introduce more as you see fit. + + Here are a few notes: + + - Icmp: the Setb instruction may be of use. Depending on how you + compile Cbr, you may want to ensure that the value produced by + Icmp is exactly 0 or 1. + + - Load & Store: these need to dereference the pointers. Const and + Null operands aren't valid pointers. Don't forget to + Platform.mangle the global identifier. + + - Alloca: needs to return a pointer into the stack + + - Bitcast: does nothing interesting at the assembly level +*) +let compile_insn (ctxt:ctxt) ((uid:uid), (i:Ll.insn)) : X86.ins list = + let op_to = compile_operand ctxt in + let op_to_rax = op_to (Reg Rax) in (* Move the value of op into rax *) + let op_to_rcx = op_to (Reg Rcx) in (* Move the value of op into rax *) + let dst = lookup ctxt.layout uid in + match i with + | Binop (bop, t, op1, op2) -> + let bin op = + (op_to_rax op1) :: + (op_to_rcx op2) :: + Asm.([ op, [~%Rcx; ~%Rax] + ; Movq, [~%Rax; dst] ]) + in + begin match bop with + | Ll.Add -> bin Addq + | Ll.Sub -> bin Subq + | Ll.Mul -> bin Imulq + | Ll.Shl -> bin Shlq + | Ll.Lshr -> bin Shrq + | Ll.Ashr -> bin Sarq + | Ll.And -> bin Andq + | Ll.Or -> bin Orq + | Ll.Xor -> bin Xorq + end + + (* Alloca instructions allocate an fresh stack slot and + move the address of the newly allocated storage into the + destination uid. *) + | Alloca (_t) -> Asm.([ Pushq, [~$0] + ; Movq, [~%Rsp; dst] ]) + + (* Load dereferences the pointer value stored in a local. + Global and constant pointers don't need indirection. *) + | Load (t, op) -> (op_to_rax op) :: Asm.([ Movq, [Ind2 Rax; ~%Rcx] + ; Movq, [~%Rcx; dst] ]) + + (* Store also needs to dereference the destination pointer if it's a global *) + | Store (_, src, (Id uid as dest)) -> + (op_to_rcx src) :: + (op_to_rax dest) :: Asm.([Movq, [~%Rcx; Ind2 Rax]]) + | Store (_, src, Gid gid) -> + (op_to_rax src) :: Asm.([Movq, [~%Rax; Ind3 (Lbl (Platform.mangle gid), Rip)]]) + | Store (_, _, _) -> failwith "store destination was not a local or global id" + + (* Treat LL i1 values as words, so zero-out the rest of the bits *) + | Icmp (cnd, _, op1, op2) -> (op_to_rax op1) :: + (op_to_rcx op2) :: + Asm.([ Cmpq, [~%Rcx; ~%Rax] + ; (Set (compile_cnd cnd)), [dst] + ; Andq, [imm_of_int 1; dst] ]) + + | Call(ret_ty, fop, args) -> + let code = compile_call ctxt fop args in + code @ + (match ret_ty with + | Void -> [] + | _ -> Asm.([Movq, [~%Rax; dst]])) + + (* Bitcast is effectively just a Mov at the assembly level *) + | Bitcast (_, op, _) -> (op_to_rax op) :: Asm.([Movq, [~%Rax; dst]]) + + (* Defer to the helper function to compute the pointer value *) + | Gep (t, op, path) -> + let code = compile_gep ctxt (t, op) path in + code @ Asm.([ Movq, [~%Rax; dst] ]) + + +(* compiling terminators --------------------------------------------------- *) + +(* prefix the function name [fn] to a label to ensure that the X86 labels are + globally unique . *) +let mk_lbl (fn:string) (l:string) = fn ^ "." ^ l + +(* Compile block terminators is not too difficult: + + - Ret should properly exit the function: freeing stack space, + restoring the value of %rbp, and putting the return value (if + any) in %rax. + + - Br should jump + + - Cbr branch should treat its operand as a boolean conditional +*) +let compile_terminator (fn:string) (ctxt:ctxt) (t:Ll.terminator) : ins list = + let epilogue = Asm.([ Movq, [~%Rbp; ~%Rsp] + ; Popq, [~%Rbp] + ; Retq, []]) + in match t with + | Ll.Ret (_, None) -> epilogue + | Ll.Ret (_, Some o) -> (compile_operand ctxt (Reg Rax) o) :: epilogue + | Ll.Br l -> Asm.([ Jmp, [~$$(mk_lbl fn l)] ]) + | Ll.Cbr (o, l1, l2) -> (compile_operand ctxt (Reg Rax) o) + :: Asm.([ Cmpq, [~$0; ~%Rax] + ; J (X86.Neq) , [~$$(mk_lbl fn l1)] + ; Jmp, [~$$(mk_lbl fn l2)] + ]) + +(* compiling blocks --------------------------------------------------------- *) + +let compile_block (fn:string) (ctxt:ctxt) (blk:Ll.block) : ins list = + let insns = List.map (compile_insn ctxt) blk.insns |> List.flatten in + let term = compile_terminator fn ctxt (snd blk.term) in + insns @ term + +let compile_lbl_block fn lbl ctxt blk : elem = + Asm.text (mk_lbl fn lbl) (compile_block fn ctxt blk) + + + +(* compile_fdecl ------------------------------------------------------------ *) +let rbp_offset n = Ind3 (Lit (Int64.of_int @@ 8 * n), Rbp) + +(* This helper function computes the location of the nth incoming + function argument: either in a register or relative to %rbp, + according to the calling conventions. You might find it useful for + compile_fdecl. + + [ NOTE: the first six arguments are numbered 0 .. 5 ] +*) +let arg_loc (n : int) : operand = + begin match arg_reg n with + | Some op -> op + | None -> rbp_offset (n-4) + end + +(* We suggest that you create a helper function that computes the + stack layout for a given function declaration. + + - each function argument should be copied into a stack slot + - in this (inefficient) compilation strategy, each local id + is also stored as a stack slot. + - see the discussion about locals + +*) +let stack_layout (args : uid list) ((block, lbled_blocks):cfg) : layout = + let lbled_block_isns = List.map (fun (_, blk) -> blk.insns) lbled_blocks in + let cfg_uids = List.map fst (block.insns @ (List.flatten lbled_block_isns)) in + List.mapi (fun i uid -> (uid, rbp_offset (-i - 1))) (args @ cfg_uids) + +(* The code for the entry-point of a function must do several things: + + - since our simple compiler maps local %uids to stack slots, + compiling the control-flow-graph body of an fdecl requires us to + compute the layout (see the discussion of locals and layout) + + - the function code should also comply with the calling + conventions, typically by moving arguments out of the parameter + registers (or stack slots) into local storage space. For our + simple compilation strategy, that local storage space should be + in the stack. (So the function parameters can also be accounted + for in the layout.) + + - the function entry code should allocate the stack storage needed + to hold all of the local stack slots. +*) +let compile_fdecl (tdecls:(tid * ty) list) (name:string) ({ f_ty; f_param; f_cfg }:fdecl) : prog = + let entry_name = (Platform.mangle name) in + let layout = stack_layout f_param f_cfg in + let init_arg_code = + (List.mapi (fun i uid -> Asm.([ Movq, [arg_loc i; ~%Rax] + ; Movq, [~%Rax; lookup layout uid] ]) ) + f_param) |> List.flatten + in + let ctxt = { tdecls; layout } in + let tmpsize = 8 * (List.length layout) in + + let prologue = Asm.([ Pushq, [~%Rbp] + ; Movq, [~%Rsp; ~%Rbp] + ; Subq, [~$tmpsize; ~%Rsp] ]) + @ init_arg_code + in + let (entry, body) = f_cfg in + let entry_insns = compile_block name ctxt entry in + (Asm.gtext entry_name @@ prologue @ entry_insns) :: + (List.map (fun (lbl, blk) -> compile_lbl_block name lbl ctxt blk) body) + + +(* compile_gdecl ------------------------------------------------------------ *) +(* Compile a global value into an X86 global data declaration and map + a global uid to its associated X86 label. +*) +let rec compile_ginit : ginit -> X86.data list = function + | GNull -> [Quad (Lit 0L)] + | GGid gid -> [Quad (Lbl (Platform.mangle gid))] + | GInt c -> [Quad (Lit c)] + | GString s -> [Asciz s] + | GArray gs | GStruct gs -> List.map compile_gdecl gs |> List.flatten + | GBitcast (t1,g,t2) -> compile_ginit g + +and compile_gdecl (_, g) = compile_ginit g + + +(* compile_prog ------------------------------------------------------------- *) +let compile_prog {tdecls; gdecls; fdecls} : X86.prog = + let g = fun (lbl, gdecl) -> Asm.data (Platform.mangle lbl) (compile_gdecl gdecl) in + let f = fun (name, fdecl) -> compile_fdecl tdecls name fdecl in + (List.map g gdecls) @ (List.map f fdecls |> List.flatten) diff --git a/hw5/driver.ml b/hw5/driver.ml new file mode 100644 index 0000000..dbcc82a --- /dev/null +++ b/hw5/driver.ml @@ -0,0 +1,150 @@ +open Printf +open Platform + +(* configuration flags ------------------------------------------------------ *) +let print_ll_flag = ref false +let print_x86_flag = ref false +let print_ast_flag = ref false +let print_oat_flag = ref false +let clang = ref false +let assemble = ref true +let link = ref true +let executable_filename = ref "a.out" +let execute_x86 = ref false +let print_regs_flag = ref false + +let link_files = ref [] +let add_link_file path = + link_files := path :: (!link_files) +let files : string list ref = ref [] + +let print_banner s = + let rec dashes n = if n = 0 then "" else "-"^(dashes (n-1)) in + printf "%s %s\n%!" (dashes (79 - (String.length s))) s + +let print_ll file ll_ast = + print_banner (file ^ ".ll"); + print_endline (Llutil.string_of_prog ll_ast) + +let print_x86 file asm_str = + print_banner file; + print_endline asm_str + +let read_file (file:string) : string = + let channel = open_in file in + let lines = ref [] in + try while true; do + lines := input_line channel :: !lines + done; "" + with End_of_file -> + close_in channel; + String.concat "\n" (List.rev !lines) + +let write_file (file:string) (out:string) = + let channel = open_out file in + fprintf channel "%s" out; + close_out channel + +let parse_ll_file filename = + let program = read_file filename |> + Lexing.from_string |> + Llparser.prog Lllexer.token + in + program + +let parse_oat_file filename = + let lexbuf = read_file filename |> + Lexing.from_string + in + try + Parser.prog Lexer.token lexbuf + with + | Parser.Error -> failwith @@ Printf.sprintf "Parse error at: %s" + (Range.string_of_range (Range.lex_range lexbuf)) + + +let print_oat file ll_ast = + print_banner (file ^ ".oat"); + Astlib.print_prog ll_ast + +let print_ast p = Printf.printf "\n%s\n\n" (Astlib.ml_string_of_prog p) + +let run_executable arg pr = + let cmd = sprintf "%s%s %s" dot_path pr arg in + sh cmd (fun _ i -> i) + +let run_executable_to_tmpfile arg pr tmp = + let cmd = sprintf "%s%s %d > %s 2>&1" dot_path pr arg tmp in + sh cmd ignore_error + +let run_program (args:string) (executable:string) (tmp_out:string) : string = + let cmd = sprintf "%s%s %s > %s 2>&1" dot_path executable args tmp_out in + let result = sh cmd (fun _ i -> i) in + (read_file tmp_out) ^ (string_of_int result) + +let process_ll_ast path file ll_ast = + if !print_ll_flag then print_ll file ll_ast; + let dot_s_file = Platform.gen_name !Platform.output_path file ".s" in + let dot_o_file = Platform.gen_name !Platform.output_path file ".o" in + if !clang + then (Platform.verb "* compiling with clang\n"; + Platform.clang_compile path dot_s_file; + if !print_x86_flag + then (print_banner dot_s_file; + Platform.sh (Printf.sprintf "cat %s" dot_s_file) Platform.raise_error)) + else (let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + if !print_x86_flag then begin + print_x86 dot_s_file asm_str + end; + write_file dot_s_file asm_str); + if !assemble then Platform.assemble dot_s_file dot_o_file; + add_link_file dot_o_file + +let string_of_ll_ast path ll_ast = + let ll_str = Llutil.string_of_prog ll_ast in + let prog = Printf.sprintf "; generated from: %s\ntarget triple = \"%s\"\n%s\n" + path !Platform.target_triple ll_str in + prog + +let process_ll_file path file = + Platform.verb @@ Printf.sprintf "* processing file: %s\n" path; + let ll_ast = parse_ll_file path in + process_ll_ast path file ll_ast + +let process_oat_ast path file oat_ast = + if !print_oat_flag then print_oat file oat_ast; + if !print_ast_flag then print_ast oat_ast; + Typechecker.typecheck_program oat_ast; + let ll_ast = Frontend.cmp_prog oat_ast in + let dot_ll_file = Platform.gen_name !Platform.output_path file ".ll" in + Platform.verb @@ Printf.sprintf "writing file: %s\n" dot_ll_file; + let prog = string_of_ll_ast path ll_ast in + write_file dot_ll_file prog; + process_ll_ast dot_ll_file file ll_ast + +let process_oat_file path basename = + Platform.verb @@ Printf.sprintf "* processing file: %s\n" path; + let oat_ast = parse_oat_file path in + process_oat_ast path basename oat_ast + +let process_file path = + let basename, ext = Platform.path_to_basename_ext path in + begin match ext with + | "oat" -> process_oat_file path basename + | "ll" -> process_ll_file path basename + | "o" -> add_link_file path + | "c" -> add_link_file path + | _ -> failwith @@ Printf.sprintf "found unsupported file type: %s" path + end + +let process_files files = + if (List.length files) > 0 then begin + List.iter process_file files; + ( if !assemble && !link then + Platform.link (List.rev !link_files@["runtime.c"]) !executable_filename ); + ( if !assemble && !link && !execute_x86 then + let ret = run_executable "" !executable_filename in + print_banner @@ Printf.sprintf "Executing: %s" !executable_filename; + Printf.printf "* %s returned %d\n" !executable_filename ret ) + end diff --git a/hw5/frontend.ml b/hw5/frontend.ml new file mode 100644 index 0000000..4c537f1 --- /dev/null +++ b/hw5/frontend.ml @@ -0,0 +1,645 @@ +open Ll +open Llutil +open Ast + +(* instruction streams ------------------------------------------------------ *) + +(* As in the last project, we'll be working with a flattened representation + of LLVMlite programs to make emitting code easier. This version + additionally makes it possible to emit elements will be gathered up and + "hoisted" to specific parts of the constructed CFG + - G of gid * Ll.gdecl: allows you to output global definitions in the middle + of the instruction stream. You will find this useful for compiling string + literals + - E of uid * insn: allows you to emit an instruction that will be moved up + to the entry block of the current function. This will be useful for + compiling local variable declarations +*) + +type elt = + | L of Ll.lbl (* block labels *) + | I of uid * Ll.insn (* instruction *) + | T of Ll.terminator (* block terminators *) + | G of gid * Ll.gdecl (* hoisted globals (usually strings) *) + | E of uid * Ll.insn (* hoisted entry block instructions *) + +type stream = elt list +let ( >@ ) x y = y @ x +let ( >:: ) x y = y :: x +let lift : (uid * insn) list -> stream = List.rev_map (fun (x,i) -> I (x,i)) + +(* Build a CFG and collection of global variable definitions from a stream *) +let cfg_of_stream (code:stream) : Ll.cfg * (Ll.gid * Ll.gdecl) list = + let gs, einsns, insns, term_opt, blks = List.fold_left + (fun (gs, einsns, insns, term_opt, blks) e -> + match e with + | L l -> + begin match term_opt with + | None -> + if (List.length insns) = 0 then (gs, einsns, [], None, blks) + else failwith @@ Printf.sprintf "build_cfg: block labeled %s has\ + no terminator" l + | Some term -> + (gs, einsns, [], None, (l, {insns; term})::blks) + end + | T t -> (gs, einsns, [], Some (Llutil.Parsing.gensym "tmn", t), blks) + | I (uid,insn) -> (gs, einsns, (uid,insn)::insns, term_opt, blks) + | G (gid,gdecl) -> ((gid,gdecl)::gs, einsns, insns, term_opt, blks) + | E (uid,i) -> (gs, (uid, i)::einsns, insns, term_opt, blks) + ) ([], [], [], None, []) code + in + match term_opt with + | None -> failwith "build_cfg: entry block has no terminator" + | Some term -> + let insns = einsns @ insns in + ({insns; term}, blks), gs + + +(* compilation contexts ----------------------------------------------------- *) + +(* To compile OAT variables, we maintain a mapping of source identifiers to the + corresponding LLVMlite operands. Bindings are added for global OAT variables + and local variables that are in scope. *) + +module Ctxt = struct + + type t = (Ast.id * (Ll.ty * Ll.operand)) list + let empty = [] + + (* Add a binding to the context *) + let add (c:t) (id:id) (bnd:Ll.ty * Ll.operand) : t = (id,bnd)::c + + (* Lookup a binding in the context *) + let lookup (id:Ast.id) (c:t) : Ll.ty * Ll.operand = + List.assoc id c + +end + +(* Mapping of identifiers representing struct definitions to + * the corresponding name-to-name-to-type map. + + Note: You will need to use these operations when compiling structures. +*) +module TypeCtxt = struct + type t = (Ast.id * Ast.field list) list + let empty = [] + + let add c id bnd = (id, bnd) :: c + let lookup id c = List.assoc id c + let lookup_field st_name f_name (c : t) = + let rec lookup_field_aux f_name l = + match l with + | [] -> failwith "TypeCtxt.lookup_field: Not_found" + | h :: t -> if h.fieldName = f_name then h.ftyp else lookup_field_aux f_name t in + lookup_field_aux f_name (List.assoc st_name c) + + let rec index_of f l i = + match l with + | [] -> None + | h :: t -> if h.fieldName = f then Some i else index_of f t (i + 1) + + (* Return the index of a field in the struct. *) + let index_of_field_opt st f (c : t) = + index_of f (List.assoc st c) 0 + + let index_of_field st f c = + match index_of_field_opt st f c with + | None -> failwith "index_of_field: Not found" + | Some x -> x + + (* Return a pair of base type and index into struct *) + let rec lookup_field_name (st:Ast.id) (f:Ast.id) (c : t) : (Ast.ty * Int64.t) = + let fields = lookup st c in + match index_of f fields 0 with + | None -> failwith "no such field" + | Some x -> List.(nth fields x).ftyp, Int64.of_int x +end + +(* compiling OAT types ------------------------------------------------------ *) + +(* The mapping of source types onto LLVMlite is straightforward. Booleans and ints + are represented as the the corresponding integer types. OAT strings are + pointers to bytes (I8). Arrays are the most interesting type: they are + represented as pointers to structs where the first component is the number + of elements in the following array. + + NOTE: structure types are named, so they compile to their named form +*) + +let rec cmp_ty (ct : TypeCtxt.t) : Ast.ty -> Ll.ty = function + | Ast.TBool -> I1 + | Ast.TInt -> I64 + | Ast.TRef r -> Ptr (cmp_rty ct r) + | Ast.TNullRef r -> Ptr (cmp_rty ct r) + + +and cmp_ret_ty ct : Ast.ret_ty -> Ll.ty = function + | Ast.RetVoid -> Void + | Ast.RetVal t -> cmp_ty ct t + +and cmp_fty ct (ts, r) : Ll.fty = + List.map (cmp_ty ct) ts, cmp_ret_ty ct r + +and cmp_rty ct : Ast.rty -> Ll.ty = function + | Ast.RString -> I8 + | Ast.RArray u -> Struct [I64; Array(0, cmp_ty ct u)] + | Ast.RStruct r -> Namedt r + | Ast.RFun (ts, t) -> + let args, ret = cmp_fty ct (ts, t) in + Fun (args, ret) + +let typ_of_binop : Ast.binop -> Ast.ty * Ast.ty * Ast.ty = function + | Add | Mul | Sub | Shl | Shr | Sar | IAnd | IOr -> (TInt, TInt, TInt) + | Eq | Neq | Lt | Lte | Gt | Gte -> (TInt, TInt, TBool) + | And | Or -> (TBool, TBool, TBool) + +let typ_of_unop : Ast.unop -> Ast.ty * Ast.ty = function + | Neg | Bitnot -> (TInt, TInt) + | Lognot -> (TBool, TBool) + + +(* Some useful helper functions *) + +(* Generate a fresh temporary identifier. Since OAT identifiers cannot begin + with an underscore, these should not clash with any source variables *) +let gensym : string -> string = + let c = ref 0 in + fun (s:string) -> incr c; Printf.sprintf "_%s%d" s (!c) + +(* Amount of space an Oat type takes when stored in the satck, in bytes. + Note that since structured values are manipulated by reference, all + Oat values take 8 bytes on the stack. +*) +let size_oat_ty (t : Ast.ty) = 8L + + + + +(* Generate code to allocate an array of source type TRef (RArray t) of the + given size. Note "size" is an operand whose value can be computed at + runtime *) +let oat_alloc_array ct (t:Ast.ty) (size:Ll.operand) : Ll.ty * operand * stream = + let ans_id, arr_id = gensym "array", gensym "raw_array" in + let ans_ty = cmp_ty ct @@ TRef (RArray t) in + let arr_ty = Ptr I64 in + ans_ty, Id ans_id, lift + [ arr_id, Call(arr_ty, Gid "oat_alloc_array", [I64, size]) + ; ans_id, Bitcast(arr_ty, Id arr_id, ans_ty) ] + + +(* STRUCT TASK: Complete this helper function that allocates an oat structure on the + heap and returns a target operand with the appropriate reference. + + - generate a call to 'oat_malloc' and use bitcast to convert the + resulting pointer to the right type + + - make sure to calculate the correct amount of space to allocate! +*) +let oat_alloc_struct ct (id:Ast.id) : Ll.ty * operand * stream = + failwith "TODO: oat_alloc_struct" + + +let str_arr_ty s = Array(1 + String.length s, I8) +let i1_op_of_bool b = Ll.Const (if b then 1L else 0L) +let i64_op_of_int i = Ll.Const (Int64.of_int i) + +let cmp_binop t (b : Ast.binop) : Ll.operand -> Ll.operand -> Ll.insn = + let ib b op1 op2 = Ll.Binop (b, t, op1, op2) in + let ic c op1 op2 = Ll.Icmp (c, t, op1, op2) in + match b with + | Ast.Add -> ib Ll.Add + | Ast.Mul -> ib Ll.Mul + | Ast.Sub -> ib Ll.Sub + | Ast.And -> ib Ll.And + | Ast.IAnd -> ib Ll.And + | Ast.IOr -> ib Ll.Or + | Ast.Or -> ib Ll.Or + | Ast.Shl -> ib Ll.Shl + | Ast.Shr -> ib Ll.Lshr + | Ast.Sar -> ib Ll.Ashr + + | Ast.Eq -> ic Ll.Eq + | Ast.Neq -> ic Ll.Ne + | Ast.Lt -> ic Ll.Slt + | Ast.Lte -> ic Ll.Sle + | Ast.Gt -> ic Ll.Sgt + | Ast.Gte -> ic Ll.Sge + +(* Compiles an expression exp in context c, outputting the Ll operand that will + receive the value of the expression, and the stream of instructions + implementing the expression. +*) +let rec cmp_exp (tc : TypeCtxt.t) (c:Ctxt.t) (exp:Ast.exp node) : Ll.ty * Ll.operand * stream = + match exp.elt with + | Ast.CInt i -> I64, Const i, [] + | Ast.CNull r -> cmp_ty tc (TNullRef r), Null, [] + | Ast.CBool b -> I1, i1_op_of_bool b, [] + + | Ast.CStr s -> + let gid = gensym "str_arr" in + let str_typ = str_arr_ty s in + let uid = gensym "str" in + Ptr I8, Id uid, [] + >:: G(gid, (str_typ, GString s)) + >:: I(uid, Gep(Ptr str_typ, Gid gid, [Const 0L; Const 0L;])) + + | Ast.Bop (bop, e1, e2) -> + let t, _, ret_ty = typ_of_binop bop in + let ll_t = cmp_ty tc t in + let op1, code1 = cmp_exp_as tc c e1 ll_t in + let op2, code2 = cmp_exp_as tc c e2 ll_t in + let ans_id = gensym "bop" in + cmp_ty tc ret_ty, Id ans_id, code1 >@ code2 >:: I(ans_id, cmp_binop ll_t bop op1 op2) + + | Ast.Uop (uop, e) -> + let t, ret_ty = typ_of_unop uop in + let op, code = cmp_exp_as tc c e (cmp_ty tc t) in + let ans_id = gensym "unop" in + let cmp_uop op = function + | Ast.Neg -> Binop (Sub, I64, i64_op_of_int 0, op) + | Ast.Lognot -> Icmp (Eq, I1, op, i1_op_of_bool false) + | Ast.Bitnot -> Binop (Xor, I64, op, i64_op_of_int (-1)) in + cmp_ty tc ret_ty, Id ans_id, code >:: I (ans_id, cmp_uop op uop) + + | Ast.Id id -> + let t, op = Ctxt.lookup id c in + begin match t with + | Ptr (Fun _) -> t, op, [] + | Ptr t -> + let ans_id = gensym id in + t, Id ans_id, [I(ans_id, Load(Ptr t, op))] + | _ -> failwith "broken invariant: identifier not a pointer" + end + + (* ARRAY TASK: complete this case to compilet the length(e) expression. + The emitted code should yield the integer stored as part + of the array struct representation. + *) + | Ast.Length e -> + failwith "todo:implement Ast.Length case" + + | Ast.Index (e, i) -> + let ans_ty, ptr_op, code = cmp_exp_lhs tc c exp in + let ans_id = gensym "index" in + ans_ty, Id ans_id, code >:: I(ans_id, Load(Ptr ans_ty, ptr_op)) + + | Ast.Call (f, es) -> + cmp_call tc c f es + + | Ast.CArr (elt_ty, cs) -> + let size_op = Ll.Const (Int64.of_int @@ List.length cs) in + let arr_ty, arr_op, alloc_code = oat_alloc_array tc elt_ty size_op in + let ll_elt_ty = cmp_ty tc elt_ty in + let add_elt s (i, elt) = + let elt_op, elt_code = cmp_exp_as tc c elt ll_elt_ty in + let ind = gensym "ind" in + s >@ elt_code >@ lift + [ ind, Gep(arr_ty, arr_op, [Const 0L; Const 1L; i64_op_of_int i ]) + ; "", Store(ll_elt_ty, elt_op, Id ind) ] + in + let ind_code = List.(fold_left add_elt [] @@ mapi (fun i e -> i, e) cs) in + arr_ty, arr_op, alloc_code >@ ind_code + + (* ARRAY TASK: Modify the compilation of the NewArr construct to implement the + initializer: + - the initializer is a loop that uses id as the index + - each iteration of the loop the code evaluates e2 and assigns it + to the index stored in id. + + Note: You can either write code to generate the LL loop directly, or + you could write the loop using abstract syntax and then call cmp_stmt to + compile that into LL code... + *) + | Ast.NewArr (elt_ty, e1, id, e2) -> + let _, size_op, size_code = cmp_exp tc c e1 in + let arr_ty, arr_op, alloc_code = oat_alloc_array tc elt_ty size_op in + arr_ty, arr_op, size_code >@ alloc_code + + (* STRUCT TASK: complete this code that compiles struct expressions. + For each field component of the struct + - use the TypeCtxt operations to compute getelementptr indices + - compile the initializer expression + - store the resulting value into the structure + *) + | Ast.CStruct (id, l) -> + failwith "TODO: Ast.CStruct" + + | Ast.Proj (e, id) -> + let ans_ty, ptr_op, code = cmp_exp_lhs tc c exp in + let ans_id = gensym "proj" in + ans_ty, Id ans_id, code >:: I(ans_id, Load(Ptr ans_ty, ptr_op)) + + +and cmp_exp_lhs (tc : TypeCtxt.t) (c:Ctxt.t) (e:exp node) : Ll.ty * Ll.operand * stream = + match e.elt with + | Ast.Id x -> + let t, op = Ctxt.lookup x c in + t, op, [] + + (* STRUCT TASK: Complete this code that emits LL code to compute the + address of the i'th field from a value of struct type. Note that + the actual load from the address to project the value is handled by the + Ast.proj case of the cmp_exp function (above). + + You will find the TypeCtxt.lookup_field_name function helpful. + *) + | Ast.Proj (e, i) -> + failwith "todo: Ast.Proj case of cmp_exp_lhs" + + + (* ARRAY TASK: Modify this index code to call 'oat_assert_array_length' before doing the + GEP calculation. This should be very straightforward, except that you'll need to use a Bitcast. + You might want to take a look at the implementation of 'oat_assert_array_length' + in runtime.c. (That check is where the infamous "ArrayIndexOutOfBounds" exception would + be thrown...) + *) + | Ast.Index (e, i) -> + let arr_ty, arr_op, arr_code = cmp_exp tc c e in + let _, ind_op, ind_code = cmp_exp tc c i in + let ans_ty = match arr_ty with + | Ptr (Struct [_; Array (_,t)]) -> t + | _ -> failwith "Index: indexed into non pointer" in + let ptr_id, tmp_id = gensym "index_ptr", gensym "tmp" in + ans_ty, (Id ptr_id), + arr_code >@ ind_code >@ lift + [ptr_id, Gep(arr_ty, arr_op, [i64_op_of_int 0; i64_op_of_int 1; ind_op]) ] + + + + | _ -> failwith "invalid lhs expression" + +and cmp_call (tc : TypeCtxt.t) (c:Ctxt.t) (exp:Ast.exp node) (es:Ast.exp node list) : Ll.ty * Ll.operand * stream = + let (t, op, s) = cmp_exp tc c exp in + let (ts, rt) = + match t with + | Ptr (Fun (l, r)) -> l, r + | _ -> failwith "nonfunction passed to cmp_call" in + let args, args_code = List.fold_right2 + (fun e t (args, code) -> + let arg_op, arg_code = cmp_exp_as tc c e t in + (t, arg_op)::args, arg_code @ code + ) es ts ([],[]) in + let res_id = gensym "result" in + rt, Id res_id, s >@ args_code >:: I(res_id, Call(rt, op, args)) + +and cmp_exp_as (tc : TypeCtxt.t) (c:Ctxt.t) (e:Ast.exp node) (t:Ll.ty) : Ll.operand * stream = + let from_t, op, code = cmp_exp tc c e in + if from_t = t then op, code + else let res_id = gensym "cast" in + Id res_id, code >:: I(res_id, Bitcast(from_t, op, t)) + +(* Compile a statement in context c with return typ rt. Return a new context, + possibly extended with new local bindings, and the instruction stream + implementing the statement. + + Left-hand-sides of assignment statements must either be OAT identifiers, + or an index into some arbitrary expression of array type. Otherwise, the + program is not well-formed and your compiler may throw an error. + *) +and cmp_stmt (tc : TypeCtxt.t) (c:Ctxt.t) (rt:Ll.ty) (stmt:Ast.stmt node) : Ctxt.t * stream = + + match stmt.elt with + | Ast.Decl (id, init) -> + let ll_ty, init_op, init_code = cmp_exp tc c init in + let res_id = gensym id in + let c' = Ctxt.add c id (Ptr ll_ty, Id res_id) in + c', init_code + >:: E(res_id, Alloca ll_ty) + >:: I("", Store (ll_ty, init_op, Id res_id)) + + | Ast.Assn (path ,e) -> + let _, pop, path_code = cmp_exp_lhs tc c path in + let ll_ty, eop, exp_code = cmp_exp tc c e in + c, path_code >@ exp_code >:: I("", (Store (ll_ty, eop, pop))) + + | Ast.If (guard, st1, st2) -> + let guard_ty, guard_op, guard_code = cmp_exp tc c guard in + let then_code = cmp_block tc c rt st1 in + let else_code = cmp_block tc c rt st2 in + let lt, le, lm = gensym "then", gensym "else", gensym "merge" in + c, guard_code + >:: T(Cbr (guard_op, lt, le)) + >:: L lt >@ then_code >:: T(Br lm) + >:: L le >@ else_code >:: T(Br lm) + >:: L lm + + (* CAST TASK: Fill in this case of the compiler to implement the 'if?' checked + null downcast statement. + - check whether the value computed by exp is null, if so jump to + the 'null' block, otherwise take the 'notnull' block + + - the identifier id is in scope in the 'nutnull' block and so + needs to be allocated (and added to the context) + + - as in the if-the-else construct, you should jump to the common + merge label after either block + *) + | Ast.Cast (typ, id, exp, notnull, null) -> + failwith "todo: implement Ast.Cast case" + + | Ast.While (guard, body) -> + let guard_ty, guard_op, guard_code = cmp_exp tc c guard in + let lcond, lbody, lpost = gensym "cond", gensym "body", gensym "post" in + let body_code = cmp_block tc c rt body in + c, [] + >:: T (Br lcond) + >:: L lcond >@ guard_code >:: T (Cbr (guard_op, lbody, lpost)) + >:: L lbody >@ body_code >:: T (Br lcond) + >:: L lpost + + | Ast.For (inits, guard, after, body) -> + let guard = match guard with Some e -> e | None -> no_loc (CBool true) in + let after = match after with Some s -> [s] | None -> [] in + let body = body @ after in + let ds = List.map (fun d -> no_loc (Decl d)) inits in + let stream = cmp_block tc c rt (ds @ [no_loc @@ Ast.While (guard, body)]) in + c, stream + + | Ast.Ret None -> + c, [T (Ret(Void, None))] + + | Ast.Ret (Some e) -> + let op, code = cmp_exp_as tc c e rt in + c, code >:: T(Ret (rt, Some op)) + + | Ast.SCall (f, es) -> + let _, op, code = cmp_call tc c f es in + c, code + +(* Compile a series of statements *) +and cmp_block (tc : TypeCtxt.t) (c:Ctxt.t) (rt:Ll.ty) (stmts:Ast.block) : stream = + snd @@ List.fold_left (fun (c, code) s -> + let c, stmt_code = cmp_stmt tc c rt s in + c, code >@ stmt_code + ) (c,[]) stmts + + + +(* Construct the structure context for compilation. We could reuse + the H component from the Typechecker rather than recomputing this + information here, but we do it this way to make the two parts of + the project less interdependent. *) +let get_struct_defns (p:Ast.prog) : TypeCtxt.t = + List.fold_right (fun d ts -> + match d with + | Ast.Gtdecl { elt=(id, fs) } -> + TypeCtxt.add ts id fs + | _ -> ts) p TypeCtxt.empty + + +(* Adds each function identifier to the context at an + appropriately translated type. + + NOTE: The Gid of a function is just its source name +*) +let cmp_function_ctxt (tc : TypeCtxt.t) (c:Ctxt.t) (p:Ast.prog) : Ctxt.t = + List.fold_left (fun c -> function + | Ast.Gfdecl { elt={ frtyp; fname; args } } -> + let ft = TRef (RFun (List.map fst args, frtyp)) in + Ctxt.add c fname (cmp_ty tc ft, Gid fname) + | _ -> c + ) c p + +(* Populate a context with bindings for global variables + mapping OAT identifiers to LLVMlite gids and their types. + + Only a small subset of OAT expressions can be used as global initializers + in well-formed programs. (The constructors starting with C and Id's + for global function values). +*) +let cmp_global_ctxt (tc : TypeCtxt.t) (c:Ctxt.t) (p:Ast.prog) : Ctxt.t = + let gexp_ty c = function + | Id id -> fst (Ctxt.lookup id c) + | CStruct (t, cs) -> Ptr (Namedt t) + | CNull r -> cmp_ty tc (TNullRef r) + | CBool b -> I1 + | CInt i -> I64 + | CStr s -> Ptr (str_arr_ty s) + | CArr (u, cs) -> Ptr (Struct [I64; Array(List.length cs, cmp_ty tc u)]) + | x -> failwith ( "bad global initializer: " ^ (Astlib.string_of_exp (no_loc x))) + in + List.fold_left (fun c -> function + | Ast.Gvdecl { elt={ name; init } } -> + Ctxt.add c name (Ptr (gexp_ty c init.elt), Gid name) + | _ -> c) c p + + +(* Compile a function declaration in global context c. Return the LLVMlite cfg + and a list of global declarations containing the string literals appearing + in the function. + *) +let cmp_fdecl (tc : TypeCtxt.t) (c:Ctxt.t) (f:Ast.fdecl node) : Ll.fdecl * (Ll.gid * Ll.gdecl) list = + let {frtyp; args; body} = f.elt in + let add_arg (s_typ, s_id) (c,code,args) = + let ll_id = gensym s_id in + let ll_ty = cmp_ty tc s_typ in + let alloca_id = gensym s_id in + let c = Ctxt.add c s_id (Ptr ll_ty, Ll.Id alloca_id)in + c, [] + >:: E(alloca_id, Alloca ll_ty) + >:: I("", Store(ll_ty, Id ll_id, Id alloca_id)) + >@ code, + (ll_ty, ll_id)::args + in + let c, args_code, args = List.fold_right add_arg args (c,[],[]) in + let ll_rty = cmp_ret_ty tc frtyp in + let block_code = cmp_block tc c ll_rty body in + let argtys, f_param = List.split args in + let f_ty = (argtys, ll_rty) in + let return_code = + let return_val = + match frtyp with + | RetVoid -> None + | RetVal TBool | RetVal TInt -> Some (Const 0L) + | RetVal (TRef _) -> Some Null + | RetVal (TNullRef _) -> Some Null + in + [T (Ret (ll_rty, return_val))] + in + let f_cfg, globals = cfg_of_stream (args_code >@ block_code >@ return_code) in + {f_ty; f_param; f_cfg}, globals + + + +(* Compile a global initializer, returning the resulting LLVMlite global + declaration, and a list of additional global declarations. +*) +let rec cmp_gexp c (tc : TypeCtxt.t) (e:Ast.exp node) : Ll.gdecl * (Ll.gid * Ll.gdecl) list = + match e.elt with + | CNull r -> (cmp_ty tc (TNullRef r), GNull), [] + | CBool b -> (I1, (if b then GInt 1L else GInt 0L)), [] + | CInt i -> (I64, GInt i), [] + | Id id -> ((fst @@ Ctxt.lookup id c), GGid id), [] + + | CStr s -> + let gid = gensym "str" in + let ll_ty = str_arr_ty s in + (Ptr ll_ty, GGid gid), [gid, (ll_ty, GString s)] + + | CArr (u, cs) -> + let elts, gs = List.fold_right + (fun cst (elts, gs) -> + let gd, gs' = cmp_gexp c tc cst in + gd::elts, gs' @ gs) cs ([], []) + in + let len = List.length cs in + let ll_u = cmp_ty tc u in + let gid = gensym "global_arr" in + let arr_t = Struct [ I64; Array(len, ll_u) ] in + let arr_i = GStruct [ I64, GInt (Int64.of_int len); Array(len, ll_u), GArray elts ] in + (Ptr arr_t, GGid gid), (gid, (arr_t, arr_i))::gs + + (* STRUCT TASK: Complete this code that generates the global initializers for a struct value. *) + | CStruct (id, cs) -> + failwith "todo: Cstruct case of cmp_gexp" + + | _ -> failwith "bad global initializer" + +(* Oat internals function context ------------------------------------------- *) +let internals = + [ "oat_malloc", Ll.Fun ([I64], Ptr I64) + ; "oat_alloc_array", Ll.Fun ([I64], Ptr I64) + ; "oat_assert_not_null", Ll.Fun ([Ptr I8], Void) + ; "oat_assert_array_length", Ll.Fun ([Ptr I64; I64], Void) + ] + +(* Oat builtin function context --------------------------------------------- *) +let builtins = List.map + (fun (fname, ftyp) -> + let args, ret = cmp_fty TypeCtxt.empty ftyp in + (fname, Ll.Fun (args, ret))) + Typechecker.builtins + + +let tctxt_to_tdecls c = + List.map (fun (i, l) -> i, Struct (List.map (fun f -> cmp_ty c f.ftyp) l)) c + +(* Compile a OAT program to LLVMlite *) +let cmp_prog (p:Ast.prog) : Ll.prog = + let tc = get_struct_defns p in + (* add built-in functions to context *) + let init_ctxt = + List.fold_left (fun c (i, t) -> Ctxt.add c i (Ll.Ptr t, Gid i)) + Ctxt.empty builtins + in + let fc = cmp_function_ctxt tc init_ctxt p in + + (* build global variable context *) + let c = cmp_global_ctxt tc fc p in + (* compile functions and global variables *) + let fdecls, gdecls = + List.fold_right (fun d (fs, gs) -> + match d with + | Ast.Gvdecl { elt=gd } -> + let ll_gd, gs' = cmp_gexp c tc gd.init in + (fs, (gd.name, ll_gd)::gs' @ gs) + | Ast.Gfdecl fd -> + let fdecl, gs' = cmp_fdecl tc c fd in + (fd.elt.fname,fdecl)::fs, gs' @ gs + | Ast.Gtdecl _ -> + fs, gs + ) p ([], []) + in + (* gather external declarations *) + let edecls = internals @ builtins in + { tdecls = tctxt_to_tdecls tc; gdecls; fdecls; edecls } diff --git a/hw5/gradedtests.ml b/hw5/gradedtests.ml new file mode 100644 index 0000000..d39a649 --- /dev/null +++ b/hw5/gradedtests.ml @@ -0,0 +1,490 @@ +open Assert +open X86 +open Driver +open Ll +open Backend + +(* Do NOT modify this file -- we will overwrite it with our *) +(* own version when we test your project. *) + +(* These tests will be used to grade your assignment *) + +let fdecl_of_path path = + Platform.verb @@ Printf.sprintf "* processing file: %s\n" path; + let ll_ast = parse_ll_file path in + match ll_ast.Ll.fdecls with + | [_, fdecl] -> fdecl + | _ -> failwith "test expected one fdecl" + + +let exec_e2e_ast ll_ast args extra_files = + let output_path = !Platform.output_path in + let dot_s_file = Platform.gen_name output_path "test" ".s" in + let exec_file = Platform.gen_name output_path "exec" "" in + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + let _ = Driver.write_file dot_s_file asm_str in + let _ = Platform.link (dot_s_file::extra_files) exec_file in + let result = Driver.run_executable args exec_file in + let _ = Platform.sh (Printf.sprintf "rm -f %s %s" dot_s_file exec_file) Platform.ignore_error in + let _ = Platform.verb @@ Printf.sprintf "** Executable exited with: %d\n" result in + Int64.of_int result + + +let exec_e2e_file path args = + let ast = Driver.parse_ll_file path in + exec_e2e_ast ast args [] + +let io_test path args = + let ll_ast = Driver.parse_ll_file path in + let output_path = !Platform.output_path in + let dot_s_file = Platform.gen_name output_path "test" ".s" in + let exec_file = Platform.gen_name output_path "exec" "" in + let tmp_file = Platform.gen_name output_path "tmp" ".txt" in + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + let _ = Driver.write_file dot_s_file asm_str in + let _ = Platform.link (dot_s_file::["cinterop.c"]) exec_file in + let args = String.concat " " args in + let result = Driver.run_program args exec_file tmp_file in + let _ = Platform.sh (Printf.sprintf "rm -f %s %s %s" dot_s_file exec_file tmp_file) Platform.ignore_error in + let _ = Platform.verb @@ Printf.sprintf "** Executable output:\n%s\n" result in + result + +let c_link_test c_files path args = + let ll_ast = Driver.parse_ll_file path in + let output_path = !Platform.output_path in + let dot_s_file = Platform.gen_name output_path "test" ".s" in + let exec_file = Platform.gen_name output_path "exec" "" in + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + let _ = Driver.write_file dot_s_file asm_str in + let _ = Platform.link (dot_s_file::c_files) exec_file in + let args = String.concat " " args in + let result = Driver.run_executable args exec_file in + let _ = Platform.sh (Printf.sprintf "rm -f %s %s" dot_s_file exec_file) Platform.ignore_error in + Int64.of_int result + +let oat_file_test path args = + let () = Platform.verb @@ Printf.sprintf "** Processing: %s\n" path in + + let output_path = !Platform.output_path in + let dot_ll_file = Platform.gen_name output_path "test" ".ll" in + let exec_file = Platform.gen_name output_path "exec" "" in + let tmp_file = Platform.gen_name output_path "tmp" ".txt" in + + let oat_ast = parse_oat_file path in + Typechecker.typecheck_program oat_ast; + let ll_ast = Frontend.cmp_prog oat_ast in + let ll_str = Driver.string_of_ll_ast path ll_ast in + let () = write_file dot_ll_file ll_str in + let () = Platform.link (dot_ll_file::["runtime.c"]) exec_file in + + let result = Driver.run_program args exec_file tmp_file in + let () = Platform.sh (Printf.sprintf "rm -f %s %s %s" dot_ll_file exec_file tmp_file) Platform.ignore_error in + let () = Platform.verb @@ Printf.sprintf "** Executable output:\n%s\n" result in + result + +let oat_tc_ok_file_test path = + let _ = Platform.verb @@ Printf.sprintf "** OAT Typechecker OK Processing: %s\n" path in + let oat_ast = parse_oat_file path in + let _= Typechecker.typecheck_program oat_ast in + () + +let oat_tc_err_file_test path err = + let _ = Platform.verb @@ Printf.sprintf "** OAT Typechecker Error Processing: %s\n" path in + let oat_ast = parse_oat_file path in + try + let _ = Typechecker.typecheck_program oat_ast in + failwith @@ Printf.sprintf "Expected type error: %s" err + with + | Typechecker.TypeError s -> + if s = err then () else + failwith @@ Printf.sprintf "Expected type error: %s but got %s" err s + +let executed tests = + List.map (fun (fn, ans) -> + fn, assert_eqf (fun () -> exec_e2e_file fn "") ans) + tests + +let executed_oat_file tests = + List.map (fun (path, args, ans) -> + (path ^ " args: " ^ args), assert_eqf (fun () -> oat_file_test path args) ans) + tests + +let executed_tc_ok_file tests = + List.map (fun path -> + ("typechecking: " ^ path, fun () -> oat_tc_ok_file_test path)) tests + +let executed_tc_err_file tests = + List.map (fun (path, err) -> + ("typechecking: " ^ path, fun () -> oat_tc_err_file_test path err)) tests + + + +let executed_io tests = + List.map (fun (fn, args, ans) -> + (fn ^ ":" ^ (String.concat " " args)), assert_eqf (fun () -> io_test fn args) ans) + tests + +let executed_c_link tests = + List.map (fun (c_file, fn, args, ans) -> + (fn ^ ":" ^ (String.concat " " args)), assert_eqf (fun () -> c_link_test c_file fn args) ans) + tests + +let typecheck path () = + let () = Platform.verb @@ Printf.sprintf "** Processing: %s\n" path in + let oat_ast = parse_oat_file path in + Typechecker.typecheck_program oat_ast + +let typecheck_error (a : assertion) () = + try a (); failwith "Should have a type error" with Typechecker.TypeError s -> () + +let typecheck_correct (a : assertion) () = + try a () with Typechecker.TypeError s -> failwith "Should not have had a type error" + + +let typecheck_file_error tests = + List.map (fun p -> p, typecheck_error (typecheck p)) tests + +let typecheck_file_correct tests = + List.map (fun p -> p, typecheck_correct (typecheck p)) tests + +let unit_tests = [ + "subtype_stringQ_stringQ", + (fun () -> + if Typechecker.subtype Tctxt.empty (TNullRef RString) (TNullRef RString) then () + else failwith "should not fail") +; ("no_subtype_stringQ_stringQ", + (fun () -> + if Typechecker.subtype Tctxt.empty (TNullRef RString) (TRef RString) then + failwith "should not succeed" else ()) + ) +] + + +let hw4_easiest_tests = [ + ("oatprograms/easyrun1.oat", "", "17"); + ("oatprograms/easyrun2.oat", "", "35"); + ("oatprograms/easyrun3.oat", "", "73"); + ("oatprograms/easyrun4.oat", "", "6"); + ("oatprograms/easyrun5.oat", "", "212"); + ("oatprograms/easyrun6.oat", "", "9"); + ("oatprograms/easyrun7.oat", "", "23"); + ("oatprograms/easyrun8.oat", "", "96"); + ("oatprograms/easyrun9.oat", "", "236"); +] + +let hw4_globals_tests = [ + ("oatprograms/globals1.oat", "", "42"); + ("oatprograms/globals2.oat", "", "17"); + ("oatprograms/globals3.oat", "", "17"); + ("oatprograms/globals4.oat", "", "5"); + ("oatprograms/globals5.oat", "", "17"); + ("oatprograms/globals6.oat", "", "15"); + +] + +let hw4_path_tests = [ + ("oatprograms/path1.oat", "", "17"); + ("oatprograms/path2.oat", "", "35"); + ("oatprograms/path3.oat", "", "3"); + ("oatprograms/arrayargs1.oat", "", "17"); + ("oatprograms/arrayargs2.oat", "", "17"); + ("oatprograms/arrayargs3.oat", "", "34"); +] + +let hw4_easy_tests = [ + ("oatprograms/run26.oat", "", "0"); + ("oatprograms/run27.oat", "", "99"); + ("oatprograms/run28.oat", "", "18"); + ("oatprograms/run29.oat", "", "1"); + ("oatprograms/run30.oat", "", "9"); + ("oatprograms/run31.oat", "", "9"); + ("oatprograms/run13.oat", "", "1"); + ("oatprograms/run32.oat", "", "33"); + ("oatprograms/run21.oat", "", "99"); + ("oatprograms/run33.oat", "", "1"); + ("oatprograms/run34.oat", "", "66"); + ("oatprograms/run38.oat", "", "31"); + ("oatprograms/run39.oat", "a", "2"); + ("oatprograms/run40.oat", "", "8"); + ("oatprograms/run41.oat", "", "3"); + ("oatprograms/run42.oat", "", "2"); + ("oatprograms/run49.oat", "", "abc0"); + ("oatprograms/run50.oat", "", "abcde0"); + ("oatprograms/run60.oat", "", "85"); + ("oatprograms/run61.oat", "", "3410"); +] + +let hw4_medium_tests = [ + ("oatprograms/fact.oat", "", "1200"); + ("oatprograms/run1.oat", "", "153"); + ("oatprograms/run2.oat", "", "6"); + ("oatprograms/run8.oat", "", "2"); + ("oatprograms/run9.oat", "", "4"); + ("oatprograms/run10.oat", "", "5"); + ("oatprograms/run11.oat", "", "7"); + ("oatprograms/run14.oat", "", "16"); + ("oatprograms/run15.oat", "", "19"); + ("oatprograms/run16.oat", "", "13"); + ("oatprograms/run22.oat", "", "abc0"); + ("oatprograms/run23.oat", "", "1230"); + ("oatprograms/run25.oat", "", "nnn0"); + ("oatprograms/run46.oat", "", "420"); + ("oatprograms/run47.oat", "", "3"); + ("oatprograms/run48.oat", "", "11"); + ("oatprograms/lib4.oat", "", "53220"); + ("oatprograms/lib5.oat", "", "20"); + ("oatprograms/lib6.oat", "", "56553"); + ("oatprograms/lib7.oat", "", "53"); + ("oatprograms/lib8.oat", "", "Hello world!0"); + ("oatprograms/lib9.oat", "a b c d", "abcd5"); + ("oatprograms/lib11.oat", "", "45"); + ("oatprograms/lib14.oat", "", "~}|{zyxwvu0"); + ("oatprograms/lib15.oat", "123456789", "456780"); +] + +let hw4_hard_tests = [ +("oatprograms/fac.oat", "", "120"); +("oatprograms/qsort.oat", "", "kpyf{shomfhkmopsy{255"); +("oatprograms/bsort.oat", "", "y}xotnuw notuwxy}255"); +("oatprograms/msort.oat", "", "~}|{zyxwvu uvwxyz{|}~ 0"); +("oatprograms/msort2.oat", "", "~}|{zyxwvu uvwxyz{|}~ 0"); +("oatprograms/selectionsort.oat", "", "01253065992000"); +("oatprograms/matrixmult.oat", "", "19 16 13 23 \t5 6 7 6 \t19 16 13 23 \t5 6 7 6 \t0"); +] + +let hw4_old_student_tests = [ + ("oatprograms/binary_search.oat", "", "Correct!0") + ; ("oatprograms/xor_shift.oat", "", "838867572\n22817190600") + ; ("oatprograms/sieve.oat", "", "25") + ; ("oatprograms/count_sort.oat", "", "AFHZAAEYC\nAAACEFHYZ0") + ; ("oatprograms/determinant_size2.oat", "", "94") + ; ("oatprograms/fibo.oat", "", "0") + ; ("oatprograms/bubble_sort.oat", "", "1") + ; ("oatprograms/heap.oat", "", "1") + ; ("oatprograms/binary_gcd.oat", "", "3") + ; ("oatprograms/lfsr.oat", "", "TFTF FFTT0") + ; ("oatprograms/gnomesort.oat", "", "01253065992000") + ; ("oatprograms/josh_joyce_test.oat", "", "0") + ; ("oatprograms/conquest.oat", "", "My name is Jeff...\nCharizard is the BEST Pokemon ever!!!11") + ; ("oatprograms/gcd.oat", "", "16") + ; ("oatprograms/lcs.oat", "", "OAT0") + ; ("oatprograms/insertion_sort.oat", "", "42") + ; ("oatprograms/maxsubsequence.oat", "", "107") +] + +let hw4_type_error_tests = [ + "oatprograms/run3.oat" +; "oatprograms/run5.oat" +; "oatprograms/run35.oat" +; "oatprograms/run43.oat" +; "oatprograms/run44.oat" +; "oatprograms/run45.oat" +] + + + +let struct_tests = [ +("hw5programs/compile_assign_struct.oat", "", "16"); +("hw5programs/compile_basic_struct.oat", "", "7"); +("hw5programs/compile_global_struct.oat", "", "254"); +("hw5programs/compile_nested_struct.oat", "", "10"); +("hw5programs/compile_return_struct.oat", "", "0"); +("hw5programs/compile_struct_array.oat", "", "15"); +("hw5programs/compile_struct_fptr.oat", "", "7"); +("hw5programs/compile_various_fields.oat", "", "hello253"); +] + +let fptr_tests = [ + ("hw5programs/compile_array_fptr.oat", "", "2"); + ("hw5programs/compile_func_argument.oat", "", "4"); + ("hw5programs/compile_global_fptr.oat", "", "7"); + ("hw5programs/compile_global_fptr_unordered.oat", "", "2"); + ("hw5programs/compile_scall_fptr.oat", "", "4"); + ("hw5programs/compile_var_fptr.oat", "", "1"); + ("hw5programs/compile_local_fptr.oat", "", "5"); + ("hw5programs/compile_function_shadow.oat", "", "12"); + ("hw5programs/compile_global_struct_fptr.oat", "", "20"); + ("hw5programs/compile_builtin_argument.oat", "", "abab0"); +] + +let typecheck_subtyping_tests = + [ "hw5programs/tc_subtyping1.oat" + ; "hw5programs/tc_subtyping2.oat" + ; "hw5programs/tc_subtyping3.oat" + ; "hw5programs/tc_subtyping4.oat" + ; "hw5programs/tc_subtyping5.oat" + ; "hw5programs/tc_subtyping6.oat" + ; "hw5programs/tc_subtyping7.oat" + ; "hw5programs/tc_subtyping8.oat" + ; "hw5programs/tc_subtyping9.oat" + ] + +let typecheck_subtyping_error_tests = + [ "hw5programs/tc_subtyping_err1.oat" + ; "hw5programs/tc_subtyping_err2.oat" + ; "hw5programs/tc_subtyping_err3.oat" + ; "hw5programs/tc_subtyping_err4.oat" + ; "hw5programs/tc_subtyping_err5.oat" + ; "hw5programs/tc_subtyping_err6.oat" + ; "hw5programs/tc_subtyping_err7.oat" + ; "hw5programs/tc_subtyping_err8.oat" + ] + + +let typecheck_statement_error_tests = + [ "hw5programs/tc_error_early_return.oat"; + "hw5programs/tc_error_early_return_void.oat"; + "hw5programs/tc_error_return_wrong.oat"; + "hw5programs/tc_error_while_nonbool.oat"; + "hw5programs/tc_error_while.oat"; + "hw5programs/tc_error_if_nonbool.oat"; + "hw5programs/tc_error_if.oat"; + "hw5programs/tc_error_for.oat"; + "hw5programs/tc_error_void.oat"; + "hw5programs/tc_error_assign_void.oat"; + "hw5programs/tc_error_scall_nonvoid.oat"; + ] + +let typecheck_correct_statement_tests = + [ "hw5programs/tc_correct_while.oat"; + "hw5programs/tc_correct_for.oat"; + "hw5programs/tc_correct_if.oat"; + "hw5programs/tc_correct_void.oat" + ] + +let typecheck_error_expression_tests = + [ "hw5programs/tc_error_binop1.oat"; + "hw5programs/tc_error_binop2.oat"; + "hw5programs/tc_error_binop3.oat"; + "hw5programs/tc_error_call1.oat"; + "hw5programs/tc_error_call2.oat"; + "hw5programs/tc_error_unop1.oat"; + "hw5programs/tc_error_array1.oat"; + "hw5programs/tc_error_array2.oat"; + "hw5programs/tc_error_null.oat"; + ] + +let typecheck_error_struct_tests = + [ "hw5programs/tc_error_struct_proj.oat"; + "hw5programs/tc_error_struct1.oat"; + "hw5programs/tc_error_struct2.oat"; + "hw5programs/tc_error_struct3.oat"; + "hw5programs/tc_error_struct4.oat"; + "hw5programs/tc_error_struct_dup.oat"; + "hw5programs/tc_error_struct.oat"; + "hw5programs/tc_error_dupstruct.oat"; + "hw5programs/tc_error_struct_unbound.oat"; + ] + +let typecheck_error_global_tests = + [ "hw5programs/tc_error_global_dup.oat"; + "hw5programs/tc_error_global.oat"; + "hw5programs/tc_error_func_redeclaration.oat"; + "hw5programs/tc_error_func_assign.oat"; + "hw5programs/tc_error_overwrite.oat"; + "hw5programs/tc_error_global_fptr_scope.oat"; + "hw5programs/tc_error_function_no_shadow.oat"; + "hw5programs/tc_correct_null.oat"; + ] + +let typecheck_correct_other_tests = + [ "hw5programs/tc_correct_array.oat"; + "hw5programs/tc_correct_call.oat"; + "hw5programs/tc_correct_fptr.oat"; + "hw5programs/tc_correct_global.oat"; + "hw5programs/tc_correct_struct.oat"; + "hw5programs/tc_correct_struct_fptr.oat"; + "hw5programs/tc_correct_void.oat"; + "hw5programs/tc_correct_local_redeclaration.oat"; + "hw5programs/tc_correct_fptr_array.oat"; + ] + +let typecheck_error_null_not_null_tests = + hw4_type_error_tests + + +let fptr_tests = [ + ("hw5programs/compile_array_fptr.oat", "", "2"); + ("hw5programs/compile_func_argument.oat", "", "4"); + ("hw5programs/compile_global_fptr.oat", "", "7"); + ("hw5programs/compile_global_fptr_unordered.oat", "", "2"); + ("hw5programs/compile_scall_fptr.oat", "", "4"); + ("hw5programs/compile_var_fptr.oat", "", "1"); + ("hw5programs/compile_local_fptr.oat", "", "5"); + ("hw5programs/compile_function_shadow.oat", "", "12"); + ("hw5programs/compile_global_struct_fptr.oat", "", "20"); + ("hw5programs/compile_builtin_argument.oat", "", "abab0"); +] + + +let tc_ok_tests = [ + "hw5programs/tc_struct_ok.oat" +; "hw5programs/tc_func_ret_ok.oat" +; "hw5programs/tc_func_arg_ok.oat" +; "hw5programs/tc_ifq1.oat" +; "oatprograms/tc_ok1.oat" +; "oatprograms/tc_ok2.oat" +; "oatprograms/tc_ok4.oat" +; "oatprograms/tc_ok5.oat" +; "oatprograms/tc_ok6.oat" +; "oatprograms/tc_ok7.oat" +; "oatprograms/tc_ok8.oat" +; "hw5programs/tc_arrow.oat" +; "hw5programs/tc_arrow_null.oat" +; "hw5programs/tc_arrow_null_rec.oat" +] + +let tc_err_tests = [ + "hw5programs/tc_null_array_err.oat" +; "hw5programs/tc_struct_err.oat" +; "hw5programs/tc_func_ret_err.oat" +; "hw5programs/tc_func_arg_err.oat" +; "hw5programs/tc_array_err.oat" +; "hw5programs/tc_struct_field_err.oat" +; "hw5programs/tc_recursive_struct_err.oat" +; "hw5programs/tc_ifq_err1.oat" +] + + +let typecheck_tests : suite = [ + GradedTest("subtype unit tests", 3, unit_tests); + GradedTest("tc subtyping tests", 4, typecheck_file_correct typecheck_subtyping_tests); + GradedTest("tc subtyping error tests", 4, typecheck_file_error typecheck_subtyping_error_tests); + GradedTest("tc statement error tests", 5, typecheck_file_error typecheck_statement_error_tests); + GradedTest("tc statement correct tests", 5, typecheck_file_correct typecheck_correct_statement_tests); + GradedTest("tc other correct tests", 5, typecheck_file_correct typecheck_correct_other_tests); + GradedTest("tc null/not null error tests", 5, typecheck_file_error typecheck_error_null_not_null_tests); + GradedTest("tc expression error tests", 5, typecheck_file_error typecheck_error_expression_tests); + GradedTest("tc struct/global error tests", 5, typecheck_file_error (typecheck_error_struct_tests @ typecheck_error_global_tests)); + GradedTest("extra tc err tests", 5, typecheck_file_error tc_err_tests); + +] + +let student_tests = [] + +let hw5_tests : suite = [ + GradedTest("tc ok tests", 10, executed_tc_ok_file tc_ok_tests) +; GradedTest("struct tests", 10, executed_oat_file struct_tests) +; GradedTest("fptr tests", 4, executed_oat_file fptr_tests) +; GradedTest("hidden tests", 20, executed_oat_file student_tests) +] + + +let hw4_tests = + hw4_easiest_tests + @ hw4_globals_tests + @ hw4_path_tests + @ hw4_easy_tests + @ hw4_medium_tests + @ hw4_hard_tests + @ hw4_old_student_tests + +let functionality_tests : suite = [GradedTest("functionality tests from HW04", 10, executed_oat_file hw4_tests)] + +let graded_tests : suite = + typecheck_tests @ + hw5_tests @ + functionality_tests diff --git a/hw5/hw5programs/apoth_composition.oat b/hw5/hw5programs/apoth_composition.oat new file mode 100644 index 0000000..064bba4 --- /dev/null +++ b/hw5/hw5programs/apoth_composition.oat @@ -0,0 +1,60 @@ +struct Dog { + string name; + int food +} + +struct TrainableDog { + Dog dog; + int intelligence; + (TrainableDog, int) -> int train +} + +struct Person { + string name; + bool[][] areaMap; + ((Person, int, int) -> void) visit +} + +struct DogOwner { + Person person; + int numDogs; + Dog[] dogs; + (DogOwner, int) -> void feedDogs +} + +int train(TrainableDog tdog, int food) { + tdog.intelligence = tdog.intelligence + 1; + tdog.dog.food = tdog.dog.food + food; + return tdog.dog.food; +} + +void visit(Person p, int x, int y) { p.areaMap[x][y] = true; return; } + +void feedDogs(DogOwner do, int numDogs) { + for (var i = 0; i < numDogs; i = i + 1;) { + do.dogs[i].food = do.dogs[i].food + 1; + } + return; +} + +int program(int argc, string[] argv) { + var dog = new Dog { name = "Holmes"; food = 10 }; + var tdog = new TrainableDog { dog = dog; intelligence = 0; train = train }; + var areaMap = new bool[][] { new bool[] {false, false}, new bool[] {false, true} }; + var p = new Person { name = "Guy"; areaMap = areaMap; visit = visit }; + var do = new DogOwner { feedDogs = feedDogs; numDogs = 1; person = p; dogs = new Dog[] { dog } }; + + var newFood = tdog.train(tdog, 5); + p.visit(p, 0, 0); + do.feedDogs(do, 1); + + var numVisited = 0; + for (var i = 0; i < 2; i = i + 1;) { + for (var j = 0; j < 2; j = j + 1;) { + if (p.areaMap[i][j]) { + numVisited = numVisited + 1; + } + } + } + return dog.food + numVisited; +} diff --git a/hw5/hw5programs/burowski_bfs.oat b/hw5/hw5programs/burowski_bfs.oat new file mode 100644 index 0000000..157ca30 --- /dev/null +++ b/hw5/hw5programs/burowski_bfs.oat @@ -0,0 +1,174 @@ +global debug = false; + +struct Node { + string val; + bool visited; + Queue neighbors; + bool hasNext +} + +struct QNode { + Node node; + QNode next; + bool qhasNext +} + +struct Queue { + QNode head; + QNode tail; + int size +} + +Node getIthInQueue(int i, Queue q) { + var tmp = q.head; + if (i + 1 == q.size) { + return q.tail.node; + } + while (tmp.qhasNext) { + if (i == 0) { + return tmp.node; + } + tmp = tmp.next; + i = i - 1; + } + return newNode("ERROR"); +} + +Node newNode(string v) { + return new Node {val=v; hasNext=false; visited=false; neighbors=newEmptyQueue()}; +} + +QNode newQNode(Node n) { + return new QNode {node=n; next=QNode null; qhasNext=false}; +} + +void printNode(Node n) { + print_string(n.val); + return; +} + +Queue newEmptyQueue() { + return new Queue {head=QNode null; tail=QNode null; size=0}; +} + + +bool isEmpty(Queue q) { + return q.size == 0; +} + +void printNeighbors(Node n) { + printNeighborsDebug(n, debug); + return; +} + +void printNeighborsDebug(Node n, bool d) { + if (!d) { + return; + } + var s = n.neighbors.size; + for (var i = 0; i < s; i = i + 1;) { + var x = getIthInQueue(i, n.neighbors); + printNode(x); + } + print_string("\n"); + return; +} + +void enqueue(Queue q, Node n) { + var node = newQNode(n); + if (q.size == 0) { + q.head = node; + } else { + q.tail.qhasNext = true; + q.tail.next = node; + } + q.size = q.size + 1; + node.qhasNext = false; + q.tail = node; + return; +} + +Node dequeue(Queue q) { + if (isEmpty(q)) { + return newNode(""); + } + var tmp = q.head; + q.head = tmp.next; + q.size = q.size - 1; + return tmp.node; +} + +void addNeighbor(Node tgt, Node toAdd) { + enqueue(tgt.neighbors, toAdd); + return; +} + +void bfs(Node start) { + var q = newEmptyQueue(); + start.visited = true; + enqueue(q, start); + while (!isEmpty(q)) { + var curr = dequeue(q); + printNode(curr); + var s = curr.neighbors.size; + for (var i = 0; i < s; i = i + 1;) { + var n = getIthInQueue(i, curr.neighbors); + if (!(n.visited)) { + n.visited = true; + enqueue(q, n); + } + } + } + return; +} + + +void print_debug(string msg) { + if (!debug) { + return; + } + print_string(msg); + return; +} + +int program (int argc, string[] argv) { + + var there = newNode("there "); + var should = newNode("should "); + var be = newNode("be "); + var better = newNode("better "); + var food = newNode("food "); + var options = newNode("options "); + var on = newNode("on "); + var campus = newNode("campus"); + + addNeighbor(there, should); + addNeighbor(there, be); + addNeighbor(there, better); + + addNeighbor(should, there); + addNeighbor(should, food); + + addNeighbor(be, there); + addNeighbor(be, better); + + + addNeighbor(better, there); + addNeighbor(better, be); + addNeighbor(better, options); + + addNeighbor(food, should); + addNeighbor(food, options); + + addNeighbor(options, food); + addNeighbor(options, better); + addNeighbor(options, on); + addNeighbor(options, campus); + + addNeighbor(on, options); + + addNeighbor(campus, options); + + bfs(there); + return 0; +} diff --git a/hw5/hw5programs/chmartin_heapsort.oat b/hw5/hw5programs/chmartin_heapsort.oat new file mode 100644 index 0000000..d1770b8 --- /dev/null +++ b/hw5/hw5programs/chmartin_heapsort.oat @@ -0,0 +1,77 @@ +struct Heap { + int[] values; + int arr_length; + int size; + (Heap, int) -> void insert; + (Heap) -> int extract_min; + (Heap) -> int peek +} + +void swim (Heap heap, int index) { + while (index > 1 & (heap.values[index >> 1] > heap.values[index])) { + var parent = heap.values[index >> 1]; + heap.values[index >> 1] = heap.values[index]; + heap.values[index] = parent; + index = index >> 1; + } + return; +} + +void sink (Heap heap, int index) { + while (2 * index <= heap.size) { + var j = 2 * index; + if (j < heap.size & (heap.values[j] > heap.values[j + 1])) { + j = j + 1; + } + if (heap.values[index] <= heap.values[j]) { + index = heap.size; + } else { + var parent = heap.values[index]; + heap.values[index] = heap.values[j]; + heap.values[j] = parent; + index = j; + } + } + return; +} + +void insert (Heap heap, int n) { + heap.size = heap.size + 1; + heap.values[heap.size] = n; + swim(heap, heap.size); + return; +} + +int peek (Heap heap) { + return heap.values[1]; +} + +int extract_min (Heap heap) { + var min = heap.values[1]; + heap.values[1] = heap.values[heap.size]; + heap.values[heap.size] = min; + heap.size = heap.size - 1; + sink(heap, 1); + return min; +} + +int[] heapsort (int[] arr, int arr_len) { + var heap = new Heap {values = new int[arr_len + 1]; arr_length = arr_len + 1; size = 0; insert = insert; extract_min = extract_min; peek = peek}; + for (var i = 0; i < arr_len; i = i + 1;) { + heap.insert(heap, arr[i]); + } + for (var i = 0; i < arr_len; i = i + 1;) { + arr[i] = heap.extract_min(heap); + } + return arr; +} + +int program (int argc, string[] argv) { + var arr1 = new int[]{11, -5, 0, 2, 7, 7, 3, -11}; + var sorted_arr = heapsort(arr1, 8); + for (var i = 0; i < 8; i = i + 1;) { + print_int(sorted_arr[i]); + print_string(", "); + } + return 0; +} diff --git a/hw5/hw5programs/compile_array_fptr.oat b/hw5/hw5programs/compile_array_fptr.oat new file mode 100644 index 0000000..3fae796 --- /dev/null +++ b/hw5/hw5programs/compile_array_fptr.oat @@ -0,0 +1,7 @@ +int add(int x, int y) { return x + y; } +int sub(int x, int y) { return x - y; } + +int program(int argc, string[] argv) { + var ops = new ((int, int) -> int) [] { add, sub }; + return ops[0](1, 1); +} diff --git a/hw5/hw5programs/compile_assign_struct.oat b/hw5/hw5programs/compile_assign_struct.oat new file mode 100644 index 0000000..f9e705d --- /dev/null +++ b/hw5/hw5programs/compile_assign_struct.oat @@ -0,0 +1,12 @@ +struct Point { + int x; + int y +} + +int program(int argc, string[] argv) { + var p = new Point {x = 3; y = 4 }; + p.x = 5; + p.y = p.x + p.y + 3; + p.x = p.y + 4; + return p.x; +} diff --git a/hw5/hw5programs/compile_basic_struct.oat b/hw5/hw5programs/compile_basic_struct.oat new file mode 100644 index 0000000..403e60f --- /dev/null +++ b/hw5/hw5programs/compile_basic_struct.oat @@ -0,0 +1,10 @@ +struct Color { + int red; + int green; + int blue +} + +int program (int argc, string[] argv) { + var garr = new Color { red = 3; green = 4; blue = 5 }; + return garr.red + garr.green; +} diff --git a/hw5/hw5programs/compile_builtin_argument.oat b/hw5/hw5programs/compile_builtin_argument.oat new file mode 100644 index 0000000..07440b8 --- /dev/null +++ b/hw5/hw5programs/compile_builtin_argument.oat @@ -0,0 +1,10 @@ +void run2((string) -> void f, string arg) { + f(arg); + f(arg); + return; +} + +int program(int argc, string[] argv) { + run2(print_string, "ab"); + return 0; +} diff --git a/hw5/hw5programs/compile_func_argument.oat b/hw5/hw5programs/compile_func_argument.oat new file mode 100644 index 0000000..ab8e821 --- /dev/null +++ b/hw5/hw5programs/compile_func_argument.oat @@ -0,0 +1,9 @@ +int call((int) -> int f, int arg) { + return f(arg); +} + +int inc(int x) { return x + 1; } + +int program(int argc, string[] argv) { + return call(inc, 3); +} diff --git a/hw5/hw5programs/compile_function_shadow.oat b/hw5/hw5programs/compile_function_shadow.oat new file mode 100644 index 0000000..1fc85e2 --- /dev/null +++ b/hw5/hw5programs/compile_function_shadow.oat @@ -0,0 +1,12 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int mul(int arg1, int arg2) { + return arg1 * arg2; +} + +int program(int argc, string[] argv) { + var add = mul; + return add(3, 4); +} diff --git a/hw5/hw5programs/compile_global_array.oat b/hw5/hw5programs/compile_global_array.oat new file mode 100644 index 0000000..21f4c7a --- /dev/null +++ b/hw5/hw5programs/compile_global_array.oat @@ -0,0 +1,15 @@ +struct Point { + int x; + int y; + int z +} + +global x = Point[] {Point {x = 3; y = 4; z = 5}, Point {x = 1; y = 2; z = 3}}; + +int program(int argc, string[] argv) { + var i = 0; + for (var j = 0; j < 2; j = j + 1;) { + i = i + x[j].y; + } + return i; +} diff --git a/hw5/hw5programs/compile_global_fptr.oat b/hw5/hw5programs/compile_global_fptr.oat new file mode 100644 index 0000000..d76cc3f --- /dev/null +++ b/hw5/hw5programs/compile_global_fptr.oat @@ -0,0 +1,9 @@ +int add(int x, int y) { + return x + y; +} + +global x = add; + +int program(int argc, string[] argv) { + return x(3, 4); +} diff --git a/hw5/hw5programs/compile_global_fptr_unordered.oat b/hw5/hw5programs/compile_global_fptr_unordered.oat new file mode 100644 index 0000000..77be0ce --- /dev/null +++ b/hw5/hw5programs/compile_global_fptr_unordered.oat @@ -0,0 +1,9 @@ +global plus = add; + +int add(int x, int y) { + return x + y; +} + +int program(int argc, string[] argv) { + return plus(1, 1); +} diff --git a/hw5/hw5programs/compile_global_struct.oat b/hw5/hw5programs/compile_global_struct.oat new file mode 100644 index 0000000..058619f --- /dev/null +++ b/hw5/hw5programs/compile_global_struct.oat @@ -0,0 +1,12 @@ +struct Color { + int red; + int green; + int blue +} + +global white = new Color { red = 255; green = 254; blue = 253 }; + +int program (int argc, string[] argv) { + var garr = new Color { red = 3; green = 5; blue = 7 }; + return white.blue + 1; +} diff --git a/hw5/hw5programs/compile_global_struct_fptr.oat b/hw5/hw5programs/compile_global_struct_fptr.oat new file mode 100644 index 0000000..3024063 --- /dev/null +++ b/hw5/hw5programs/compile_global_struct_fptr.oat @@ -0,0 +1,17 @@ +struct Color { + int red; + int green; + int blue; + (Color) -> Color f +} + +Color rot(Color c1) { + var c2 = new Color{ red = c1.green; green = c1.blue; blue = c1.red; f = c1.f }; + return c2; +} + +global c = new Color { red = 10; green = 20; blue = 30 ; f = rot}; + +int program (int argc, string[] argv) { + return c.f(c).red; +} diff --git a/hw5/hw5programs/compile_local_fptr.oat b/hw5/hw5programs/compile_local_fptr.oat new file mode 100644 index 0000000..c331478 --- /dev/null +++ b/hw5/hw5programs/compile_local_fptr.oat @@ -0,0 +1,9 @@ +int add(int x, int y) { + return x + y; +} + +int program(int argc, string[] argv) { + var plus = add; + var loc_add = plus; + return loc_add(2, 3); +} diff --git a/hw5/hw5programs/compile_nested_struct.oat b/hw5/hw5programs/compile_nested_struct.oat new file mode 100644 index 0000000..6e84a67 --- /dev/null +++ b/hw5/hw5programs/compile_nested_struct.oat @@ -0,0 +1,25 @@ +struct RGB { + int red; + int green; + int blue +} + +struct Point { + RGB x; + RGB y; + RGB z +} + +global red = new RGB {red = 255; blue = 0; green = 0 }; +global green = new RGB {red = 0; blue = 0; green = 255 }; +global blue = new RGB {blue = 255; red = 0; green = 0 }; +global points = new Point[] {new Point {x=new RGB {red=255; blue=0; green=0}; + y=new RGB {green=255; blue=0; red=0}; + z=new RGB {blue=255; green=0; red=0}}}; + +int program(int argc, string[] argv) { + points[0].x.red = 3; + points[0].x.green = 2; + points[0].x.blue = 4; + return points[0].x.red * points[0].x.green + points[0].x.blue; +} diff --git a/hw5/hw5programs/compile_object_like.oat b/hw5/hw5programs/compile_object_like.oat new file mode 100644 index 0000000..1877def --- /dev/null +++ b/hw5/hw5programs/compile_object_like.oat @@ -0,0 +1,15 @@ +struct Point { + int x; + int y; + ((Point) -> int) f +} + +int sum(Point p) { + return p.x + p.y; +} + +global p = Point {x=3; y=4; f=sum}; + +int program (int argc, string[] argv) { + return p.f(p); +} diff --git a/hw5/hw5programs/compile_return_struct.oat b/hw5/hw5programs/compile_return_struct.oat new file mode 100644 index 0000000..0931c23 --- /dev/null +++ b/hw5/hw5programs/compile_return_struct.oat @@ -0,0 +1,17 @@ +struct Pair { + bool x; + bool y +} + +Pair create_pair(bool a, bool b) { + return new Pair {x = a; y = b}; +} + +int program(int argc, string[] argv) { + var p = create_pair(true, false); + if (p.x & p.y) { + return 1; + } else { + return 0; + } +} diff --git a/hw5/hw5programs/compile_scall_fptr.oat b/hw5/hw5programs/compile_scall_fptr.oat new file mode 100644 index 0000000..20162a0 --- /dev/null +++ b/hw5/hw5programs/compile_scall_fptr.oat @@ -0,0 +1,10 @@ +void inc_first(int[] x) { + x[0] = x[0] + 1; + return; +} + +int program(int argc, string[] argv) { + var x = new int[] {3, 4, 5}; + inc_first(x); + return x[0]; +} diff --git a/hw5/hw5programs/compile_struct_array.oat b/hw5/hw5programs/compile_struct_array.oat new file mode 100644 index 0000000..4c63bab --- /dev/null +++ b/hw5/hw5programs/compile_struct_array.oat @@ -0,0 +1,13 @@ +struct Test { + int[] xs; + int y; + int[] zs +} + +global arr_x = new int[] {3,4,5}; +global arr_z = new int[] {4,5,6}; + +int program(int argc, string[] argv) { + var t = new Test {xs=arr_x; y=3; zs=arr_z}; + return t.xs[0] * t.zs[1]; +} diff --git a/hw5/hw5programs/compile_struct_fptr.oat b/hw5/hw5programs/compile_struct_fptr.oat new file mode 100644 index 0000000..4319004 --- /dev/null +++ b/hw5/hw5programs/compile_struct_fptr.oat @@ -0,0 +1,12 @@ +struct S { + int s; + int t; + (int, int) -> int f +} + +int add(int x, int y) { return x + y; } + +int program(int argc, string[] argv) { + var x = new S { s = 3; t = 4; f = add }; + return x.f(x.s, x.t); +} diff --git a/hw5/hw5programs/compile_struct_lhs.oat b/hw5/hw5programs/compile_struct_lhs.oat new file mode 100644 index 0000000..ee5a7dd --- /dev/null +++ b/hw5/hw5programs/compile_struct_lhs.oat @@ -0,0 +1,11 @@ +struct Color { + int red; + int green; + int blue +} + +int program (int argc, string[] argv) { + var garr = new Color { red = 3; green = 4; blue = 5 }; + garr.red = 17; + return garr.red + garr.green; +} diff --git a/hw5/hw5programs/compile_struct_reordered.oat b/hw5/hw5programs/compile_struct_reordered.oat new file mode 100644 index 0000000..3315194 --- /dev/null +++ b/hw5/hw5programs/compile_struct_reordered.oat @@ -0,0 +1,8 @@ +struct Pair { + int x; + int y +} + +int program(int argc, string[] argv) { + return (new Pair {y = 3; x = 4}).y; +} diff --git a/hw5/hw5programs/compile_var_fptr.oat b/hw5/hw5programs/compile_var_fptr.oat new file mode 100644 index 0000000..d020345 --- /dev/null +++ b/hw5/hw5programs/compile_var_fptr.oat @@ -0,0 +1,6 @@ +int id(int x) { return x; } + +int program(int argc, string[] argv) { + var id_local = id; + return id_local(1); +} diff --git a/hw5/hw5programs/compile_various_fields.oat b/hw5/hw5programs/compile_various_fields.oat new file mode 100644 index 0000000..3e2e8be --- /dev/null +++ b/hw5/hw5programs/compile_various_fields.oat @@ -0,0 +1,20 @@ +struct Test { + int i; + bool b; + string s; + int[] arr; + Test? t; + (int) -> int f +} + +int neg(int x) { return -x; } + +int program(int argc, string[] argv) { + var n = new Test {i=3; b=true; s="hello"; arr=new int[3]{j->0}; t=Test null; f=neg}; + print_string(n.s); + if(n.b) { + return n.f(n.i); + } else { + return n.i; + } +} diff --git a/hw5/hw5programs/davidcao_treefunctions.oat b/hw5/hw5programs/davidcao_treefunctions.oat new file mode 100644 index 0000000..3f19d31 --- /dev/null +++ b/hw5/hw5programs/davidcao_treefunctions.oat @@ -0,0 +1,119 @@ +struct Node { + int val; + bool hasleft; + bool hasright; + Node left; + Node right +} + +void treemap(Node t, (int) -> int f) { + t.val = f(t.val); + if (t.hasleft) { + treemap(t.left, f); + } + if (t.hasright) { + treemap(t.right, f); + } + return; +} + +bool for_all(Node t, (int) -> bool pred) { + var result = pred(t.val); + if(t.hasleft & t.hasright) { + return result & for_all(t.left, pred) & for_all(t.right, pred); + } else if (t.hasleft) { + return result & for_all(t.left, pred); + } else if (t.hasright) { + return result & for_all(t.right, pred); + } + + return result; +} + +bool xor(bool b1, bool b2) { + return (b1 | b2) & !(b1 & b2); +} + +bool tree_eq (Node t1, Node t2) { + if (t1.val != t2.val) { + return false; + } else { + var flag = true; + if (t1.hasleft & t2.hasleft) { + flag = flag & tree_eq(t1.left, t2.left); + } + if (t1.hasright & t2.hasright) { + flag = flag & tree_eq(t1.right, t2.right); + } + if (xor(t1.hasleft, t2.hasleft)) { + return false; + } + if (xor(t1.hasright, t2.hasright)) { + return false; + } + return flag; + } +} + +int double(int i) { + return i*2; +} + +bool pred_lt_6 (int i) { + return i < 6; +} + +int program(int argc, string[] argv) { + var a1 = new Node{val = 1; hasleft = false; hasright = false; left = Node null; right = Node null }; + var a2 = new Node{val = 2; hasleft = true; hasright = false; left = a1; right = Node null }; + var a3 = new Node{val = 3; hasleft = false; hasright = false; left = Node null; right = Node null }; + var a4 = new Node{val = 4; hasleft = true; hasright = true; left = a2; right = a3 }; + var a5 = new Node{val = 5; hasleft = false; hasright = false; left = Node null; right = Node null }; + var root = new Node{val = 0; hasleft = true; hasright = true; left = a5; right = a4 }; + + var b1 = new Node{val = 1; hasleft = false; hasright = false; left = Node null; right = Node null }; + var b6 = new Node{val = 6; hasleft = false; hasright = false; left = Node null; right = Node null }; + var b2 = new Node{val = 2; hasleft = true; hasright = true; left = b1; right = b6 }; + var b3 = new Node{val = 3; hasleft = false; hasright = false; left = Node null; right = Node null }; + var b4 = new Node{val = 4; hasleft = true; hasright = true; left = b2; right = b3 }; + var b5 = new Node{val = 5; hasleft = false; hasright = false; left = Node null; right = Node null }; + var root2 = new Node{val = 0; hasleft = true; hasright = true; left = b5; right = b4 }; + + var c1 = new Node{val = 2; hasleft = false; hasright = false; left = Node null; right = Node null }; + var c2 = new Node{val = 4; hasleft = true; hasright = false; left = c1; right = Node null }; + var c3 = new Node{val = 6; hasleft = false; hasright = false; left = Node null; right = Node null }; + var c4 = new Node{val = 8; hasleft = true; hasright = true; left = c2; right = c3 }; + var c5 = new Node{val = 10; hasleft = false; hasright = false; left = Node null; right = Node null }; + var root3 = new Node{val = 0; hasleft = true; hasright = true; left = c5; right = c4 }; + + if (tree_eq(root,root)) { + print_string("1"); + } + + if (tree_eq(root2,root2)) { + print_string("2"); + } + + if (!tree_eq(root,root2)) { + print_string("3"); + } + + if (!tree_eq(root2,root)) { + print_string("4"); + } + + if (for_all(root, pred_lt_6)) { + print_string("5"); + } + + treemap(root,double); + if (tree_eq(root, root3)) { + print_string("6"); + } + + if (!for_all(root, pred_lt_6)) { + print_string("7"); + } + + return 0; +} diff --git a/hw5/hw5programs/gregor.oat b/hw5/hw5programs/gregor.oat new file mode 100644 index 0000000..b789f8e --- /dev/null +++ b/hw5/hw5programs/gregor.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var id = "" +} + +int id(int x) { return x; } diff --git a/hw5/hw5programs/hand_rgb_to_gray.oat b/hw5/hw5programs/hand_rgb_to_gray.oat new file mode 100644 index 0000000..f86dc11 --- /dev/null +++ b/hw5/hw5programs/hand_rgb_to_gray.oat @@ -0,0 +1,77 @@ +struct RGB { + int red; + int green; + int blue +} + +struct GrayScale { + int lightness; + int average; + int luminosity +} + +int div (int a, int b) { + var count = 0; + var cur_num = a; + while (cur_num - b >= 0) { + cur_num = cur_num - b; + count = count + 1; + } + return count; +} + +int max (int a, int b, int c) { + var m = 0; + if (a > b) { + m = a; + } else { + m = b; + } + + if (c > m) { + m = c; + } + + return m; +} + +int min (int a, int b, int c) { + var m = 300; + if (a < b) { + m = a; + } else { + m = b; + } + + if (c < m) { + m = c; + } + + return m; +} + +GrayScale rgbtogray (RGB rgb) { + var maxNum = max(rgb.red, rgb.green, rgb.blue); + var minNum = min(rgb.red, rgb.green, rgb.blue); + + var maxmin = maxNum + minNum; + var light = div(maxmin, 2); + + var averageSum = rgb.red + rgb.green + rgb.blue; + var ave = div(averageSum, 3); + + var luminositySum = (rgb.red * 21) + (rgb.green * 72) + (rgb.blue * 7); + var lum = luminositySum; + + var gray = new GrayScale { lightness = light; average = ave; luminosity = lum }; + return gray; +} + +global rgb = RGB { red = 200; green = 150; blue = 100 }; + +global gray = GrayScale { lightness = 150; average = 150; luminosity = 150 }; + +int program (int argc, string[] argv) { + var convert = rgbtogray(rgb); + return (convert.average - gray.average) + (convert.lightness - gray.lightness); +} diff --git a/hw5/hw5programs/hta_map_reduce.oat b/hw5/hw5programs/hta_map_reduce.oat new file mode 100644 index 0000000..2b488cd --- /dev/null +++ b/hw5/hw5programs/hta_map_reduce.oat @@ -0,0 +1,98 @@ +/* Simulates nodes which perform a map job */ +int[] map ((int) -> int f, int[] src, int len) { + var tgt = new int[len]; + for (var i = 0; i < len; i = i + 1;) { tgt[i] = f(src[i]); } + return tgt; +} + +struct MapJob { + (int) -> int f; + int[] arr; + int arrlen +} + +int[] mapNode(MapJob j) { return map(j.f, j.arr, j.arrlen); } + +/* Simulates nodes which perform a reduce job */ + +int reduce((int, int) -> int f, int[] arr, int len, int base) { + var acc = base; + for (var i = 0; i < len; i = i + 1;) { acc = f(acc, arr[i]); } + return acc; +} + +struct ReduceJob { + int[] arr; + int arrlen; + (int, int) -> int f; + int base +} + +int reduceNode(ReduceJob j) { return reduce(j.f, j.arr, j.arrlen, j.base); } + +/* Generates an array of data, partitions it into map jobs and assigns + them to virtual map nodes. When all data is mapped, reduces it into + an answer and returns it */ + +int square(int elt) { return elt * elt; } + +int sum(int acc, int elt) { return acc + elt; } + +int sumOfSquares(int[] arr, int arrlen, int numPartitions, int partitionLen) { + /* Partition array into almost equal subarrays */ + var src = new int[][numPartitions]; + for (var i = 0; i < numPartitions; i = i + 1;) { + src[i] = new int[partitionLen]; + } + var j = 0; + var k = 0; + for (var i = 0; i < arrlen; i = i + 1;) { + src[j][k] = arr[i]; + if (j == numPartitions - 1) { + j = 0; + k = k + 1; + } else { j = j + 1; } + } + /* Build map-jobs */ + var mapJobs = new MapJob[numPartitions]; + for (var i = 0; i < numPartitions; i = i + 1;) { + mapJobs[i] = new MapJob { + f = square; + arr = src[i]; + arrlen = partitionLen + }; + } + /* Map! */ + var tgt = new int[][numPartitions]; + for (var i = 0; i < numPartitions; i = i + 1;) { + tgt[i] = mapNode(mapJobs[i]); + } + + /* Build reduce-jobs */ + var reduceJobs = new ReduceJob[numPartitions]; + for (var i = 0; i < numPartitions; i = i + 1;) { + reduceJobs[i] = new ReduceJob { + f = sum; + arr = tgt[i]; + arrlen = partitionLen; + base = 0 + }; + } + /* Reduce! */ + var acc = 0; + for (var i = 0; i < numPartitions; i = i + 1;) { + acc = acc + reduceNode(reduceJobs[i]); + } + return acc; +} + +int program(int argc, string[] argv) { + /* Initialize array with first n positive ints */ + var n = 30; + var arr = new int[n]; + for (var i = 0; i < n; i = i + 1;) { arr[i] = i + 1; } + /* Need partitionLen * numPartitions >= arr.length */ + var numPartitions = 5; + var partitionLen = 6; + return sumOfSquares(arr, n, numPartitions, partitionLen); +} diff --git a/hw5/hw5programs/initarr1.oat b/hw5/hw5programs/initarr1.oat new file mode 100644 index 0000000..a0ddf27 --- /dev/null +++ b/hw5/hw5programs/initarr1.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[3] {i -> i + 1}; + return x[0]; +} diff --git a/hw5/hw5programs/initarr2.oat b/hw5/hw5programs/initarr2.oat new file mode 100644 index 0000000..08d1c9c --- /dev/null +++ b/hw5/hw5programs/initarr2.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[3] {i -> 2}; + return x[0]; +} diff --git a/hw5/hw5programs/jacbrad_kruskal.oat b/hw5/hw5programs/jacbrad_kruskal.oat new file mode 100644 index 0000000..2dbfb1d --- /dev/null +++ b/hw5/hw5programs/jacbrad_kruskal.oat @@ -0,0 +1,120 @@ +struct Edge { + int u; + int v; + int weight +} + +int compare(Edge e1, Edge e2) { + return e1.weight - e2.weight; +} + +void sort((Edge, Edge) -> int cmp, int len, Edge[] list) { + + for(var i = 1; i < len; i = i + 1;){ + var j = i - 1; + var toswap = list[i]; + while(j >= 0) { + if(cmp(list[j], toswap) > 0) { + var temp = list[j]; + list[j] = list[j+1]; + list[j+1] = temp; + j = j - 1; + } + else { + j = -1; + } + } + } + return; +} + + +int[] create_ufind(int len) +{ + var arr = new int[len]; + for(var i = 0; i < len; i = i + 1;) + { + arr[i] = i; + } + return arr; + +} + +void union(int[] comps, int u, int v) +{ + var cU = find(comps, u); + var cV = find(comps, v); + + if(cU == cV) + { + return; + } + + comps[cU] = cV; + return; +} + +int find(int[] comps, int u) +{ + var root = u; + while(root != comps[root]) + { + root = comps[root]; + } + + while(u != root) + { + var parent = find(comps, comps[u]); + comps[u] = root; + u = parent; + + } + + return root; + +} + +Edge[] findMST(Edge[] edges, int m, int n) { + sort(compare, m, edges); + var uf = create_ufind(n); + var result = new Edge[n-1]; + var size = 0; + var count = 0; + + while(size < n - 1){ + + if(find(uf, edges[count].u) != find(uf, edges[count].v)){ + result[size] = edges[count]; + union(uf, edges[count].u, edges[count].v); + size = size + 1; + } + + count = count + 1; + } + return result; +} + + +int program (int argc, string[] argv) { + var e1 = new Edge {u = 1; v = 2; weight = 3}; + var e2 = new Edge {u = 0; v = 1; weight = 20}; + var e3 = new Edge {u = 1; v = 4; weight = 1}; + var e4 = new Edge {u = 2; v = 4; weight = 5}; + var e5 = new Edge {u = 3; v = 4; weight = 6}; + var e6 = new Edge {u = 2; v = 3; weight = 4}; + + var edges = new Edge[]{e1, e2, e3, e4, e5, e6}; + var mst = findMST(edges, 6, 5); + + for(var i = 0; i < 4; i = i + 1;){ + print_string("("); + print_int(mst[i].u); + print_string(","); + print_int(mst[i].v); + print_string(","); + print_int(mst[i].weight); + print_string(") "); + } + print_string("="); + return 0; +} diff --git a/hw5/hw5programs/johnhew_pagerank.oat b/hw5/hw5programs/johnhew_pagerank.oat new file mode 100644 index 0000000..ef50c1a --- /dev/null +++ b/hw5/hw5programs/johnhew_pagerank.oat @@ -0,0 +1,81 @@ +struct Node { + int value; + int new_value; + bool[] incoming_edges; + int outgoing_count +} + +struct PageRank { + int iterations; + (int, int) -> int division_fun; + (Node[], int) -> void iteration_fun; + (Node[], int, int) -> void run_fun +} + +int divide(int dividend, int divisor) { + var quotient = 0; + while (dividend > divisor) { + quotient = quotient + 1; + dividend = dividend - divisor; + } + /*print_int(quotient); + print_string("quotient\n");*/ + return quotient; +} + +void inter(Node[] nodes, int node_count) { + for (var i = 0; i < node_count; i = i+1; ) { + for (var j = 0; j < node_count; j = j+1; ) { + if (nodes[i].incoming_edges[j]) { + nodes[i].new_value = nodes[i].new_value + divide(nodes[j].value, nodes[j].outgoing_count); /* TODO: implement divide by number of outgoing edges. */ + } + } + } + for(var i = 0; i < node_count; i = i+1;) { + var half = nodes[i].new_value >> 1; + var quarter = nodes[i].new_value >> 2; + nodes[i].value = divide(250000,node_count) + half + quarter; /* This is 250000 (rather than 0.25) because of the lack of floating point support. */ + nodes[i].new_value = 0; + } + return; +} + +void run(Node[] nodes, int node_count, int iterations) { + for (var i = 0; i < 100; i = i + 1;) { + inter(nodes, node_count); + } + return; +} + +int program (int argc, string[] argv) { + var node_count = 3; + var nodes = new Node[node_count]; + var node_1_arr = new bool[] {false, false, true}; + var node_2_arr = new bool[] {false, false, false}; + var node_3_arr = new bool[] {true, true, false}; + nodes[0] = new Node {value = 333333; new_value = 0; incoming_edges = node_1_arr; outgoing_count = 1}; + nodes[1] = new Node {value = 333333; new_value = 0; incoming_edges = node_2_arr; outgoing_count = 1}; + nodes[2] = new Node {value = 333333; new_value = 0; incoming_edges = node_3_arr; outgoing_count = 1}; + + var pr = new PageRank {iterations = 100; division_fun = divide; iteration_fun = inter; run_fun = run}; + pr.run_fun(nodes, 3, 100); + + /*for (var i = 0; i < 100; i = i + 1;) { + inter(nodes, node_count); + }*/ + /*print_string("Results\n"); + print_string("Node 0: "); + print_int(nodes[0].value); + print_string("\n"); + print_string("Node 1: "); + print_int(nodes[1].value); + print_string("\n"); + print_string("Node 2: "); + print_int(nodes[2].value); + print_string("\n"); + print_string("Sum: "); + print_int(nodes[0].value + nodes[1].value + nodes[2].value); + print_string("\n");*/ + print_int(nodes[2].value); + return 0; +} diff --git a/hw5/hw5programs/kyim_test.oat b/hw5/hw5programs/kyim_test.oat new file mode 100644 index 0000000..d68a336 --- /dev/null +++ b/hw5/hw5programs/kyim_test.oat @@ -0,0 +1,53 @@ +global path1 = int[]{0, 0, 1}; +global path2 = int[]{1, 1, 0}; + +struct Node { + int val; + Node left; + Node right; + (int, int) -> int fun +} + +int sum_plus_one(int x, int y) { + return x+y+1; +} + +int two_x_plus_y(int x, int y) { + return 2*x+y; +} + +void make_children(Node root, int depth) { + if (depth != 0) { + var left_node = new Node{val=root.fun(root.val, 0); left=Node null; right=Node null; fun=root.fun}; + make_children(left_node, depth-1); + var right_node = new Node{val=root.fun(root.val, 1); left=Node null; right=Node null; fun=root.fun}; + make_children(right_node, depth-1); + root.left = left_node; + root.right = right_node; + } + return; +} + +int retrieve(Node root, int depth, int[] path) { + var next = root.right; + if (path[depth] == 0) { + next = root.left; + } + if (depth == 0) { + return next.val; + } else { + return retrieve(next, depth-1, path); + } +} + +int program(int argc, string[] argv) { + var root1 = new Node{val=1; left=Node null; right=Node null; fun=sum_plus_one}; + var root2 = new Node{val=2; left=Node null; right=Node null; fun=two_x_plus_y}; + make_children(root1, 3); + make_children(root2, 3); + if (retrieve(root1, 2, path1) == 5 & retrieve(root2, 2, path2) == 19) { + return 1; + } else { + return 0; + } +} diff --git a/hw5/hw5programs/length1.oat b/hw5/hw5programs/length1.oat new file mode 100644 index 0000000..eb365bf --- /dev/null +++ b/hw5/hw5programs/length1.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[] {3,4,5,6,7}; + return length(x); +} diff --git a/hw5/hw5programs/length2.oat b/hw5/hw5programs/length2.oat new file mode 100644 index 0000000..752811c --- /dev/null +++ b/hw5/hw5programs/length2.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[3]{i -> 0}; + return length(x); +} diff --git a/hw5/hw5programs/leqiliu_traversal.oat b/hw5/hw5programs/leqiliu_traversal.oat new file mode 100644 index 0000000..050a14d --- /dev/null +++ b/hw5/hw5programs/leqiliu_traversal.oat @@ -0,0 +1,61 @@ +struct Tree { + int val; + Tree left; + Tree right; + (int) -> void f +} + +void print(int val) { + print_string(string_cat("->", string_of_int(val))); + return; +} + +void in_order_traverse(Tree tree) { + tree.f(tree.val); + if(tree.left.val != 0) { + in_order_traverse(tree.left); + } + + if(tree.right.val != 0) { + in_order_traverse(tree.right); + } + return; +} + +void pre_order_traverse(Tree tree) { + if(tree.left.val != 0) { + pre_order_traverse(tree.left); + } + + tree.f(tree.val); + + if(tree.right.val != 0) { + pre_order_traverse(tree.right); + } + return; +} + +void post_order_traverse(Tree tree) { + if(tree.left.val != 0) { + post_order_traverse(tree.left); + } + + if(tree.right.val != 0) { + post_order_traverse(tree.right); + } + + tree.f(tree.val); + return; +} + +int program(int argc, string[] argv) { + var nullchild = new Tree { val = 0; left = Tree null; right = Tree null; f = print}; + var rightchild = new Tree { val = 1; left = nullchild; right = nullchild; f = print }; + var leftchild = new Tree { val = 1; left = nullchild; right = nullchild; f = print }; + var tree = new Tree { val = 2; left = leftchild; right = rightchild; f = print }; + + pre_order_traverse(tree); + in_order_traverse(tree); + post_order_traverse(tree); + return 0; +} \ No newline at end of file diff --git a/hw5/hw5programs/maale_odd_even.oat b/hw5/hw5programs/maale_odd_even.oat new file mode 100644 index 0000000..2c2b79b --- /dev/null +++ b/hw5/hw5programs/maale_odd_even.oat @@ -0,0 +1,35 @@ +int[] oddevensort (int[] input, int len) { + var sorted = false; + while(!sorted) { + sorted = true; + for(var i = 1; i < len - 1; i = i + 2;) { + if(input[i] > input[i + 1]) { + var temp = input[i]; + input[i] = input[i + 1]; + input[i + 1] = temp; + sorted = false; + } + } + + for(var j = 0; j < len - 1; j = j + 2;) { + if(input[j] > input[j+1]) { + var temp = input[j]; + input[j] = input[j + 1]; + input[j + 1] = temp; + sorted = false; + } + } + } + return input; +} + +int program (int argc, string[] argv) { + var arr = new int[]{ 5, 200, 1, 65, 30, 99, 2, 0 }; + var len = 8; + var sorted = oddevensort(arr, len); + for(var i=0; i 0) { + var d = s * s; + if (d > n) { + n = -1; + } else { + s = s + 1; + } + } + return s - 1; +} + +int side_squared(Point p1, Point p2) { + var m1 = (p1.x - p2.x) * (p1.x - p2.x); + var m2 = (p1.y - p2.y) * (p1.y - p2.y); + if (m1 > m2) { + return m1 - m2; + } else { + return m2 - m1; + } +} + +int pythagorean(Triangle t) { + var s1 = side_squared(t.p1, t.p2); + var s2 = side_squared(t.p2, t.p3); + return sqrt(s1 + s2); +} + +struct Triangle { + Point p1; + Point p2; + Point p3 +} + +struct Point { + int x; + int y +} + +global points = Point[] {Point { x = 0; y = 0 }, Point { x = 4; y = 0 }, Point { x = 4; y = 3 }}; + +int program(int argc, string[] argv) { + var t = new Triangle { p1 = points[0]; p2 = points[1]; p3 = points[2] }; + return pythagorean(t); +} \ No newline at end of file diff --git a/hw5/hw5programs/myprogram.oat b/hw5/hw5programs/myprogram.oat new file mode 100644 index 0000000..51867fa --- /dev/null +++ b/hw5/hw5programs/myprogram.oat @@ -0,0 +1,12 @@ +void debug(string msg) { + if (!debug) { + return; + } + print_string(msg); + return; +} +int program (int argc, string[] argv) { + var debug = "well"; + debug("DEBUG"); + debug = "xxlll"; +} diff --git a/hw5/hw5programs/negative_array_index.oat b/hw5/hw5programs/negative_array_index.oat new file mode 100644 index 0000000..530989e --- /dev/null +++ b/hw5/hw5programs/negative_array_index.oat @@ -0,0 +1,5 @@ +int program(string[] args) { + var arr = new int[]{1, 2, 3}; + var x = arr[-1]; + return x; +} \ No newline at end of file diff --git a/hw5/hw5programs/olekg_fold_struct.oat b/hw5/hw5programs/olekg_fold_struct.oat new file mode 100644 index 0000000..839dc74 --- /dev/null +++ b/hw5/hw5programs/olekg_fold_struct.oat @@ -0,0 +1,32 @@ +struct Node { + int i; + Node next; + bool hasNext +} + +int minus(int x, int y) { return x - y; } + +int plus(int x, int y) { return x + y; } + +int fold_str_int(Node n, (int, int) -> int f, int base) { + if(n.hasNext) { + var newBase = f(base, n.i); + return fold_str_int(n.next, f, newBase); + } else { + return f(base, n.i); + } +} + + +int program(int argc, string[] argv) { + var n9 = new Node {i=9; next=Node null; hasNext=false}; + var n8 = new Node {i=8; next=n9; hasNext=true}; + var n7 = new Node {i=7; next=n8; hasNext=true}; + var n6 = new Node {i=6; next=n7; hasNext=true}; + var n5 = new Node {i=5; next=n6; hasNext=true}; + var n4 = new Node {i=4; next=n5; hasNext=true}; + var n3 = new Node {i=3; next=n4; hasNext=true}; + var n2 = new Node {i=2; next=n3; hasNext=true}; + var n1 = new Node {i=1; next=n2; hasNext=true}; + return fold_str_int(n1, plus, 0) - fold_str_int(n1, minus, 2); +} \ No newline at end of file diff --git a/hw5/hw5programs/ssumit_balancedparens.oat b/hw5/hw5programs/ssumit_balancedparens.oat new file mode 100644 index 0000000..37a8971 --- /dev/null +++ b/hw5/hw5programs/ssumit_balancedparens.oat @@ -0,0 +1,104 @@ +struct Node { + int p; + Node next +} + +struct Stack { + int size; + Node head; + (Stack, int) -> Stack push; + (Stack) -> Stack pop; + (Stack) -> int peek +} + +Stack push(Stack stack, int paren) { + var n = new Node {p = paren; next = stack.head}; + return new Stack {size = stack.size + 1; head = n; push = stack.push; pop = stack.pop; peek = stack.peek}; +} + +Stack pop(Stack stack) { + if (stack.size == 0) { + return Stack null; + } + return new Stack{size = stack.size - 1; head = stack.head.next; push = stack.push; pop = stack.pop; peek = stack.peek}; +} + +int peek(Stack stack) { + if (stack.size == 0) { + return -1; + } + return stack.head.p; +} + +global leftParen = 40; +global leftBracket = 91; +global leftBrace = 123; +global rightParen = 41; +global rightBracket = 93; +global rightBrace = 125; + + +bool isStringBalanced(string input) { + var stack = new Stack {size = 0; head = Node null; push = push; pop = pop; peek = peek}; + var length = length_of_string(input); + var char_arr = array_of_string(input); + var result = new int[2*length]; + var ptr = 0; + for (var i = 0; i < length; i = i + 1;) { + var char = char_arr[i]; + if (char == leftParen | char == leftBracket | char == leftBrace) { + stack = stack.push(stack, char); + } else if (char == rightParen) { + var head = stack.peek(stack); + stack = stack.pop(stack); + if (head != leftParen) { + print_string("mismatch"); + return false; + } + result[ptr] = leftParen; + ptr = ptr + 1; + result[ptr] = rightParen; + ptr = ptr + 1; + } else if (char == rightBracket) { + var head = stack.peek(stack); + stack = stack.pop(stack); + if (head != leftBracket) { + print_string("mismatch"); + return false; + } + result[ptr] = leftBracket; + ptr = ptr + 1; + result[ptr] = rightBracket; + ptr = ptr + 1; + } else if (char == rightBrace) { + var head = stack.peek(stack); + stack = stack.pop(stack); + if (head != leftBrace) { + print_string("mismatch"); + return false; + } + result[ptr] = leftBrace; + ptr = ptr + 1; + result[ptr] = rightBrace; + ptr = ptr + 1; + } + } + if (stack.size != 0) { + print_string("mismatch"); + return false; + } + var finalString = new int[ptr]; + for (var i = 0; i < ptr; i = i + 1;) { + finalString[i] = result[i]; + } + print_string(string_of_array(finalString)); + return true; +} + +int program(int argc, string[] argv) { + var result = isStringBalanced(argv[1]); + if (result) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_array_err.oat b/hw5/hw5programs/tc_array_err.oat new file mode 100644 index 0000000..0b42c76 --- /dev/null +++ b/hw5/hw5programs/tc_array_err.oat @@ -0,0 +1,14 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +int f() { + var x = A[] null; + x = B[] null; + return 2; +} diff --git a/hw5/hw5programs/tc_arrow.oat b/hw5/hw5programs/tc_arrow.oat new file mode 100644 index 0000000..52183f9 --- /dev/null +++ b/hw5/hw5programs/tc_arrow.oat @@ -0,0 +1,15 @@ +int f((int) -> int g) { + return s(3); +} + +int s(int x) { + return x; +} + +int l(((int) -> int) -> int x) { + return 0; +} + +int main() { + return l(f); +} diff --git a/hw5/hw5programs/tc_arrow_null.oat b/hw5/hw5programs/tc_arrow_null.oat new file mode 100644 index 0000000..964b21e --- /dev/null +++ b/hw5/hw5programs/tc_arrow_null.oat @@ -0,0 +1,13 @@ +struct Point { + int x; + int y +} + +Point? f() { + return Point null; +} + +int g(() -> Point? x) { + return 0; +} + diff --git a/hw5/hw5programs/tc_arrow_null_rec.oat b/hw5/hw5programs/tc_arrow_null_rec.oat new file mode 100644 index 0000000..e566ef7 --- /dev/null +++ b/hw5/hw5programs/tc_arrow_null_rec.oat @@ -0,0 +1,17 @@ +struct Point { + int x; + int y +} + +Point? f() { + return Point null; +} + +Point? g(() -> Point? x) { + return x(); +} + +Point? h((() -> Point?) -> Point? x) { + return x(f); +} + diff --git a/hw5/hw5programs/tc_assn_err.oat b/hw5/hw5programs/tc_assn_err.oat new file mode 100644 index 0000000..3b8822a --- /dev/null +++ b/hw5/hw5programs/tc_assn_err.oat @@ -0,0 +1,9 @@ +int f() { + return 3; +} + +int bad() { + f() = 4; + return 0; +} + diff --git a/hw5/hw5programs/tc_correct_array.oat b/hw5/hw5programs/tc_correct_array.oat new file mode 100644 index 0000000..a57b14c --- /dev/null +++ b/hw5/hw5programs/tc_correct_array.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + var int_arr = new int[] {3, 4}; + var arr = new int[int_arr[2]]{i -> 0}; + return int_arr[0]; +} diff --git a/hw5/hw5programs/tc_correct_call.oat b/hw5/hw5programs/tc_correct_call.oat new file mode 100644 index 0000000..07f7399 --- /dev/null +++ b/hw5/hw5programs/tc_correct_call.oat @@ -0,0 +1,7 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int program(int argc, string[] argv) { + return add(3, 4); +} diff --git a/hw5/hw5programs/tc_correct_for.oat b/hw5/hw5programs/tc_correct_for.oat new file mode 100644 index 0000000..9ff1a4a --- /dev/null +++ b/hw5/hw5programs/tc_correct_for.oat @@ -0,0 +1,6 @@ +int program(int argc, string[] argv) { + for (var i = 0; i < 5; i = i + 1; ) { + return 0; + } + return 0; +} diff --git a/hw5/hw5programs/tc_correct_fptr.oat b/hw5/hw5programs/tc_correct_fptr.oat new file mode 100644 index 0000000..07f7399 --- /dev/null +++ b/hw5/hw5programs/tc_correct_fptr.oat @@ -0,0 +1,7 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int program(int argc, string[] argv) { + return add(3, 4); +} diff --git a/hw5/hw5programs/tc_correct_fptr_array.oat b/hw5/hw5programs/tc_correct_fptr_array.oat new file mode 100644 index 0000000..a846b82 --- /dev/null +++ b/hw5/hw5programs/tc_correct_fptr_array.oat @@ -0,0 +1,7 @@ +int add(int x, int y) { return x + y; } +int sub(int x, int y) { return x - y; } + +int program(int argc, string[] argv) { + var x = new ((int, int) -> int) [] { add, sub }; + return 0; +} diff --git a/hw5/hw5programs/tc_correct_function_shadow.oat b/hw5/hw5programs/tc_correct_function_shadow.oat new file mode 100644 index 0000000..1fc85e2 --- /dev/null +++ b/hw5/hw5programs/tc_correct_function_shadow.oat @@ -0,0 +1,12 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int mul(int arg1, int arg2) { + return arg1 * arg2; +} + +int program(int argc, string[] argv) { + var add = mul; + return add(3, 4); +} diff --git a/hw5/hw5programs/tc_correct_global.oat b/hw5/hw5programs/tc_correct_global.oat new file mode 100644 index 0000000..a405023 --- /dev/null +++ b/hw5/hw5programs/tc_correct_global.oat @@ -0,0 +1,11 @@ +int program(int argc, string[] argv) { + var x = array_of_string(""); + var y = string_of_array(x); + var z = length_of_string(y); + var a = string_of_int(3); + var b = string_cat("hello", "world"); + print_string(b); + print_int(3); + print_bool(true); + return z; +} diff --git a/hw5/hw5programs/tc_correct_if.oat b/hw5/hw5programs/tc_correct_if.oat new file mode 100644 index 0000000..502ab3d --- /dev/null +++ b/hw5/hw5programs/tc_correct_if.oat @@ -0,0 +1,7 @@ +int program(int argc, string[] argv) { + if (true) { + return 0; + } else { + return 1; + } +} diff --git a/hw5/hw5programs/tc_correct_local_redeclaration.oat b/hw5/hw5programs/tc_correct_local_redeclaration.oat new file mode 100644 index 0000000..97d977f --- /dev/null +++ b/hw5/hw5programs/tc_correct_local_redeclaration.oat @@ -0,0 +1,6 @@ +global x = 2; + +int program(int argc, string[] argv) { + var x = 2; + return x; +} diff --git a/hw5/hw5programs/tc_correct_null.oat b/hw5/hw5programs/tc_correct_null.oat new file mode 100644 index 0000000..65d9053 --- /dev/null +++ b/hw5/hw5programs/tc_correct_null.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] argv) { + var x = new (int[])[] { int[] null }; + return x[0][1]; +} diff --git a/hw5/hw5programs/tc_correct_struct.oat b/hw5/hw5programs/tc_correct_struct.oat new file mode 100644 index 0000000..6d3cba9 --- /dev/null +++ b/hw5/hw5programs/tc_correct_struct.oat @@ -0,0 +1,9 @@ +struct T { + int f1; + int f2 +} + +int program(int argc, string[] argv) { + var x = new T { f1 = 3; f2 = 4 }; + return x.f1; +} diff --git a/hw5/hw5programs/tc_correct_struct_fptr.oat b/hw5/hw5programs/tc_correct_struct_fptr.oat new file mode 100644 index 0000000..4319004 --- /dev/null +++ b/hw5/hw5programs/tc_correct_struct_fptr.oat @@ -0,0 +1,12 @@ +struct S { + int s; + int t; + (int, int) -> int f +} + +int add(int x, int y) { return x + y; } + +int program(int argc, string[] argv) { + var x = new S { s = 3; t = 4; f = add }; + return x.f(x.s, x.t); +} diff --git a/hw5/hw5programs/tc_correct_void.oat b/hw5/hw5programs/tc_correct_void.oat new file mode 100644 index 0000000..8b5139b --- /dev/null +++ b/hw5/hw5programs/tc_correct_void.oat @@ -0,0 +1,7 @@ +void f() { + return; +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw5/hw5programs/tc_correct_while.oat b/hw5/hw5programs/tc_correct_while.oat new file mode 100644 index 0000000..e370aef --- /dev/null +++ b/hw5/hw5programs/tc_correct_while.oat @@ -0,0 +1,6 @@ +int program(int argc, string[] argv) { + while (1 > 0) { + return 3; + } + return 0; +} diff --git a/hw5/hw5programs/tc_error_array1.oat b/hw5/hw5programs/tc_error_array1.oat new file mode 100644 index 0000000..3834bd2 --- /dev/null +++ b/hw5/hw5programs/tc_error_array1.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + var arr = new int[] {4, 5}; + arr[1] = true; + return arr[0]; +} diff --git a/hw5/hw5programs/tc_error_array2.oat b/hw5/hw5programs/tc_error_array2.oat new file mode 100644 index 0000000..22c2698 --- /dev/null +++ b/hw5/hw5programs/tc_error_array2.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + var arr2 = new bool[] { true, false }; + var arr = new int[arr2[0]]{i -> 0}; + return arr[0]; +} diff --git a/hw5/hw5programs/tc_error_assign_void.oat b/hw5/hw5programs/tc_error_assign_void.oat new file mode 100644 index 0000000..b838be0 --- /dev/null +++ b/hw5/hw5programs/tc_error_assign_void.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] argv) { + var x = print_int(3); + return 0; +} diff --git a/hw5/hw5programs/tc_error_binop1.oat b/hw5/hw5programs/tc_error_binop1.oat new file mode 100644 index 0000000..3ef0178 --- /dev/null +++ b/hw5/hw5programs/tc_error_binop1.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return 1 + true; +} diff --git a/hw5/hw5programs/tc_error_binop2.oat b/hw5/hw5programs/tc_error_binop2.oat new file mode 100644 index 0000000..f557307 --- /dev/null +++ b/hw5/hw5programs/tc_error_binop2.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return true | 3; +} diff --git a/hw5/hw5programs/tc_error_binop3.oat b/hw5/hw5programs/tc_error_binop3.oat new file mode 100644 index 0000000..47d57c5 --- /dev/null +++ b/hw5/hw5programs/tc_error_binop3.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return 1 [|] true; +} diff --git a/hw5/hw5programs/tc_error_call1.oat b/hw5/hw5programs/tc_error_call1.oat new file mode 100644 index 0000000..af3ce19 --- /dev/null +++ b/hw5/hw5programs/tc_error_call1.oat @@ -0,0 +1,7 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int program(int argc, string[] argv) { + return add(3, 4, 5); +} diff --git a/hw5/hw5programs/tc_error_call2.oat b/hw5/hw5programs/tc_error_call2.oat new file mode 100644 index 0000000..631b0cf --- /dev/null +++ b/hw5/hw5programs/tc_error_call2.oat @@ -0,0 +1,7 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int program(int argc, string[] argv) { + return add(3, false); +} diff --git a/hw5/hw5programs/tc_error_dupstruct.oat b/hw5/hw5programs/tc_error_dupstruct.oat new file mode 100644 index 0000000..be05de2 --- /dev/null +++ b/hw5/hw5programs/tc_error_dupstruct.oat @@ -0,0 +1,11 @@ +struct L { + bool b +} + +struct L { + int c +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw5/hw5programs/tc_error_early_return.oat b/hw5/hw5programs/tc_error_early_return.oat new file mode 100644 index 0000000..7f5252e --- /dev/null +++ b/hw5/hw5programs/tc_error_early_return.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + return 3; + var x = 5; + return 4; +} diff --git a/hw5/hw5programs/tc_error_early_return_void.oat b/hw5/hw5programs/tc_error_early_return_void.oat new file mode 100644 index 0000000..c378553 --- /dev/null +++ b/hw5/hw5programs/tc_error_early_return_void.oat @@ -0,0 +1,9 @@ +void f() { + return; + var x = 5; + return; +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw5/hw5programs/tc_error_for.oat b/hw5/hw5programs/tc_error_for.oat new file mode 100644 index 0000000..0a05986 --- /dev/null +++ b/hw5/hw5programs/tc_error_for.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + for (var i = 0; i < 5; i = i + 1; ) { + return 0; + } +} diff --git a/hw5/hw5programs/tc_error_func_assign.oat b/hw5/hw5programs/tc_error_func_assign.oat new file mode 100644 index 0000000..904384f --- /dev/null +++ b/hw5/hw5programs/tc_error_func_assign.oat @@ -0,0 +1,12 @@ +int f() { + return 0; +} + +int g() { + return 1; +} + +int program(string[] args) { + f = g; + return 0; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_error_func_redeclaration.oat b/hw5/hw5programs/tc_error_func_redeclaration.oat new file mode 100644 index 0000000..610cedc --- /dev/null +++ b/hw5/hw5programs/tc_error_func_redeclaration.oat @@ -0,0 +1,11 @@ +int id(int x) { + return x; +} + +bool id (bool b) { + return b; +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw5/hw5programs/tc_error_function_no_shadow.oat b/hw5/hw5programs/tc_error_function_no_shadow.oat new file mode 100644 index 0000000..b6b00a3 --- /dev/null +++ b/hw5/hw5programs/tc_error_function_no_shadow.oat @@ -0,0 +1,12 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +bool foo(int arg2) { + return true; +} + +int program(int argc, string[] argv) { + var add = foo; + return add(3, 4); +} diff --git a/hw5/hw5programs/tc_error_global.oat b/hw5/hw5programs/tc_error_global.oat new file mode 100644 index 0000000..fef5639 --- /dev/null +++ b/hw5/hw5programs/tc_error_global.oat @@ -0,0 +1,7 @@ +global x = 3; + +int program(int argc, string[] argv) { + var y = new bool[] { true }; + y[0] = x; + return y; +} diff --git a/hw5/hw5programs/tc_error_global_dup.oat b/hw5/hw5programs/tc_error_global_dup.oat new file mode 100644 index 0000000..bd3218a --- /dev/null +++ b/hw5/hw5programs/tc_error_global_dup.oat @@ -0,0 +1,6 @@ +global x = 3; +global x = 4; + +int program(int argc, string[] argv) { + return x; +} diff --git a/hw5/hw5programs/tc_error_global_fptr_scope.oat b/hw5/hw5programs/tc_error_global_fptr_scope.oat new file mode 100644 index 0000000..d17d869 --- /dev/null +++ b/hw5/hw5programs/tc_error_global_fptr_scope.oat @@ -0,0 +1,10 @@ +int f(int x, int y) { + return x + y; +} + +global x = f; +global y = x; + +int program(int argc, string[] argv) { + return y(3,4); +} diff --git a/hw5/hw5programs/tc_error_if.oat b/hw5/hw5programs/tc_error_if.oat new file mode 100644 index 0000000..f18348a --- /dev/null +++ b/hw5/hw5programs/tc_error_if.oat @@ -0,0 +1,7 @@ +int program(int argc, string[] argv) { + if (true) { + return 0; + } else { + var x = 3; + } +} diff --git a/hw5/hw5programs/tc_error_if_nonbool.oat b/hw5/hw5programs/tc_error_if_nonbool.oat new file mode 100644 index 0000000..3ef1347 --- /dev/null +++ b/hw5/hw5programs/tc_error_if_nonbool.oat @@ -0,0 +1,6 @@ +int program(int argc, string[] argv) { + if (3) { + } else { + } + return 0; +} diff --git a/hw5/hw5programs/tc_error_null.oat b/hw5/hw5programs/tc_error_null.oat new file mode 100644 index 0000000..1ebb883 --- /dev/null +++ b/hw5/hw5programs/tc_error_null.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] argv) { + var x = new (int[])[] { string[] null }; + return x[0][1]; +} diff --git a/hw5/hw5programs/tc_error_overwrite.oat b/hw5/hw5programs/tc_error_overwrite.oat new file mode 100644 index 0000000..bafb6aa --- /dev/null +++ b/hw5/hw5programs/tc_error_overwrite.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + var x = true; + var x = 3; + return x; +} diff --git a/hw5/hw5programs/tc_error_return_wrong.oat b/hw5/hw5programs/tc_error_return_wrong.oat new file mode 100644 index 0000000..572fd92 --- /dev/null +++ b/hw5/hw5programs/tc_error_return_wrong.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return true; +} diff --git a/hw5/hw5programs/tc_error_scall_nonvoid.oat b/hw5/hw5programs/tc_error_scall_nonvoid.oat new file mode 100644 index 0000000..27aa76a --- /dev/null +++ b/hw5/hw5programs/tc_error_scall_nonvoid.oat @@ -0,0 +1,9 @@ +int print(int x) { + print_int(x); + return x; +} + +int program(int argc, string[] argv) { + print(argc); + return 0; +} diff --git a/hw5/hw5programs/tc_error_struct.oat b/hw5/hw5programs/tc_error_struct.oat new file mode 100644 index 0000000..739d792 --- /dev/null +++ b/hw5/hw5programs/tc_error_struct.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int[] program(int argc, string[] argv) { + var x = new S { f1 = true; f2 = 3 }; + return x.f1; +} diff --git a/hw5/hw5programs/tc_error_struct1.oat b/hw5/hw5programs/tc_error_struct1.oat new file mode 100644 index 0000000..739d792 --- /dev/null +++ b/hw5/hw5programs/tc_error_struct1.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int[] program(int argc, string[] argv) { + var x = new S { f1 = true; f2 = 3 }; + return x.f1; +} diff --git a/hw5/hw5programs/tc_error_struct2.oat b/hw5/hw5programs/tc_error_struct2.oat new file mode 100644 index 0000000..5439677 --- /dev/null +++ b/hw5/hw5programs/tc_error_struct2.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int program(int argc, string[] argv) { + var x = new S { f1 = 4; f2 = 3; f3 = 4 }; + return x.f1; +} diff --git a/hw5/hw5programs/tc_error_struct3.oat b/hw5/hw5programs/tc_error_struct3.oat new file mode 100644 index 0000000..0bb9230 --- /dev/null +++ b/hw5/hw5programs/tc_error_struct3.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int program(int argc, string[] argv) { + var x = new S { f1 = 4; f2 = 3; f1 = 4 }; + return x.f1; +} diff --git a/hw5/hw5programs/tc_error_struct4.oat b/hw5/hw5programs/tc_error_struct4.oat new file mode 100644 index 0000000..f9d38c3 --- /dev/null +++ b/hw5/hw5programs/tc_error_struct4.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int program(int argc, string[] argv) { + var x = new S { f1 = 4 }; + return x.f1; +} diff --git a/hw5/hw5programs/tc_error_struct_dup.oat b/hw5/hw5programs/tc_error_struct_dup.oat new file mode 100644 index 0000000..ebd5a8f --- /dev/null +++ b/hw5/hw5programs/tc_error_struct_dup.oat @@ -0,0 +1,8 @@ +struct X { + int y; + int y +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw5/hw5programs/tc_error_struct_proj.oat b/hw5/hw5programs/tc_error_struct_proj.oat new file mode 100644 index 0000000..f1fe1d9 --- /dev/null +++ b/hw5/hw5programs/tc_error_struct_proj.oat @@ -0,0 +1,12 @@ +struct T { + int f +} + +struct G { + int g +} + +int program(int argc, string[] argv) { + var x = new T { f = 3 }; + return x.g; +} diff --git a/hw5/hw5programs/tc_error_struct_unbound.oat b/hw5/hw5programs/tc_error_struct_unbound.oat new file mode 100644 index 0000000..4d545f3 --- /dev/null +++ b/hw5/hw5programs/tc_error_struct_unbound.oat @@ -0,0 +1,8 @@ +struct T { + S name; + int x +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw5/hw5programs/tc_error_unop1.oat b/hw5/hw5programs/tc_error_unop1.oat new file mode 100644 index 0000000..47846cb --- /dev/null +++ b/hw5/hw5programs/tc_error_unop1.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return !3; +} diff --git a/hw5/hw5programs/tc_error_void.oat b/hw5/hw5programs/tc_error_void.oat new file mode 100644 index 0000000..fac8c61 --- /dev/null +++ b/hw5/hw5programs/tc_error_void.oat @@ -0,0 +1,7 @@ +void f() { + return 3; +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw5/hw5programs/tc_error_while.oat b/hw5/hw5programs/tc_error_while.oat new file mode 100644 index 0000000..0e20ddd --- /dev/null +++ b/hw5/hw5programs/tc_error_while.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + while (1 > 0) { + return 3; + } +} diff --git a/hw5/hw5programs/tc_error_while_nonbool.oat b/hw5/hw5programs/tc_error_while_nonbool.oat new file mode 100644 index 0000000..310063b --- /dev/null +++ b/hw5/hw5programs/tc_error_while_nonbool.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + while (3) { + } + return 0; +} diff --git a/hw5/hw5programs/tc_func_arg_err.oat b/hw5/hw5programs/tc_func_arg_err.oat new file mode 100644 index 0000000..ac00f9a --- /dev/null +++ b/hw5/hw5programs/tc_func_arg_err.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +int f(A x) { + return 3; +} + +int g(B x) { + return 3; +} + +int l() { + var x = f; + x = g; + return 3; +} + diff --git a/hw5/hw5programs/tc_func_arg_ok.oat b/hw5/hw5programs/tc_func_arg_ok.oat new file mode 100644 index 0000000..7dbf401 --- /dev/null +++ b/hw5/hw5programs/tc_func_arg_ok.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +int f(A x) { + return 3; +} + +int g(B x) { + return 3; +} + +int l() { + var x = g; + x = f; + return 3; +} + diff --git a/hw5/hw5programs/tc_func_ret_err.oat b/hw5/hw5programs/tc_func_ret_err.oat new file mode 100644 index 0000000..700fb30 --- /dev/null +++ b/hw5/hw5programs/tc_func_ret_err.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +A f() { + return new A {x = 3}; +} + +B g() { + return new B {x = 3; y = 4}; +} + +int l() { + var x = g; + x = f; + return 3; +} + diff --git a/hw5/hw5programs/tc_func_ret_ok.oat b/hw5/hw5programs/tc_func_ret_ok.oat new file mode 100644 index 0000000..daac258 --- /dev/null +++ b/hw5/hw5programs/tc_func_ret_ok.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +A f() { + return new A {x = 3}; +} + +B g() { + return new B {x = 3; y = 4}; +} + +int l() { + var x = f; + x = g; + return 3; +} + diff --git a/hw5/hw5programs/tc_ifq1.oat b/hw5/hw5programs/tc_ifq1.oat new file mode 100644 index 0000000..d242770 --- /dev/null +++ b/hw5/hw5programs/tc_ifq1.oat @@ -0,0 +1,17 @@ +int sum(int[]? arr) { + var acc = 0; + if? (int[] a = arr) { + for(var i = 0; i < length(a); i = i+1;) { + acc = acc + a[i]; + } + } + return acc; +} + + +int program (int argc, string[] argv) { + var a1 = new int[]{1, 2, 3, 4}; + var a2 = int[] null; + var x = sum(a1) + sum(a2); + return x; +} diff --git a/hw5/hw5programs/tc_ifq_err1.oat b/hw5/hw5programs/tc_ifq_err1.oat new file mode 100644 index 0000000..5ce5716 --- /dev/null +++ b/hw5/hw5programs/tc_ifq_err1.oat @@ -0,0 +1,17 @@ +struct T { int x } +struct S { int x; int y } + +int sum(T? t) { + if?(S s = t) { + return s.y; + } else { + return 0; + } +} + +int program (int argc, string[] argv) { + var x = 0; + x = x + sum(S null); + x = x + sum(new S{x=4; y=5}); + return x; +} diff --git a/hw5/hw5programs/tc_null_array_err.oat b/hw5/hw5programs/tc_null_array_err.oat new file mode 100644 index 0000000..7318c5c --- /dev/null +++ b/hw5/hw5programs/tc_null_array_err.oat @@ -0,0 +1,5 @@ +int f() { + var x = int[] null; + x = new int[] {3,4}; + return x[0]; +} diff --git a/hw5/hw5programs/tc_recursive_struct_err.oat b/hw5/hw5programs/tc_recursive_struct_err.oat new file mode 100644 index 0000000..a0f0b3a --- /dev/null +++ b/hw5/hw5programs/tc_recursive_struct_err.oat @@ -0,0 +1,12 @@ +struct A{ + B x +} + +struct B { + A x +} + +void f() { + var x = A null; + x = B null; +} diff --git a/hw5/hw5programs/tc_struct_bad.oat b/hw5/hw5programs/tc_struct_bad.oat new file mode 100644 index 0000000..67e4170 --- /dev/null +++ b/hw5/hw5programs/tc_struct_bad.oat @@ -0,0 +1,4 @@ +void foo() { + var x = new S[]{S null}; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_struct_err.oat b/hw5/hw5programs/tc_struct_err.oat new file mode 100644 index 0000000..ffd69ac --- /dev/null +++ b/hw5/hw5programs/tc_struct_err.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +A f() { + return new A {x = 3}; +} + +B g() { + return new B {x = 3; y = 4}; +} + +int l() { + var x = g(); + x = f(); + return 3; +} + diff --git a/hw5/hw5programs/tc_struct_field_err.oat b/hw5/hw5programs/tc_struct_field_err.oat new file mode 100644 index 0000000..bd97c45 --- /dev/null +++ b/hw5/hw5programs/tc_struct_field_err.oat @@ -0,0 +1,22 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +struct C { + A x +} + +struct D { + B x +} + +int f() { + var x = C null; + x = D null; + return 2; +} diff --git a/hw5/hw5programs/tc_struct_ok.oat b/hw5/hw5programs/tc_struct_ok.oat new file mode 100644 index 0000000..b0e155f --- /dev/null +++ b/hw5/hw5programs/tc_struct_ok.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +A f() { + return new A {x = 3}; +} + +B g() { + return new B {x = 3; y = 4}; +} + +int l() { + var x = f(); + x = g(); + return 3; +} + diff --git a/hw5/hw5programs/tc_subtyping1.oat b/hw5/hw5programs/tc_subtyping1.oat new file mode 100644 index 0000000..d09a965 --- /dev/null +++ b/hw5/hw5programs/tc_subtyping1.oat @@ -0,0 +1,4 @@ +void f(int[] x, int[]? y) { + y = x; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping2.oat b/hw5/hw5programs/tc_subtyping2.oat new file mode 100644 index 0000000..7187dc1 --- /dev/null +++ b/hw5/hw5programs/tc_subtyping2.oat @@ -0,0 +1,7 @@ +struct A {} +struct B { int x } + +void foo(A a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping3.oat b/hw5/hw5programs/tc_subtyping3.oat new file mode 100644 index 0000000..e2b3c7a --- /dev/null +++ b/hw5/hw5programs/tc_subtyping3.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int x ; int y } + +void foo(A a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping4.oat b/hw5/hw5programs/tc_subtyping4.oat new file mode 100644 index 0000000..59dcd7e --- /dev/null +++ b/hw5/hw5programs/tc_subtyping4.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int x ; int y } + +void foo(A? a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping5.oat b/hw5/hw5programs/tc_subtyping5.oat new file mode 100644 index 0000000..cd0d57e --- /dev/null +++ b/hw5/hw5programs/tc_subtyping5.oat @@ -0,0 +1,11 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y } + +void foo(A a, B b, C c) { + a = b; + a = c; + b = c; + c = b; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping6.oat b/hw5/hw5programs/tc_subtyping6.oat new file mode 100644 index 0000000..aca5f5b --- /dev/null +++ b/hw5/hw5programs/tc_subtyping6.oat @@ -0,0 +1,6 @@ +struct A { int x } +struct B { int x ; int y } + +A f(B b) { + return b; +} diff --git a/hw5/hw5programs/tc_subtyping7.oat b/hw5/hw5programs/tc_subtyping7.oat new file mode 100644 index 0000000..596821b --- /dev/null +++ b/hw5/hw5programs/tc_subtyping7.oat @@ -0,0 +1,20 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y ; int z } + +/* C <: B B <: B */ +/* ---------------------- */ +/* (B) -> B <: (C) -> B */ +B f(B b) { + return b; +} + +B g((C) -> B f) { + var c = new C {x = 1; y = 2; z = 3}; + return f(c); +} + +int program(string[] args) { + var b = g(f); + return b.y; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping8.oat b/hw5/hw5programs/tc_subtyping8.oat new file mode 100644 index 0000000..8813494 --- /dev/null +++ b/hw5/hw5programs/tc_subtyping8.oat @@ -0,0 +1,19 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y ; int z } + +/* C <: B B <: B */ +/* ---------------------- */ +/* (B) -> B <: (C) -> B */ +B f(B b) { + return b; +} + +void g((C) -> B f) { + return; +} + +int program(string[] args) { + g(f); + return 0; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping9.oat b/hw5/hw5programs/tc_subtyping9.oat new file mode 100644 index 0000000..2091e53 --- /dev/null +++ b/hw5/hw5programs/tc_subtyping9.oat @@ -0,0 +1,19 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y ; int z } + +/* C <: B B <: B */ +/* ---------------------- */ +/* (B) -> B <: (C) -> B */ +B? f(B b) { + return b; +} + +void g((C) -> B? f) { + return; +} + +int program(string[] args) { + g(f); + return 0; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping_err1.oat b/hw5/hw5programs/tc_subtyping_err1.oat new file mode 100644 index 0000000..1f61ddd --- /dev/null +++ b/hw5/hw5programs/tc_subtyping_err1.oat @@ -0,0 +1,4 @@ +void f(int[] x, int[]? y) { + x = y; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping_err2.oat b/hw5/hw5programs/tc_subtyping_err2.oat new file mode 100644 index 0000000..c6f0f62 --- /dev/null +++ b/hw5/hw5programs/tc_subtyping_err2.oat @@ -0,0 +1,7 @@ +struct A {} +struct B { int x } + +void foo(A a, B b) { + b = a; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping_err3.oat b/hw5/hw5programs/tc_subtyping_err3.oat new file mode 100644 index 0000000..b090f8d --- /dev/null +++ b/hw5/hw5programs/tc_subtyping_err3.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int x ; int y } + +void foo(A a, B b) { + b = a; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping_err4.oat b/hw5/hw5programs/tc_subtyping_err4.oat new file mode 100644 index 0000000..d77b766 --- /dev/null +++ b/hw5/hw5programs/tc_subtyping_err4.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int x ; int y } + +void foo(A? a, B b) { + b = a; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping_err5.oat b/hw5/hw5programs/tc_subtyping_err5.oat new file mode 100644 index 0000000..582b3c2 --- /dev/null +++ b/hw5/hw5programs/tc_subtyping_err5.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { bool x ; int y } + +void foo(A a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping_err6.oat b/hw5/hw5programs/tc_subtyping_err6.oat new file mode 100644 index 0000000..3dc023d --- /dev/null +++ b/hw5/hw5programs/tc_subtyping_err6.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int y } + +void foo(A a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw5/hw5programs/tc_subtyping_err7.oat b/hw5/hw5programs/tc_subtyping_err7.oat new file mode 100644 index 0000000..afb5731 --- /dev/null +++ b/hw5/hw5programs/tc_subtyping_err7.oat @@ -0,0 +1,6 @@ +struct A { int x } +struct B { int x ; int y } + +B f(A a) { + return a; +} diff --git a/hw5/hw5programs/tc_subtyping_err8.oat b/hw5/hw5programs/tc_subtyping_err8.oat new file mode 100644 index 0000000..7b16b9c --- /dev/null +++ b/hw5/hw5programs/tc_subtyping_err8.oat @@ -0,0 +1,19 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y ; int z } + +/* C <: B B <: B */ +/* ---------------------- */ +/* (B) -> B <: (C) -> B */ +B? f(B b) { + return b; +} + +void g((C) -> B f) { + return; +} + +int program(string[] args) { + g(f); + return 0; +} \ No newline at end of file diff --git a/hw5/hw5programs/whartonv_calculator.oat b/hw5/hw5programs/whartonv_calculator.oat new file mode 100644 index 0000000..8ceba15 --- /dev/null +++ b/hw5/hw5programs/whartonv_calculator.oat @@ -0,0 +1,149 @@ +struct Node { + int val; + Node next +} + +struct Stack { + Node head; + int size +} + +struct Calculator { + (Stack) -> void add; + (Stack) -> void sub; + (Stack) -> void mul +} + +/* Stack operations */ +Stack new_stack() { + return new Stack { head = Node null; size = 0 }; +} + +int peek_stack(Stack s) { + if (s.size == 0) { + return -1; + } + return s.head.val; +} + +int pop_stack(Stack s) { + if (s.size == 0) { + return -1; + } + var top = s.head.val; + s.head = s.head.next; + s.size = s.size - 1; + return top; +} + +void push_stack(Stack s, int v) { + var node = new Node { val = v; next = s.head }; + s.head = node; + s.size = s.size - 1; + return; +} + +int get_val(int i) { + /* turns a char_code i into a value v */ + return i - 48; +} + +/* Calculator operations */ +void calc_binop(Stack s, (int, int) -> int op) { + var x1 = pop_stack(s); + var x2 = pop_stack(s); + var val = op(x1, x2); + push_stack(s, val); + return; +} + +int add_op(int v1, int v2) { + return v1 + v2; +} + +int sub_op(int v1, int v2) { + return v1 - v2; +} + +int mul_op(int v1, int v2) { + return v1 * v2; +} + +void calc_add(Stack s) { + calc_binop(s, add_op); + return; +} + +void calc_sub(Stack s) { + calc_binop(s, sub_op); + return; +} + +void calc_mul(Stack s) { + calc_binop(s, mul_op); + return; +} + +Calculator new_calculator() { + return new Calculator { add = calc_add; sub = calc_sub; mul = calc_mul }; +} + +/* String manipulation */ +int int_of_string(string s) { + var arr = array_of_string(s); + var len = length_of_string(s); + + var sum = 0; + for(var i = 0; i < len; i = i + 1;) { + sum = sum * 10; + var val = get_val(arr[i]); + sum = sum + val; + } + + return sum; +} + +/* Main program */ +int program (int argc, string[] argv) { + /* A stack-based reverse Polish notation calculator. Feed in input numbers */ + /* and operands + (addition), - (subtraction), and x (multiplication) to */ + /* calculate result. */ + + var str = "\n"; + + var stack = new_stack(); + var calculator = new_calculator(); + + for(var i = 1; i < argc; i = i + 1;) { + var current_item = argv[i]; + + var did_op = false; + + var len = length_of_string(current_item); + if (len == 1) { + var arr = array_of_string(current_item); + did_op = true; + if (arr[0] == 43) { + /* plus op */ + calculator.add(stack); + } else if (arr[0] == 45) { + /* minus op */ + calculator.sub(stack); + } else if (arr[0] == 120) { + /* times op */ + calculator.mul(stack); + } else { + did_op = false; + } + } + + if (!did_op) { + /* didn't do op! we have a number maybe */ + var v = int_of_string(current_item); + push_stack(stack, v); + } + } + + print_int(peek_stack(stack)); + return peek_stack(stack); +} diff --git a/hw5/hw5programs/yingjiao_floydwarshall.oat b/hw5/hw5programs/yingjiao_floydwarshall.oat new file mode 100644 index 0000000..dd78806 --- /dev/null +++ b/hw5/hw5programs/yingjiao_floydwarshall.oat @@ -0,0 +1,102 @@ +struct Edge { + int weight; + int source; + int target; + Edge next; + bool hasNext +} + +int min(int x, int y) { + if (x < y) { + return x; + } else { + return y; + } +} + +int maximum(int x, int y) { + if (x < y | x == 5000) { + return y; + } else { + return x; + } +} + +int program(int argc, string[] argv) { + var n = 10; + var arr = new int[][10]; + + for (var i = 0; i < 10; i = i + 1;) { + arr[i] = new int[10]; + for (var j = 0; j < 10; j = j + 1;) { + if (i == j) { + arr[i][j] = 0; + } else { + arr[i][j] = 5000; + } + } + } + + var e0 = new Edge {weight = 4; source = 1; target = 2; next = Edge null; hasNext = false}; + var e1 = new Edge {weight = 3; source = 2; target = 0; next = e0; hasNext = true}; + var e2 = new Edge {weight = 4; source = 8; target = 5; next = e1; hasNext = true}; + var e3 = new Edge {weight = 1; source = 5; target = 7; next = e2; hasNext = true}; + var e4 = new Edge {weight = 2; source = 3; target = 1; next = e3; hasNext = true}; + var e5 = new Edge {weight = 3; source = 5; target = 4; next = e4; hasNext = true}; + var e6 = new Edge {weight = 7; source = 2; target = 1; next = e5; hasNext = true}; + var e7 = new Edge {weight = 5; source = 3; target = 8; next = e6; hasNext = true}; + var e8 = new Edge {weight = 8; source = 9; target = 4; next = e7; hasNext = true}; + var e9 = new Edge {weight = 3; source = 2; target = 7; next = e8; hasNext = true}; + var e10 = new Edge {weight = 3; source = 0; target = 2; next = e9; hasNext = true}; + var e11 = new Edge {weight = 0; source = 0; target = 3; next = e10; hasNext = true}; + var e12 = new Edge {weight = 4; source = 3; target = 2; next = e11; hasNext = true}; + var e13 = new Edge {weight = 2; source = 1; target = 8; next = e12; hasNext = true}; + var e14 = new Edge {weight = 7; source = 5; target = 1; next = e13; hasNext = true}; + + + var e = e14; + while(e.hasNext) { + arr[e.source][e.target] = e.weight; + e = e.next; + } + arr[e.source][e.target] = e.weight; + + /* + arr[1][2] = 4; + arr[2][0] = 3; + arr[8][5] = 4; + arr[5][7] = 1; + arr[3][1] = 2; + arr[5][4] = 3; + arr[2][1] = 7; + arr[3][8] = 5; + arr[9][4] = 8; + arr[2][7] = 3; + arr[0][2] = 3; + arr[0][3] = 0; + arr[3][2] = 4; + arr[1][8] = 2; + arr[5][1] = 7; + */ + + + for (var k = 0; k < n; k = k + 1;) { + for (var i = 0; i < n; i = i + 1;) { + for (var j = 0; j < n; j = j + 1;) { + arr[i][j] = min(arr[i][k] + arr[k][j], arr[i][j]); + } + } + } + + + var max = 0; + for (var i = 0; i < 10; i = i + 1;) { + for (var j = 0; j < 10; j = j + 1;) { + max = maximum(arr[i][j], max); + } + } + + return max; +} + + diff --git a/hw5/lexer.mll b/hw5/lexer.mll new file mode 100644 index 0000000..252617e --- /dev/null +++ b/hw5/lexer.mll @@ -0,0 +1,227 @@ +{ + open Lexing + open Parser + open Range + + exception Lexer_error of Range.t * string + + let reset_lexbuf (filename:string) (lnum:int) lexbuf : unit = + lexbuf.lex_curr_p <- { + pos_fname = filename; + pos_cnum = 0; + pos_bol = 0; + pos_lnum = lnum; + } + + let newline lexbuf = + lexbuf.lex_curr_p <- { (lexeme_end_p lexbuf) with + pos_lnum = (lexeme_end_p lexbuf).pos_lnum + 1; + pos_bol = (lexeme_end lexbuf) } + + (* Boilerplate to define exceptional cases in the lexer. *) + let unexpected_char lexbuf (c:char) : 'a = + raise (Lexer_error (Range.lex_range lexbuf, + Printf.sprintf "Unexpected character: '%c'" c)) + + (* Lexing reserved words *) + let reserved_words = [ + (* Keywords *) + ("struct", STRUCT); + ("null", NULL); + ("void", TVOID); + ("int", TINT); + ("string", TSTRING); + ("else", ELSE); + ("if", IF); + ("if?", IFQ); + ("while", WHILE); + ("return", RETURN); + ("var", VAR); + ("global", GLOBAL); + ("length", LENGTH); + + (* Symbols *) + ( ".", DOT); + ( ";", SEMI); + ( ",", COMMA); + ( "{", LBRACE); + ( "}", RBRACE); + ( "+", PLUS); + ( "-", DASH); + ( "*", STAR); + ( "=", EQ); + ( "==", EQEQ); + ( "!", BANG); + ( "~", TILDE); + ( "(", LPAREN); + ( ")", RPAREN); + ( "[", LBRACKET); + ( "]", RBRACKET); + ("for", FOR); + ("new", NEW); + ("true", TRUE); + ("false", FALSE); + ("bool", TBOOL); + ( "<<", LTLT); + ( ">>", GTGT); + ( ">>>", GTGTGT); + ( "!=", BANGEQ); + ( "<", LT); + ( "<=", LTEQ); + ( ">", GT); + ( ">=", GTEQ); + ( "&", AMPER); + ( "|", BAR); + ( "[&]", IAND); + ( "[|]", IOR); + ( "->", ARROW); + ( "?", QUESTION); + ] + +let (symbol_table : (string, Parser.token) Hashtbl.t) = Hashtbl.create 1024 + let _ = + List.iter (fun (str,t) -> Hashtbl.add symbol_table str t) reserved_words + + let create_token lexbuf = + let str = lexeme lexbuf in + try (Hashtbl.find symbol_table str) + with _ -> IDENT str + + let create_uident lexbuf = UIDENT (lexeme lexbuf) + + (* Lexing comments and strings *) + let string_buffer = ref (Bytes.create 2048) + let string_end = ref 0 + let start_lex = ref (Range.start_of_range Range.norange) + + let start_pos_of_lexbuf lexbuf : pos = + (Range.pos_of_lexpos (lexeme_start_p lexbuf)) + + let lex_long_range lexbuf : Range.t = + let end_p = lexeme_end_p lexbuf in + mk_range end_p.pos_fname (!start_lex) (pos_of_lexpos end_p) + + let reset_str () = string_end := 0 + + let add_str ch = + let x = !string_end in + let buffer = !string_buffer + in + if x = Bytes.length buffer then + begin + let new_buffer = Bytes.create (x*2) in + Bytes.blit buffer 0 new_buffer 0 x; + Bytes.set new_buffer x ch; + string_buffer := new_buffer; + string_end := x+1 + end + else + begin + Bytes.set buffer x ch; + string_end := x+1 + end + + let get_str () = Bytes.sub_string (!string_buffer) 0 (!string_end) + + (* Lexing directives *) + let lnum = ref 1 +} + +(* Declare your aliases (let foo = regex) and rules here. *) +let newline = '\n' | ('\r' '\n') | '\r' +let lowercase = ['a'-'z'] +let uppercase = ['A'-'Z'] +let character = uppercase | lowercase +let whitespace = ['\t' ' '] +let digit = ['0'-'9'] +let hexdigit = ['0'-'9'] | ['a'-'f'] | ['A'-'F'] + +rule token = parse + | eof { EOF } + + | "/*" { start_lex := start_pos_of_lexbuf lexbuf; comments 0 lexbuf } + | '"' { reset_str(); start_lex := start_pos_of_lexbuf lexbuf; string false lexbuf } + | '#' { let p = lexeme_start_p lexbuf in + if p.pos_cnum - p.pos_bol = 0 then directive 0 lexbuf + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "# can only be the 1st char in a line.")) } + + | lowercase (digit | character | '_')* { create_token lexbuf } + | uppercase (digit | character | '_')* { create_uident lexbuf } + | digit+ | "0x" hexdigit+ { INT (Int64.of_string (lexeme lexbuf)) } + | whitespace+ { token lexbuf } + | newline { newline lexbuf; token lexbuf } + + | ';' | ',' | '{' | '}' | '+' | '-' | '*' | '=' | "==" + | "!=" | '!' | '~' | '(' | ')' | '[' | ']' + | '<' | "<=" | '>' | ">=" | "=>" | '&' | '|' | '.' | "->" + | "[|]" | "[&]" | "<<" | ">>" | ">>>" | "?" | "if?" + { create_token lexbuf } + + | _ as c { unexpected_char lexbuf c } + +and directive state = parse + | whitespace+ { directive state lexbuf } + | digit+ { if state = 0 then + (lnum := int_of_string (lexeme lexbuf); + directive 1 lexbuf) + else if state = 2 then directive 3 lexbuf + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + | '"' { if state = 1 then + begin + reset_str(); + start_lex := start_pos_of_lexbuf lexbuf; + string true lexbuf + end + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) + } + | newline { if state = 2 || state = 3 then + begin + reset_lexbuf (get_str()) !lnum lexbuf; + token lexbuf + end + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + | _ { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + +and comments level = parse + | "*/" { if level = 0 then token lexbuf + else comments (level-1) lexbuf } + | "/*" { comments (level+1) lexbuf} + | [^ '\n'] { comments level lexbuf } + | "\n" { newline lexbuf; comments level lexbuf } + | eof { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "comments are not closed")) } + +and string in_directive = parse + | '"' { if in_directive = false then + STRING (get_str()) + else directive 2 lexbuf } + | '\\' { add_str(escaped lexbuf); string in_directive lexbuf } + | '\n' { add_str '\n'; newline lexbuf; string in_directive lexbuf } + | eof { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "String is not terminated")) } + | _ { add_str (Lexing.lexeme_char lexbuf 0); string in_directive lexbuf } + +and escaped = parse + | 'n' { '\n' } + | 't' { '\t' } + | '\\' { '\\' } + | '"' { '\034' } + | '\'' { '\'' } + | ['0'-'9']['0'-'9']['0'-'9'] + { + let x = int_of_string(lexeme lexbuf) in + if x > 255 then + raise (Lexer_error (lex_long_range lexbuf, + (Printf.sprintf "%s is an illegal escaped character constant" (lexeme lexbuf)))) + else + Char.chr x + } + | [^ '"' '\\' 't' 'n' '\''] + { raise (Lexer_error (lex_long_range lexbuf, + (Printf.sprintf "%s is an illegal escaped character constant" (lexeme lexbuf) ))) } + diff --git a/hw5/ll/ll.ml b/hw5/ll/ll.ml new file mode 100644 index 0000000..9cd2ff8 --- /dev/null +++ b/hw5/ll/ll.ml @@ -0,0 +1,98 @@ +(* LLVMlite: A simplified subset of LLVM IR *) + +(* Local identifiers *) +type uid = string + +(* Global identifiers *) +type gid = string + +(* Named types *) +type tid = string + +(* Labels *) +type lbl = string + +(* LLVM types *) +type ty = +| Void +| I1 +| I8 +| I64 +| Ptr of ty +| Struct of ty list +| Array of int * ty +| Fun of ty list * ty +| Namedt of tid + +(* Function type: argument types and return type *) +type fty = ty list * ty + +(* Syntactic Values *) +type operand = +| Null +| Const of int64 +| Gid of gid +| Id of uid + +(* Binary i64 Operations *) +type bop = +| Add +| Sub +| Mul +| Shl +| Lshr +| Ashr +| And +| Or +| Xor + +(* Comparison Operators *) +type cnd = +| Eq +| Ne +| Slt +| Sle +| Sgt +| Sge + +(* Instructions *) +type insn = +| Binop of bop * ty * operand * operand +| Alloca of ty +| Load of ty * operand +| Store of ty * operand * operand +| Icmp of cnd * ty * operand * operand +| Call of ty * operand * (ty * operand) list +| Bitcast of ty * operand * ty +| Gep of ty * operand * operand list + +type terminator = +| Ret of ty * operand option +| Br of lbl +| Cbr of operand * lbl * lbl + +(* Basic Blocks *) +type block = { insns : (uid * insn) list; term : (uid * terminator) } + +(* Control Flow Graphs: entry and labeled blocks *) +type cfg = block * (lbl * block) list + +(* Function Declarations *) +type fdecl = { f_ty : fty; f_param : uid list; f_cfg : cfg } + +(* Global Data Initializers *) +type ginit = +| GNull +| GGid of gid +| GInt of int64 +| GString of string +| GArray of (ty * ginit) list +| GStruct of (ty * ginit) list +| GBitcast of ty * ginit * ty + +(* Global Declarations *) +type gdecl = ty * ginit + +(* LLVMlite Programs *) +type prog = { tdecls : (tid * ty) list; gdecls : (gid * gdecl) list; + fdecls : (gid * fdecl) list; edecls : (gid * ty) list } diff --git a/hw5/ll/lllexer.mll b/hw5/ll/lllexer.mll new file mode 100644 index 0000000..2fbacba --- /dev/null +++ b/hw5/ll/lllexer.mll @@ -0,0 +1,83 @@ +{ open Lexing + open Llparser + + exception SyntaxError of string +} + +let newline = '\n' | ('\r' '\n') | '\r' +let whitespace = ['\t' ' '] +let lowercase = ['a'-'z'] +let uppercase = ['A'-'Z'] +let character = lowercase | uppercase +let digit = '-'? ['0'-'9'] +let identifier = (character | digit | '_' ) (character | digit | '_' | '.')* + +rule token = parse + | eof { EOF } + | whitespace+ { token lexbuf } + | newline+ { token lexbuf } + | "c\"" { read_string (Buffer.create 17) lexbuf } + | '*' { STAR } + | ',' { COMMA } + | ':' { COLON } + | '=' { EQUALS } + | '(' { LPAREN } + | ')' { RPAREN } + | '{' { LBRACE } + | '}' { RBRACE } + | '[' { LBRACKET } + | ']' { RBRACKET } + | "i1" { I1 } + | "i8" { I8 } + | "i32" { I32 } + | "i64" { I64 } + | "to" { TO } + | "br" { BR } + | "eq" { EQ } + | "ne" { NE } + | "or" { OR } + | "and" { AND } + | "add" { ADD } + | "sub" { SUB } + | "mul" { MUL } + | "xor" { XOR } + | "slt" { SLT } + | "sle" { SLE } + | "sgt" { SGT } + | "sge" { SGE } + | "shl" { SHL } + | "ret" { RET } + | "getelementptr" { GEP } + | "type" { TYPE } + | "null" { NULL } + | "lshr" { LSHR } + | "ashr" { ASHR } + | "call" { CALL } + | "icmp" { ICMP } + | "void" { VOID } + | "load" { LOAD } + | "entry" { ENTRY } + | "store" { STORE } + | "label" { LABEL } + | "global" { GLOBAL } + | "define" { DEFINE } + | "declare" { DECLARE } + | "external" { EXTERNAL } + | "alloca" { ALLOCA } + | "bitcast" { BITCAST } + | '%' ('.' ?) (identifier as i) { UID i } + | '@' ('.' ?) (identifier as i) { GID i } + | "x" { CROSS } (* for Array types *) + | digit+ as d { INT (int_of_string d) } + | identifier as i { LBL i } + | ";" ([^ '\n' '\r'])* newline { token lexbuf } (* comments *) + | "declare" ([^ '\n' '\r'])* newline { token lexbuf } (* declare acts as a comment for our IR *) + | _ as c { raise @@ SyntaxError ("Unexpected character: " ^ Char.escaped c) } + +and read_string buf = parse + | '\\' "00" '"' { STRING (Buffer.contents buf) } + | '\\' { Buffer.add_char buf '\\'; read_string buf lexbuf } + | [^ '"' '\\']+ { Buffer.add_string buf (Lexing.lexeme lexbuf) + ; read_string buf lexbuf } + | _ { raise (SyntaxError ("Illegal string character: " ^ Lexing.lexeme lexbuf)) } + | eof { raise (SyntaxError ("String is not terminated")) } diff --git a/hw5/ll/llparser.mly b/hw5/ll/llparser.mly new file mode 100644 index 0000000..ca28340 --- /dev/null +++ b/hw5/ll/llparser.mly @@ -0,0 +1,298 @@ +%{ open Ll + open Llutil.Parsing + +%} + +(* Symbols *) +%token STAR (* * *) +%token COMMA (* , *) +%token COLON (* : *) +%token EQUALS (* = *) +%token LPAREN (* ( *) +%token RPAREN (* ) *) +%token LBRACE (* { *) +%token RBRACE (* } *) +%token LBRACKET (* [ *) +%token RBRACKET (* ] *) +%token EOF + +(* Reserved Words *) +%token CROSS (* x *) +%token I1 (* i1 *) +%token I8 (* i8 *) +%token I32 (* i32 *) +%token I64 (* i64 *) +%token TO (* to *) +%token BR (* br *) +%token EQ (* eq *) +%token NE (* ne *) +%token OR (* or *) +%token AND (* and *) +%token ADD (* add *) +%token SUB (* sub *) +%token MUL (* mul *) +%token XOR (* xor *) +%token SLT (* slt *) +%token SLE (* sle *) +%token SGT (* sgt *) +%token SGE (* sge *) +%token SHL (* shl *) +%token RET (* ret *) +%token TYPE (* type *) +%token NULL (* null *) +%token LSHR (* lshr *) +%token ASHR (* ashr *) +%token CALL (* call *) +%token ICMP (* icmp *) +%token VOID (* void *) +%token LOAD (* load *) +%token STORE (* store *) +%token LABEL (* label *) +%token ENTRY (* entry *) +%token GLOBAL (* global *) +%token DEFINE (* define *) +%token DECLARE (* define *) +%token EXTERNAL (* external *) +%token ALLOCA (* alloca *) +%token BITCAST (* bitcast *) +%token GEP (* getelementptr *) + +%token INT (* int64 values *) +%token LBL (* labels *) +%token GID (* global identifier *) +%token UID (* local identifier *) +%token STRING (* string literals *) + +%start prog +%% + +prog: + | ds=decls EOF + { ds } + +decls: + | ds = decls_rev + { { tdecls = List.rev ds.tdecls + ; gdecls = List.rev ds.gdecls + ; fdecls = List.rev ds.fdecls + ; edecls = List.rev ds.edecls + } } + +decls_rev: + | (* empty *) + { { tdecls = [] ; gdecls = [] ; fdecls = [] ; edecls = [] } } + | ds=decls_rev f=fdecl + { { ds with fdecls = f :: ds.fdecls } } + | ds=decls_rev g=gdecl + { { ds with gdecls = g :: ds.gdecls } } + | ds=decls_rev t=tdecl + { { ds with tdecls = t :: ds.tdecls } } + | ds=decls_rev e=edecl + { { ds with edecls = e :: ds.edecls } } + +fdecl: + | DEFINE t=ty l=GID LPAREN a=arg_list RPAREN + LBRACE eb=entry_block bs=block_list RBRACE + { (l, { f_ty = (List.map fst a, t) + ; f_param = List.map snd a + ; f_cfg = (eb, bs) + } + ) } + +gdecl: + | g=GID EQUALS GLOBAL t=ty gi=ginit + { (g, (t,gi)) } + +tdecl: + | tid=UID EQUALS TYPE t=ty + { (tid, t) } + +edecl: + | DECLARE rt=ty g=GID LPAREN ts=separated_list(COMMA, ty) RPAREN + { (g, Fun (ts,rt)) } + | g=GID EQUALS EXTERNAL GLOBAL t=ty + { (g, t) } + +nonptr_ty: + | VOID { Void } + | I1 { I1 } + | I8 { I8 } + | I64 { I64 } + | LBRACE ts=ty_list RBRACE + { Struct ts } + | LBRACKET i=INT CROSS t=ty RBRACKET + { Array (i,t) } + | rt=ty LPAREN ts=ty_list RPAREN + { Fun (ts, rt) } + | t=UID + { Namedt t } + +ty: + | t=ty STAR + { Ptr t } + | t=nonptr_ty + { t } + +ty_list_rev: + | t=ty + { [t] } + | ts=ty_list_rev COMMA t=ty + { t::ts } + +ty_list: + | ts=ty_list_rev + { List.rev ts } + +arg: + | t=ty u=UID { (t,u) } + +arg_list_rev: + | (* empty *) + { [] } + | a=arg + { [a] } + | args=arg_list_rev COMMA a=arg + { a::args } + +arg_list: + | a=arg_list_rev + { List.rev a } + +operand: + | NULL + { Null } + | i=INT + { Const (Int64.of_int i) } + | g=GID + { Gid g } + | u=UID + { Id u } + +ty_operand_list_rev: + | (* empty *) + { [] } + | t=ty o=operand + { [(t,o)] } + | tos=ty_operand_list_rev COMMA t=ty o=operand + { (t,o)::tos } + +ty_operand_list: + | tos=ty_operand_list_rev + { List.rev tos } + +i_operand_list_rev: + | (* empty *) + { [] } + | I64 o=operand + { [o] } + | I32 o=operand + { [o] } + | os=i_operand_list_rev COMMA I64 o=operand + { o::os } + | os=i_operand_list_rev COMMA I32 o=operand + { o::os } + +i_operand_list: + | os=i_operand_list_rev + { List.rev os } + +terminator: + | RET t=ty o=operand + { Ret (t, Some o) } + | RET t=ty + { Ret (t, None) } + | BR LABEL l=UID + { Br l } + | BR I1 o=operand COMMA LABEL l1=UID COMMA LABEL l2=UID + { Cbr (o,l1,l2) } + +block: + | is=insn_list t=terminator + { { insns = is; term=(gensym "tmn", t) } } + +block_list_rev: + | (* empty *) + { [] } + | bs=block_list_rev l=LBL COLON b=block + { (l,b) :: bs } + +block_list: + | bs=block_list_rev + { List.rev bs } + +entry_block: + | ENTRY COLON b=block + { b } + | b=block + { b } + +bop: + | OR { Or } + | ADD { Add } + | SUB { Sub } + | MUL { Mul } + | SHL { Shl } + | XOR { Xor } + | AND { And } + | LSHR { Lshr } + | ASHR { Ashr } + +cnd: + | EQ { Eq } + | NE { Ne } + | SLT { Slt } + | SLE { Sle } + | SGT { Sgt } + | SGE { Sge } + +insn: + | u=UID EQUALS b=bop t=ty o1=operand COMMA o2=operand + { (u, Binop (b,t,o1,o2)) } + | u=UID EQUALS ALLOCA t=ty + { (u, Alloca t) } + | u=UID EQUALS LOAD ty COMMA t=ty o=operand + { (u, Load (t,o)) } + | STORE t1=ty o1=operand COMMA t2=ty o2=operand + { (gensym "store", Store (t1,o1,o2)) } + | u=UID EQUALS ICMP c=cnd t=ty o1=operand COMMA o2=operand + { (u, Icmp (c,t,o1,o2)) } + | CALL t=ty o=operand LPAREN args=ty_operand_list RPAREN + { (gensym "call", Call (t, o, args)) } + | u=UID EQUALS CALL t=ty o=operand LPAREN args=ty_operand_list RPAREN + { (u, Call (t, o, args)) } + | u=UID EQUALS BITCAST t1=ty o=operand TO t2=ty + { (u, Bitcast (t1,o,t2)) } + | u=UID EQUALS GEP ty COMMA t=ty o=operand COMMA os=i_operand_list + { (u, Gep (t,o,os)) } + +insn_list: + | is=list(insn) + { is } + +gdecl_list_rev: + | (* empty *) + { [] } + | t=ty g=ginit + { [(t,g)] } + | gs=gdecl_list_rev COMMA t=ty g=ginit + { (t,g)::gs } + +gdecl_list: + | gs=gdecl_list_rev + { List.rev gs } + +ginit: + | NULL + { GNull } + | g=GID + { GGid g } + | i=INT + { GInt (Int64.of_int i) } + | s=STRING + { GString s } + | LBRACKET gs=gdecl_list RBRACKET + { GArray gs } + | LBRACE gs=gdecl_list RBRACE + { GStruct gs } + | BITCAST LPAREN t1=ty g=ginit TO t2=ty RPAREN + { GBitcast (t1, g, t2) } diff --git a/hw5/ll/llruntime.c b/hw5/ll/llruntime.c new file mode 100644 index 0000000..895fe36 --- /dev/null +++ b/hw5/ll/llruntime.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +/* TODO: if we enforce that all char literals are null-terminated, + and all allocated memory is zero-initialized, are these safe + when llvmlite program does not exhibit UB? */ + +void *ll_malloc(int64_t n, int64_t size) { + return calloc(n, size); +} + +int64_t ll_strlen(int8_t *s) { + return 0; +} + +int8_t *ll_strncopy(int8_t *dst, int8_t *src, int64_t i) { + int64_t src_size = ll_strlen(src); + int64_t dst_size = ll_strlen(dst); + if (i >= dst_size) + return dst; + else + return (int8_t*)strncpy((char *)dst + i, (char *)src, dst_size - i); +} + +void ll_puts(int8_t *s) { + puts((char *)s); +} + +int64_t ll_atol(int8_t *s) { + return atol((char *)s); +} + +int64_t ll_ltoa(int64_t i, int8_t *dst) { + int64_t size = ll_strlen(dst); + return snprintf((char *)dst, size, "%ld", (long)i); +} diff --git a/hw5/ll/llutil.ml b/hw5/ll/llutil.ml new file mode 100644 index 0000000..044d536 --- /dev/null +++ b/hw5/ll/llutil.ml @@ -0,0 +1,170 @@ +;; open Ll + +(* serializing --------------------------------------------------------------- *) + +let mapcat s f l = String.concat s @@ List.map f l +let prefix p f a = p ^ f a +let ( ^. ) s t = if s = "" || t = "" then "" else s ^ t +let pp = Printf.sprintf + +let rec string_of_ty : ty -> string = function + | Void -> "void" + | I1 -> "i1" + | I8 -> "i8" + | I64 -> "i64" + | Ptr ty -> pp "%s*" (string_of_ty ty) + | Struct ts -> pp "{ %s }" (mapcat ", " string_of_ty ts) + | Array (n, t) -> pp "[%s x %s]" (string_of_int n) (string_of_ty t) + | Fun (ts,t) -> pp "%s (%s)" (string_of_ty t) (mapcat ", " string_of_ty ts) + | Namedt s -> pp "%%%s" s + +let sot = string_of_ty + +let dptr = function + | Ptr t -> t + | _ -> failwith "PP: expected pointer type" + +let string_of_operand : operand -> string = function + | Null -> "null" + | Const i -> Int64.to_string i + | Gid g -> "@" ^ g + | Id u -> "%" ^ u + +let soo = string_of_operand + +let soop (t,v:ty * operand) : string = + pp "%s %s" (sot t) (soo v) + +let string_of_bop : bop -> string = function + | Add -> "add" | Sub -> "sub" | Mul -> "mul" + | Shl -> "shl" | Lshr -> "lshr" | Ashr -> "ashr" + | And -> "and" | Or -> "or" | Xor -> "xor" + +let string_of_cnd : cnd -> string = function + | Eq -> "eq" | Ne -> "ne" | Slt -> "slt" + | Sle -> "sle" | Sgt -> "sgt" | Sge -> "sge" + +let string_of_gep_index : operand -> string = function + | Const i -> "i32 " ^ Int64.to_string i + | o -> "i64 " ^ soo o + +let string_of_insn : insn -> string = function + | Binop (b, t, o1, o2) -> pp "%s %s %s, %s" + (string_of_bop b) (sot t) (soo o1) (soo o2) + | Alloca t -> pp "alloca %s" (sot t) + | Load (t, o) -> pp "load %s, %s %s" (sot (dptr t)) (sot t) (soo o) + | Store (t, os, od) -> pp "store %s %s, %s %s" + (sot t) (soo os) (sot (Ptr t)) (soo od) + | Icmp (c, t, o1, o2) -> pp "icmp %s %s %s, %s" + (string_of_cnd c) (sot t) (soo o1) (soo o2) + | Call (t, o, oa) -> pp "call %s %s(%s)" + (sot t) (soo o) (mapcat ", " soop oa) + | Bitcast (t1, o, t2) -> pp "bitcast %s %s to %s" (sot t1) (soo o) (sot t2) + | Gep (t, o, oi) -> pp "getelementptr %s, %s %s, %s" (sot (dptr t)) (sot t) (soo o) + (mapcat ", " string_of_gep_index oi) + +let string_of_named_insn (u,i:uid * insn) : string = + match i with + | Store _ | Call (Void, _, _) -> string_of_insn i + | _ -> pp "%%%s = %s" u (string_of_insn i) + +let string_of_terminator : terminator -> string = function + | Ret (_, None) -> "ret void" + | Ret (t, Some o) -> pp "ret %s %s" (sot t) (soo o) + | Br l -> pp "br label %%%s" l + | Cbr (o, l, m) -> pp "br i1 %s, label %%%s, label %%%s" (soo o) l m + +let string_of_block (b:block) : string = + (mapcat "\n" (prefix " " string_of_named_insn) b.insns ^. "\n") + ^ (prefix " " string_of_terminator) (snd b.term) + +let string_of_cfg (e,bs:cfg) : string = + let string_of_named_block (l,b) = l ^ ":\n" ^ string_of_block b in + string_of_block e ^ "\n" ^. mapcat "\n" string_of_named_block bs + +let string_of_named_fdecl (g,f:gid * fdecl) : string = + let string_of_arg (t,u) = pp "%s %%%s" (sot t) u in + let ts, t = f.f_ty in + pp "define %s @%s(%s) {\n%s\n}\n" (sot t) g + (mapcat ", " string_of_arg List.(combine ts f.f_param)) + (string_of_cfg f.f_cfg) + +let rec string_of_ginit : ginit -> string = function + | GNull -> "null" + | GGid g -> pp "@%s" g + | GInt i -> Int64.to_string i + | GString s -> pp "c\"%s\\00\"" s + | GArray gis -> pp "[ %s ]" (mapcat ", " string_of_gdecl gis) + | GStruct gis -> pp "{ %s }" (mapcat ", " string_of_gdecl gis) + | GBitcast (t1,g,t2) -> pp "bitcast (%s %s to %s)" (sot t1) (string_of_ginit g) (sot t2) + +and string_of_gdecl (t,gi:gdecl) : string = + pp "%s %s" (sot t) (string_of_ginit gi) + +let string_of_named_gdecl (g,gd:gid * gdecl) : string = + pp "@%s = global %s" g (string_of_gdecl gd) + +let string_of_named_tdecl (n,t:tid * ty) : string = + pp "%%%s = type %s" n (sot t) + +let string_of_named_edecl (g,t:gid * ty) : string = + match t with + | Fun (ts, rt) -> pp "declare %s @%s(%s)" (string_of_ty rt) g + (mapcat ", " string_of_ty ts) + | _ -> pp "@%s = external global %s" g (string_of_ty t) + +let string_of_prog (p:prog) : string = + (mapcat "\n" string_of_named_tdecl p.tdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_gdecl p.gdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_fdecl p.fdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_edecl p.edecls) + +(* comparison for testing ----------------------------------------------------- *) + +(* delete dummy uids before comparison *) +let compare_block (b:block) (c:block) : int = + let del_dummy (u,i) = + match i with + | Store (_, _, _) -> "", i + | Call (Void, _, _) -> "", i + | _ -> u, i + in + let del_term (u,t) = ("", t) + in + Stdlib.compare + {insns=List.map del_dummy b.insns; term=del_term b.term} + {insns=List.map del_dummy c.insns; term=del_term c.term} + + + +(* helper module for AST ------------------------------------------------------ *) + +module IR = struct + let define t gid args f_cfg = + let ats, f_param = List.split args in + gid, { f_ty=ats,t; f_param; f_cfg} + + (* ignore first label *) + let cfg (lbs:(lbl * block) list) : cfg = + match lbs with + | [] -> failwith "cfg: no blocks!" + | (_,b)::lbs -> b, lbs + + let entry insns term : (lbl * block) = "", { insns; term } + let label lbl insns term = lbl, { insns; term } + + (* terminators *) + let ret_void = Ret (Void, None) + let ret t op = Ret (t, Some op) + let br l = Br l + let cbr op l1 l2 = Cbr (op, l1, l2) +end + +module Parsing = struct + +let gensym, reset = + let c = ref 0 in + ( fun (s:string) -> incr c; Printf.sprintf "_%s__%d" s (!c) ) + , ( fun () -> c := 0 ) + +end diff --git a/hw5/main.ml b/hw5/main.ml new file mode 100644 index 0000000..70daaa6 --- /dev/null +++ b/hw5/main.ml @@ -0,0 +1,43 @@ +open Ll +open Arg +open Assert +open Driver + +exception Ran_tests +let suite = ref (Studenttests.provided_tests @ Gradedtests.graded_tests) + +let execute_tests () = + Platform.configure_os (); + let outcome = run_suite !suite in + Printf.printf "%s\n" (outcome_to_string outcome); + raise Ran_tests + +let args = + [ ("-linux", Set Platform.linux, "use linux-style name mangling [must precede --test on linux]") + ; ("--test", Unit execute_tests, "run the test suite, ignoring other files inputs") + ; ("-op", Set_string Platform.output_path, "set the path to the output files directory [default='output']") + ; ("-o", Set_string executable_filename, "set the name of the resulting executable [default='a.out']") + ; ("-S", Clear assemble, "stop after generating .s files; do generate .o files") + ; ("-c", Clear link, "stop after generating .o files; do not generate executables") + ; ("--print-ll", Set print_ll_flag, "prints the program's LL code (after lowering to clang code if --clang-malloc is set)") + ; ("--print-x86", Set print_x86_flag, "prints the program's assembly code") + ; ("--clang", Set clang, "compiles to assembly using clang, not the 341 backend (implies --clang-malloc)") + ; ("--execute-x86", Set execute_x86, "run the resulting executable file") + ; ("-v", Set Platform.verbose, "enables more verbose compilation output") + ] + +let files = ref [] + +let _ = + Platform.configure_os (); + Platform.create_output_dir (); + try + Arg.parse args (fun filename -> files := filename :: !files) + "Compiler Design main test harness\n\ + USAGE: ./main.native [options] \n\ + see README for details about using the compiler"; + Platform.configure_os (); + process_files !files + + with Ran_tests -> + () diff --git a/hw5/oatprograms/arrayargs.oat b/hw5/oatprograms/arrayargs.oat new file mode 100644 index 0000000..ef8be3e --- /dev/null +++ b/hw5/oatprograms/arrayargs.oat @@ -0,0 +1,20 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +int program (int argc, string[] argv) { + var x = new int[3]; + for (var i=0; i<3; i = i+1;) { + x[i] = i; + } + var y = new int[3]; + for (var i=0; i<3; i = i+1;) { + y[i] = i+3; + } + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw5/oatprograms/arrayargs1.oat b/hw5/oatprograms/arrayargs1.oat new file mode 100644 index 0000000..74ec125 --- /dev/null +++ b/hw5/oatprograms/arrayargs1.oat @@ -0,0 +1,16 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +global x = new int[]{1, 2, 3}; +global y = new int[]{4, 5, 6}; + + +int program (int argc, string[] argv) { + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw5/oatprograms/arrayargs2.oat b/hw5/oatprograms/arrayargs2.oat new file mode 100644 index 0000000..64c93f6 --- /dev/null +++ b/hw5/oatprograms/arrayargs2.oat @@ -0,0 +1,14 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +int program (int argc, string[] argv) { + var x = new int[3]{i -> 0}; + var y = new int[3]{i -> 0}; + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw5/oatprograms/arrayargs3.oat b/hw5/oatprograms/arrayargs3.oat new file mode 100644 index 0000000..b4e18a7 --- /dev/null +++ b/hw5/oatprograms/arrayargs3.oat @@ -0,0 +1,17 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +global x = new int[]{1, 2, 3}; +global y = new int[]{4, 5, 6}; + + +int program (int argc, string[] argv) { + f(x, y, true)[0] = 17; /* non-trivial lhs path */ + var z = f(x, y, true)[0] + f(y, x, false)[0]; /* non-trivial expression paths */ + return z; +} diff --git a/hw5/oatprograms/arrayargs4.oat b/hw5/oatprograms/arrayargs4.oat new file mode 100644 index 0000000..3a5cf10 --- /dev/null +++ b/hw5/oatprograms/arrayargs4.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[3]{i -> 0}; + return 0; +} diff --git a/hw5/oatprograms/binary_gcd.oat b/hw5/oatprograms/binary_gcd.oat new file mode 100644 index 0000000..ea13088 --- /dev/null +++ b/hw5/oatprograms/binary_gcd.oat @@ -0,0 +1,26 @@ +int binary_gcd (int x, int y) { + if (x == y) { return x; } + if (x == 0) { return y; } + if (y == 0) { return x; } + if ((~x [&] 1) == 1) { + if ((y [&] 1) == 1) { + return binary_gcd(x >> 1, y); + } + else { + return binary_gcd(x >> 1, y >> 1) << 1; + } + } + if ((~y [&] 1) == 1) { + return binary_gcd(x, y >> 1); + } + if (x > y) { + return binary_gcd((x - y) >> 1, y); + } + return binary_gcd((y - x) >> 1, x); +} + +int program (int argc, string[] argv) { + var x = 21; + var y = 15; + return binary_gcd(x, y); +} diff --git a/hw5/oatprograms/binary_search.oat b/hw5/oatprograms/binary_search.oat new file mode 100644 index 0000000..7ab66db --- /dev/null +++ b/hw5/oatprograms/binary_search.oat @@ -0,0 +1,65 @@ +int euclid_division (int numerator, int denominator) { + if (denominator < 0) + { + return -(euclid_division(numerator, -(denominator))); + } + + var quotient = 0; + var remainder = numerator; + + if (numerator < 0) + { + remainder = -(numerator); + + while (remainder >= denominator) + { + quotient = quotient + 1; + remainder = remainder - denominator; + } + + if ( remainder == 0 ) { return -(quotient); } + else { + return -(quotient) - 1; + } + } + + while (remainder >= denominator) + { + quotient = quotient + 1; + remainder = remainder - denominator; + } + return quotient; +} + +bool binary_search (int[] input, int key, int min, int max) { + if (max < min) { + return false; + } + + var midpt = euclid_division((max + min), 2); + + if (input[midpt] > key) + { + return binary_search(input, key, min, (midpt - 1)); + } + if (input[midpt] < key) + { + return binary_search(input, key, (midpt + 1), max); + } else { + return true; + } +} + +int program (int argc, string[] argv) { + var test_array = new int[100]{i->0}; + for (var i=0; i < 100; i=i+1;) { test_array[i] = 2 * i + 1; } + var even = binary_search (test_array, 80, 0, 99); + var odd = binary_search (test_array, 81, 0, 99); + + if (!(even & odd) & (even | odd)) + { + print_string("Correct!"); + } + + return 0; +} \ No newline at end of file diff --git a/hw5/oatprograms/bsort.oat b/hw5/oatprograms/bsort.oat new file mode 100644 index 0000000..2123e08 --- /dev/null +++ b/hw5/oatprograms/bsort.oat @@ -0,0 +1,41 @@ +void bubble_sort(int[] numbers, int array_size) +{ + var temp=0; + var i = (array_size - 1); + + for (; i > 0; i=i-1;) + { + for (var j = 1; j <= i; j=j+1;) + { + if (numbers[j-1] > numbers[i]) + { + temp = numbers[j-1]; + numbers[j-1] = numbers[i]; + numbers[i] = temp; + } + } + } + + return; +} + +int program (int argc, string[] argv) { + var a = new int[8]{i -> 0}; + + a[0] = 121; + a[1] = 125; + a[2] = 120; + a[3] = 111; + a[4] = 116; + a[5] = 110; + a[6] = 117; + a[7] = 119; + + print_string (string_of_array (a)); + print_string (" "); + bubble_sort (a, 8); + print_string (string_of_array (a)); + + return -1; +} + diff --git a/hw5/oatprograms/bubble_sort.oat b/hw5/oatprograms/bubble_sort.oat new file mode 100644 index 0000000..1843ca8 --- /dev/null +++ b/hw5/oatprograms/bubble_sort.oat @@ -0,0 +1,30 @@ +void bubble_sort(int[] arr, int len) { + var swapped = true; + while(swapped) { + swapped = false; + for (var i = 0; i < len-1; i = i+1;) { + if (arr[i] > arr[i+1]) { + var temp = arr[i]; + arr[i] = arr[i+1]; + arr[i+1] = temp; + swapped = true; + } + } + } + return; +} + +int program (int argc, string[] argv) { + var arr = new int[][10]{i -> new int[10]{j-> 10*i-j}}; + var val = 0; + for (var i = 0; i < 10; i = i+1;) { + bubble_sort(arr[i], 10); + val = val + arr[i][i]; + } + + if (val == 405) { + return 1; + } else { + return 0; + } +} diff --git a/hw5/oatprograms/calculator.oat b/hw5/oatprograms/calculator.oat new file mode 100644 index 0000000..c4152cf --- /dev/null +++ b/hw5/oatprograms/calculator.oat @@ -0,0 +1,149 @@ +int[] new_stack() { + var s = new int[7]; + s[0] = 5; + s[1] = 0; /* current index of stack ptr (offset 2) */ + return s; +} + +int peek_stack(int[] s) { + var index = 1 + s[1]; + return s[index]; +} + +int[] pop_stack(int[] s) { + var cur_index = s[1]; + if(cur_index > 0) { + cur_index = cur_index - 1; + } + + s[1] = cur_index; + return maybe_new_stack(s); +} + +int[] push_stack(int[] s, int v) { + var cur_index = 2 + s[1]; + s[cur_index] = v; + s[1] = cur_index - 1; + + return maybe_new_stack(s); +} + +int[] maybe_new_stack(int[] s) { + /* if index of s > half the size, double the size of s */ + /* if index of s < quarter the size, half the size of s */ + + return s; + + var cur_index = s[1]; + var cur_size = s[0]; + + if(cur_size <= 5) { + /* min size is 5 */ + return s; + } + + if(cur_index > (cur_size << 1)) { + /* double size of s */ + var new_s = new int[2 + cur_size * 2]; + cur_size = cur_size * 2; + new_s[0] = cur_size; + new_s[1] = cur_index; + + /* copy over values */ + for(var i = 0; i <= cur_index; i = i + 1;) { + new_s[2 + i] = s[2 + i]; + } + + return new_s; + } else if(cur_index < ((cur_size << 1) << 1)) { + /* halve s */ + var new_s = new int[2 + cur_size << 1]; + cur_size = cur_size << 1; + new_s[0] = cur_size; + new_s[1] = cur_index; + + /* copy over values */ + for(var i = 0; i <= cur_index; i = i + 1;) { + new_s[2 + i] = s[2 + i]; + } + + return new_s; + } + + return s; +} + +int get_val(int i) { + /* turns a char_code i into a value v */ + return i - 48; +} + +int int_of_string(string s) { + var arr = array_of_string(s); + var len = length_of_string(s); + + var sum = 0; + for(var i = 0; i < len; i = i + 1;) { + sum = sum * 10; + var val = get_val(arr[i]); + sum = sum + val; + } + + return sum; +} + + + +int program (int argc, string[] argv) { + /* a stack based calculator. feed in input numbers and operands + and - */ + /* will calculate result. a reverse polish notation calculator */ + + var str = "\n"; + + var stack = new_stack(); + + for(var i = 1; i < argc; i = i + 1;) { + var current_item = argv[i]; + + var did_op = false; + + var len = length_of_string(current_item); + if(len == 1) { + var arr = array_of_string(current_item); + did_op = true; + if(arr[0] == 43) { + /* plus op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 + x2); + } else if(arr[0] == 45) { + /* minus op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 - x2); + } else if(arr[0] == 120) { + /* times op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 * x2); + } else { + did_op = false; + } + } + + if(!did_op) { + /* didn't do op! we have a number maybe */ + var v = int_of_string(current_item); + stack = push_stack(stack, v); + } + } + + print_int(peek_stack(stack)); + return peek_stack(stack); +} diff --git a/hw5/oatprograms/conquest.oat b/hw5/oatprograms/conquest.oat new file mode 100644 index 0000000..275122d --- /dev/null +++ b/hw5/oatprograms/conquest.oat @@ -0,0 +1,135 @@ +global meaning_of_life = 42; +global kesha_to_fling = true; +global professor = "Zdancewic!"; +global global_arr = new int[]{1, 1, 2, 3, 5, 8, 13}; +global null_arr = int[] null; +global ideal_341_midterm_score = new int[]{100}; +global actual_341_midterm_score = new int[]{0}; + +int four () { + var hakuna_matata = "Meaning of Life"; + var what_is_the = meaning_of_life; + var what_rhymes_with_moore = meaning_of_life - global_arr[5] * global_arr[4] + global_arr[2]; + return 0 + what_rhymes_with_moore; +} + +int[] asian_brother_of_foo_named_fui (string s, bool b, int i) { + var fui = global_arr; + return fui; +} + +void dfs (int[][] arr, int[][] visited, int row, int col, int i, int j) { + if (i - 1 >= 0) { + if (visited[i - 1][j] != 1) { + visited[i - 1][j] = 1; + + if (arr[i - 1][j] == 1) { + dfs(arr, visited, row, col, i - 1, j); + } + } + } + + if (i + 1 < row) { + if (visited[i + 1][j] != 1) { + visited[i + 1][j] = 1; + + if (arr[i + 1][j] == 1) { + dfs(arr, visited, row, col, i + 1, j); + } + } + } + + if (j - 1 >= 0) { + if (visited[i][j - 1] != 1) { + visited[i][j - 1] = 1; + + if (arr[i][j - 1] == 1) { + dfs(arr, visited, row, col, i, j - 1); + } + } + } + + if (j + 1 < col) { + if (visited[i][j + 1] != 1) { + visited[i][j + 1] = 1; + + if (arr[i][j + 1] == 1) { + dfs(arr, visited, row, col, i, j + 1); + } + } + } + + return; +} + +int connected (int[][] arr, int row, int col) { + var visited = new int[][row]{i-> new int[col]{j->0}}; + var counter = 0; + + for (var i = 0; i < row; i = i + 1;) { + var j = 0; + + while (j < col) { + if (visited[i][j] == 0) { + visited[i][j] = 1; + + if (arr[i][j] == 1) { + counter = counter + 1; + + dfs(arr, visited, row, col, i, j); + } + } + + j = j + 1; + } + } + + return counter; +} + +int program (int argc, string[] argv) { + var territory_a = new int[][]{new int[]{1, 0, 1, 0}, + new int[]{1, 1, 0, 1}, + new int[]{1, 0, 1, 1}, + new int[]{0, 1, 1, 0}}; + var territory_b = new int[][]{new int[]{0, 0, 1, 0, 1}, + new int[]{0, 1, 1, 0, 1}, + new int[]{1, 1, 1, 1, 1}}; + var territory_c = new int[][]{new int[]{1, 0, 1}, + new int[]{0, 1, 0}, + new int[]{1, 0, 1}}; + + var none_conquered = new int[][four()]{i-> new int[2]{j->actual_341_midterm_score[0]}}; + + var all_conquered = new int[][6]{i->new int[6]{j -> i*0+1}}; + + var island = new int[][] {new int[]{}}; + var emptyland = new int[][1]{i -> + new int[1]{ j -> + asian_brother_of_foo_named_fui(professor,kesha_to_fling,ideal_341_midterm_score[0])[1] + } + }; + + all_conquered = all_conquered; + var temp = island; + island = emptyland; + emptyland = temp; + + print_string("My name is Jeff...\n"); + + var a = connected(territory_a, 4, 4); + var b = connected(territory_b, 3, 5); + var c = connected(territory_c, 3, 3); + var none = connected(none_conquered, 4, 2); + var all = connected(all_conquered, 6, 6); + var i = connected(island, 1, 1); + var e = connected(emptyland, 0, 0); + + if (a == 3 & b == 1 & c == 5 & none == 0 & all == 1 & i == 1 & e == 0) { + print_string("Charizard is the BEST Pokemon ever!!!"); + } + + var sum = a + b + c + none + all + i + e; + + return sum; +} \ No newline at end of file diff --git a/hw5/oatprograms/count_sort.oat b/hw5/oatprograms/count_sort.oat new file mode 100644 index 0000000..e900df9 --- /dev/null +++ b/hw5/oatprograms/count_sort.oat @@ -0,0 +1,59 @@ + +int min(int[] arr, int len) { + var min = arr[0]; + for (var i = 0; i < len; i = i + 1;) { + if (arr[i] < min) { + min = arr[i]; + } + } + return min; +} + +int max(int[] arr, int len) { + var max = arr[0]; + for (var i = 0; i < len; i = i + 1;) { + if (arr[i] > max) { + max = arr[i]; + } + } + return max; +} + +int[] count_sort(int[] arr, int len) { + var min = min(arr, len); + var max = max(arr, len); + + var counts = new int[max - min + 1]{i->0}; + + for (var i = 0; i < len; i = i + 1;) { + counts[arr[i] - min] = counts[arr[i] - min] + 1; + } + + var i = min; + var j = 0; + + var out = new int[len]{i2->0}; + + while (i <= max) { + + if (counts[i - min] > 0) { + out[j] = i; + counts[i - min] = counts[i - min] - 1; + j = j + 1; + } else { + i = i + 1; + } + } + return out; +} + +int program(int argc, string[] argv) { + var arr = new int[]{65, 70, 72, 90, 65, 65, 69, 89, 67}; + var len = 9; + + print_string(string_of_array(arr)); + print_string("\n"); + var sorted = count_sort(arr, len); + print_string(string_of_array(sorted)); + return 0; +} diff --git a/hw5/oatprograms/determinant_size2.oat b/hw5/oatprograms/determinant_size2.oat new file mode 100644 index 0000000..b6733d9 --- /dev/null +++ b/hw5/oatprograms/determinant_size2.oat @@ -0,0 +1,31 @@ +int compute_determinant(int[][] matrix, int n) { + var sum = 0; + var multiplier = -1; + if (n == 1) { + sum = matrix[0][0]; + } + else { + for (var k = 0; k < n; k = k+1;) { + var len = n-1; + var b=new int[][len]{i-> new int[len]{j -> 1}}; + for (var l = 0; l < k; l=l+1;) { + for (var m = 0; m < n-1; m=m+1;) { + b[m][l] = matrix[m+1][l]; + } + } + for (var o = k; o < n-1; o=o+1;) { + for (var p = 0; p < n-1; p=p+1;) { + b[p][o] = matrix[p+1][o+1]; + } + } + multiplier = multiplier * -1; + sum = sum + multiplier * matrix[0][k] * compute_determinant(b, n-1); + } + } + return sum; +} + +int program (int argc, string[] argv) { + var matrix = new int[][]{new int[]{20,2},new int[]{3,5}}; + return compute_determinant(matrix, 2); +} diff --git a/hw5/oatprograms/easy_p1.oat b/hw5/oatprograms/easy_p1.oat new file mode 100644 index 0000000..3e77270 --- /dev/null +++ b/hw5/oatprograms/easy_p1.oat @@ -0,0 +1,4 @@ +int f ( ) { + return 0 ; +} + diff --git a/hw5/oatprograms/easy_p2.oat b/hw5/oatprograms/easy_p2.oat new file mode 100644 index 0000000..943c398 --- /dev/null +++ b/hw5/oatprograms/easy_p2.oat @@ -0,0 +1,5 @@ +int f ( int x ) { + var x = 0; + x = x + x - x * x >> x << x [|] x [&] -~x >>> x; + return x; +} diff --git a/hw5/oatprograms/easy_p3.oat b/hw5/oatprograms/easy_p3.oat new file mode 100644 index 0000000..6e998bc --- /dev/null +++ b/hw5/oatprograms/easy_p3.oat @@ -0,0 +1,22 @@ +string bar (int x, string y) { + var s = "This is a string"; + var array = new int[]{1, 3}; + var y = array[0]; + return s; +} + +void proc1 () { + proc2 ( ); + return; +} + +void proc2 ( ) { + proc1 ( ); + return; +} + +bool foo ( int x, int[] y ) { + var s = bar (x, "cis341"); + proc1 (); + return true; +} diff --git a/hw5/oatprograms/easy_p4.oat b/hw5/oatprograms/easy_p4.oat new file mode 100644 index 0000000..c9e13e7 --- /dev/null +++ b/hw5/oatprograms/easy_p4.oat @@ -0,0 +1,40 @@ +/* This is a test case: level 0 + + /* level 1 */ + + + /* level 1 + /* level 2 */ + */ + + "This is a commented string." +*/ + +string f ( ) { + var s = + new string[][] + { + new string []{ + "s00:\n+\n=2*\n", + "s01:this is not a comment in string.*", + "s02:\"\\t\\n\\\\?\"" + }, + new string[]{ + "s10:\133\134", + "s11", + "s12" + } + }; + + return s[0][1]; +} + +int[][] g (int [][] x) { + var y = new int[][]{ new int[]{0, 1}, new int[]{2, 3} }; + var i = 0; + + x[0][0] = i + y[1][1]; /* + g(x)[1][0]; */ + i = -!~x[0][0] ; /* comments */ + + return x; +} diff --git a/hw5/oatprograms/easy_p5.oat b/hw5/oatprograms/easy_p5.oat new file mode 100644 index 0000000..1c9abf6 --- /dev/null +++ b/hw5/oatprograms/easy_p5.oat @@ -0,0 +1,14 @@ +global i = 19; +global b1 = true; +global b2 = false; +global str = "This is a string!"; +global arr1 = int[]{0,1,2}; +global arr2 = int[][]{ int[]{10,11}, int[]{20,21}, int[]{30,31}}; +global arr3 = string[]{"String1", "String2", "String3"}; + +global arr4 = string[][] + { + string[]{"String00","String01"}, + string[]{"String10","String11"}, + string[]{"String20","String21"} + }; diff --git a/hw5/oatprograms/easy_p6.oat b/hw5/oatprograms/easy_p6.oat new file mode 100644 index 0000000..b16eb74 --- /dev/null +++ b/hw5/oatprograms/easy_p6.oat @@ -0,0 +1,12 @@ +global y = 0; +global z = 0; + +void f (int x, int y) { + var x = 0; + return; +} + +void g (int x, int y) { + var z = 0; + return; +} diff --git a/hw5/oatprograms/easy_p7.oat b/hw5/oatprograms/easy_p7.oat new file mode 100644 index 0000000..ed330b1 --- /dev/null +++ b/hw5/oatprograms/easy_p7.oat @@ -0,0 +1,8 @@ +global j = int[]{1,2,3,4}; +int[] f () { + var a = new int[][]{1, 2}; + var i = new int[4]; + var arr1 = new int[3]; + var arr2 = new int[][3]; + return new int[2]; +} diff --git a/hw5/oatprograms/easyrun1.oat b/hw5/oatprograms/easyrun1.oat new file mode 100644 index 0000000..32327bc --- /dev/null +++ b/hw5/oatprograms/easyrun1.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 17; +} diff --git a/hw5/oatprograms/easyrun10.oat b/hw5/oatprograms/easyrun10.oat new file mode 100644 index 0000000..e94ae0b --- /dev/null +++ b/hw5/oatprograms/easyrun10.oat @@ -0,0 +1,19 @@ +int program (int argc, string[] argv) { + var x = new int[][]{new int[]{1}, + new int[]{2}, + new int[]{3}, + new int[]{4}}; + var ans = 0; + + for(var i=0;i<4;i=i+1;) { + ans = x[i][0] - ans; + } + + if((5 [&] ~5 [|] 0) != 0) { + return ans; + } else { + return -ans; + } + + return ans; +} diff --git a/hw5/oatprograms/easyrun2.oat b/hw5/oatprograms/easyrun2.oat new file mode 100644 index 0000000..d18f435 --- /dev/null +++ b/hw5/oatprograms/easyrun2.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 17 + 18; +} diff --git a/hw5/oatprograms/easyrun3.oat b/hw5/oatprograms/easyrun3.oat new file mode 100644 index 0000000..f57521a --- /dev/null +++ b/hw5/oatprograms/easyrun3.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var x = 0; + var i = 0; + + while (i < 10) { + x = (x + i) * i; + i = i + 1; + } + + return x; +} diff --git a/hw5/oatprograms/easyrun4.oat b/hw5/oatprograms/easyrun4.oat new file mode 100644 index 0000000..523f3b7 --- /dev/null +++ b/hw5/oatprograms/easyrun4.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + var x = 0; + for (var i=0; i<3; i = i+1;) { + x = x + 2; + } + return x; +} diff --git a/hw5/oatprograms/easyrun5.oat b/hw5/oatprograms/easyrun5.oat new file mode 100644 index 0000000..2ddb08f --- /dev/null +++ b/hw5/oatprograms/easyrun5.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var x = 100 >> 3; + var y = 100 << 3; + + if (x-y <= 0) { + return -x-y; + } else { + return x-y; + } + +} diff --git a/hw5/oatprograms/easyrun6.oat b/hw5/oatprograms/easyrun6.oat new file mode 100644 index 0000000..f2234cb --- /dev/null +++ b/hw5/oatprograms/easyrun6.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(!true | -4 + 5 > 0 & 6 * 4 < 25) { + return 9; + } else { + return 4; + } +} diff --git a/hw5/oatprograms/easyrun7.oat b/hw5/oatprograms/easyrun7.oat new file mode 100644 index 0000000..f6e053b --- /dev/null +++ b/hw5/oatprograms/easyrun7.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(((~5 [&] 6) >= (2 [|] 0))) { + return 23; + } else { + return 46; + } +} diff --git a/hw5/oatprograms/easyrun8.oat b/hw5/oatprograms/easyrun8.oat new file mode 100644 index 0000000..21cbce6 --- /dev/null +++ b/hw5/oatprograms/easyrun8.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(6 != 5) { + return ~(5 << 17 >> 2 >>> 10) * 2 - 100 + 6; + } else { + return 2; + } +} diff --git a/hw5/oatprograms/easyrun9.oat b/hw5/oatprograms/easyrun9.oat new file mode 100644 index 0000000..282656f --- /dev/null +++ b/hw5/oatprograms/easyrun9.oat @@ -0,0 +1,10 @@ +int program (int argc, string[] argv) { + var x = new int[]{1,2,3,4}; + var ans = 0; + + for(var i=0;i<4;i=i+1;) { + ans = x[i] * ~x[i]; + } + + return ans; +} diff --git a/hw5/oatprograms/fac.oat b/hw5/oatprograms/fac.oat new file mode 100644 index 0000000..d162b63 --- /dev/null +++ b/hw5/oatprograms/fac.oat @@ -0,0 +1,13 @@ +int f(int i) { + var r = 0; + if (i == 0) { + r = 1; + } else { + r = i * f (i-1); + } + return r; +} + +int program (int argc, string[] argv) { + return f (5); +} diff --git a/hw5/oatprograms/fact.oat b/hw5/oatprograms/fact.oat new file mode 100644 index 0000000..cf1e754 --- /dev/null +++ b/hw5/oatprograms/fact.oat @@ -0,0 +1,14 @@ +int fact(int x) { + var acc = 1; + while (x > 0) { + acc = acc * x; + x = x - 1; + } + return acc; +} + +int program(int argc, string[] argv) { + print_string(string_of_int(fact(5))); + return 0; +} + diff --git a/hw5/oatprograms/fibo.oat b/hw5/oatprograms/fibo.oat new file mode 100644 index 0000000..e473097 --- /dev/null +++ b/hw5/oatprograms/fibo.oat @@ -0,0 +1,26 @@ +int fibR(int n) { + if(n == 0) {return 0;} + if(n == 1) {return 1;} + return fibR(n - 1) + fibR(n-2); +} + +int fibI(int n) { + var a = 0; + var b = 1; + if(n == 0) {return a;} + if(n == 1) {return b;} + while(n-2 > 0) { + var old = b; + b = b + a; + a = old; + n = n - 1; + } + return a + b; +} + +int program (int argc, string[] argv) +{ + var val = 1; + if(fibR(12) == 144 & fibI(12) == 144) {val = 0;} + return val; +} diff --git a/hw5/oatprograms/float_multiply.oat b/hw5/oatprograms/float_multiply.oat new file mode 100644 index 0000000..cdb2b00 --- /dev/null +++ b/hw5/oatprograms/float_multiply.oat @@ -0,0 +1,52 @@ +global float_len = 2; +int[] determine_shift(int[] float) +{ + var dec = float[1]; + var count = 0; + while(dec > 0) + { + var temp = float[0]; + float[0] = temp << 1; + dec = dec >>> 1; + count = count + 1; + } + var list = new int[2]; + list[0] = float[0] + float[1]; + list[1] = count; + return list; +} + +int[] multiply_floats(int[] f1, int[] f2) +{ + var f1_shifted = determine_shift(f1); + var f2_shifted = determine_shift(f2); + var product = f1_shifted[0] * f2_shifted[0]; + var num_left_shifts = f1_shifted[1] + f2_shifted[1]; + var remainder = 0; + for(var i = 0; i < num_left_shifts; i=i+1;) + { + var lsb = product [&] 1; + var shifted_lsb = lsb << i; + product = product >>> 1; + remainder = remainder + shifted_lsb; + } + var ans = new int[2]; + ans[0] = product; + ans[1] = remainder; + return ans; +} + +int program(int argc, string[] argv) +{ + var pi = new int[2]; + pi[0] = 3; + pi[1] = 14159; + var diameter = new int[2]; + diameter[0] = 20; + diameter[1] = 17; + var prod = multiply_floats(pi, diameter); + print_int(prod[0]); + print_string("."); + print_int(prod[1]); + return 0; +} \ No newline at end of file diff --git a/hw5/oatprograms/gcd.oat b/hw5/oatprograms/gcd.oat new file mode 100644 index 0000000..31b9063 --- /dev/null +++ b/hw5/oatprograms/gcd.oat @@ -0,0 +1,26 @@ +int gcd(int a, int b) { + while (b != 0) { + var t = b; + b = mod(a, b); + a = t; + } + + return a; +} + +int mod (int a, int b) { + + var t = a; + while (t - b >= 0) { + t = t - b; + } + + return t; +} + +int program (int argc, string[] argv) { + var a = 64; + var b = 48; + + return gcd(a, b); +} \ No newline at end of file diff --git a/hw5/oatprograms/globals1.oat b/hw5/oatprograms/globals1.oat new file mode 100644 index 0000000..d6a8c21 --- /dev/null +++ b/hw5/oatprograms/globals1.oat @@ -0,0 +1,5 @@ +global x = 42; + +int program(int argc, string[] args) { + return x; +} diff --git a/hw5/oatprograms/globals2.oat b/hw5/oatprograms/globals2.oat new file mode 100644 index 0000000..8d2705c --- /dev/null +++ b/hw5/oatprograms/globals2.oat @@ -0,0 +1,8 @@ +global y = true; + +int program(int argc, string[] args) { + if (y) { + return 17; + } + return 15; +} diff --git a/hw5/oatprograms/globals3.oat b/hw5/oatprograms/globals3.oat new file mode 100644 index 0000000..f611f99 --- /dev/null +++ b/hw5/oatprograms/globals3.oat @@ -0,0 +1,5 @@ +global arr = int[] null; + +int program(int argc, string[] args) { + return 17; +} diff --git a/hw5/oatprograms/globals4.oat b/hw5/oatprograms/globals4.oat new file mode 100644 index 0000000..24ab285 --- /dev/null +++ b/hw5/oatprograms/globals4.oat @@ -0,0 +1,5 @@ +global arr = new int[]{1, 2, 3, 4}; + +int program(int argc, string[] args) { + return 5; +} diff --git a/hw5/oatprograms/globals5.oat b/hw5/oatprograms/globals5.oat new file mode 100644 index 0000000..0ab9fd5 --- /dev/null +++ b/hw5/oatprograms/globals5.oat @@ -0,0 +1,5 @@ +global s = "hello!"; + +int program(int argc, string[] args) { + return 17; +} diff --git a/hw5/oatprograms/globals6.oat b/hw5/oatprograms/globals6.oat new file mode 100644 index 0000000..58435e1 --- /dev/null +++ b/hw5/oatprograms/globals6.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] args) { + var s = "hello!"; + return 15; +} diff --git a/hw5/oatprograms/gnomesort.oat b/hw5/oatprograms/gnomesort.oat new file mode 100644 index 0000000..039fc52 --- /dev/null +++ b/hw5/oatprograms/gnomesort.oat @@ -0,0 +1,35 @@ + +void gnomeSort(int[] a, int len) { + var i = 1; + var j = 2; + + while(i < len) { + if (a[i-1] <= a[i]) { + i = j; + j = j + 1; + } else { + var tmp = a[i-1]; + a[i-1] = a[i]; + a[i] = tmp; + i = i - 1; + + if (i == 0) { + i = j; + j = j + 1; + } + } + } + return; +} + +int program(int argc, string[] argv) { + var arr = new int[]{ 5, 200, 1, 65, 30, 99, 2, 0 }; + var len = 8; + + gnomeSort(arr, len); + for(var i=0; i<8; i=i+1;) { + print_int(arr[i]); + } + + return 0; +} \ No newline at end of file diff --git a/hw5/oatprograms/hashcode.oat b/hw5/oatprograms/hashcode.oat new file mode 100644 index 0000000..c0594fb --- /dev/null +++ b/hw5/oatprograms/hashcode.oat @@ -0,0 +1,25 @@ +/* Java string hash function */ +/* hash = s[0] * 31 ^ (n - 1) + s[1] * 31 ^(n - 2) + ... + s[n-1]*/ + +int program(int argc, string[] argv) { + var s = "aa"; + var h = hash(s); + print_int(h); + return 0; +} + +int hash(string s) { + var int_arr = array_of_string(s); + var length = length_of_string(s); + var hash = 0; + for(var i = 0; i < length; i= i+1;) { + var power = 1; + for(var j = length - i - 1; j > 0; j= j-1;) { + power = power * 31; + } + var char = int_arr[i]; + hash = hash + power * char; + + } + return hash; +} \ No newline at end of file diff --git a/hw5/oatprograms/heap.oat b/hw5/oatprograms/heap.oat new file mode 100644 index 0000000..bc7d8cf --- /dev/null +++ b/hw5/oatprograms/heap.oat @@ -0,0 +1,53 @@ +void min_heapify(int[] array, int i, int len) { + var l = i * 2; + var r = i + 1; + var tmp = 0; + var m = i; + + if (l < len) { + if (array[l] > array[m]) { + m = l; + } + } + + if (r < len) { + if (array[r] > array[m]) { + m = r; + } + } + + if (m != i) { + tmp = array[i]; + array[i] = array[m]; + array[m] = tmp; + + min_heapify(array, m, len); + } + + return; +} + +void make_min_heap(int[] array, int len) { + for (var i = len; i >= 1; i = i - 1;) { + min_heapify(array, i, len); + } + + return; +} + +int program(int argc, string[] argv) { + var array = new int[]{ 0, 9, 1, 2, 8, 10, 7, 3, 6, 4, 5 }; + var end_result = new int[]{ 0, 1, 4, 2, 8, 5, 7, 3, 6, 9, 10 }; + + make_min_heap(array, 10); + + var same = 0; + + for (var i = 0; i < 11; i = i + 1;) { + if (array[i] != end_result[i]) { + same = 1; + } + } + + return same; +} diff --git a/hw5/oatprograms/insertion_sort.oat b/hw5/oatprograms/insertion_sort.oat new file mode 100644 index 0000000..acbb6f4 --- /dev/null +++ b/hw5/oatprograms/insertion_sort.oat @@ -0,0 +1,38 @@ +int[] insert(int[] partial, int len, int insertee) { + var inserted = new int[len+1]{i->0}; + for (var i=0; i < len+1; i=i+1;) { inserted[i] = -1; } + var not_yet_inserted = true; + if (insertee < partial[0]) { + not_yet_inserted = false; + inserted[0] = insertee; + } + for (var i = 0; i < len; i = i + 1;) { + if (not_yet_inserted) { + if (insertee > partial[i]) { + not_yet_inserted = false; + inserted[i+1] = insertee; + inserted[i] = partial[i]; + } else { + inserted[i] = partial[i]; + } + } else { + inserted[i+1] = partial[i]; + } + } + return inserted; +} + +int[] insort(int[] unsorted, int len) { + var out = new int[]{0}; + out[0] = unsorted[0]; + for (var i = 1; i < len; i = i + 1;) { + out = insert(out, i, unsorted[i]); + } + return out; +} + +int program(int argc, string[] argv) { + var array = new int[]{13, 42, 32, 3, 2, 6}; + var result = insort(array, 6); + return result[5]; +} diff --git a/hw5/oatprograms/is_prime.oat b/hw5/oatprograms/is_prime.oat new file mode 100644 index 0000000..8826357 --- /dev/null +++ b/hw5/oatprograms/is_prime.oat @@ -0,0 +1,31 @@ +global list = int[] {3, 5, 7, 8, 11, 16, 17, 21}; + +bool isPrime (int n) { + if (n < 2) { + return false; + } + + for (var i = 2; i < n; i = i + 1;) + { + var cur_num = n; + while (cur_num >= i) { + cur_num = cur_num - i; + } + + if (cur_num == 0) { + return false; + } + } + return true; +} + +int program (int argc, string[] argv) { + var answer = 0; + for (var i = 0; i < 8; i = i + 1;) + { + if(isPrime(list[i])) { + answer = answer + 1; + } + } + return answer; +} diff --git a/hw5/oatprograms/josh_joyce_test.oat b/hw5/oatprograms/josh_joyce_test.oat new file mode 100644 index 0000000..19e1b49 --- /dev/null +++ b/hw5/oatprograms/josh_joyce_test.oat @@ -0,0 +1,20 @@ +global arr1 = new int[]{1,2,3,4}; +global arr2 = new int[]{1,2,3,5}; + +int arrcheck(int[] ar1, int[] ar2, int len){ + var val = 0; + for(var i =0; i < len; i= i+1;){ + if (ar1[i] != ar2[i]) { + val = 1; + } + } + return val; +} + +int program(int argc, string[] argv) { + + var val = 1; + if(arrcheck(arr1, arr2, 4) == 1) {val = 0;} + return val; + +} diff --git a/hw5/oatprograms/kmp.oat b/hw5/oatprograms/kmp.oat new file mode 100644 index 0000000..7716f51 --- /dev/null +++ b/hw5/oatprograms/kmp.oat @@ -0,0 +1,68 @@ +/* Paul Lou and Tanner Haldeman */ +/* References: Algorithms (Sedgewick), https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm */ + +int[] construct_table(string w) { + var length = length_of_string(w); + var arr_of_w = array_of_string(w); + var t = new int[length]; + var curr = 2; + var next = 0; + + t[0] = -1; + t[1] = 0; + while (curr < length) { + if (arr_of_w[curr-1] == arr_of_w[next]) { + t[curr] = next + 1; + next = next + 1; + curr = curr + 1; + } + else if (next > 0) { + next = t[next]; + } + else { + t[curr] = 0; + curr = curr + 1; + } + } + + return t; +} + + +int kmp(string str, string w) { + var str_idx = 0; + var word_idx = 0; + var word_length = length_of_string(w); + var word_arr = array_of_string(w); + var str_arr = array_of_string(str); + var t = construct_table(w); + + while (str_idx + word_idx < length_of_string(str)) { + if (word_arr[word_idx] == str_arr[str_idx + word_idx]) { + if (word_idx == word_length - 1) { + return str_idx; + } + word_idx = word_idx + 1; + } + else { + if (t[word_idx] > -1) { + str_idx = str_idx + word_idx - t[word_idx]; + word_idx = t[word_idx]; + } + else { + str_idx = str_idx + 1; + word_idx = 0; + } + } + } + + return -1; +} + +int program(int argc, string[] argv) { + var str = "abcdabcdabcdcbab"; + var word = "dabcdc"; + + var ret = kmp(str, word); + return ret; +} diff --git a/hw5/oatprograms/lcs.oat b/hw5/oatprograms/lcs.oat new file mode 100644 index 0000000..f2da612 --- /dev/null +++ b/hw5/oatprograms/lcs.oat @@ -0,0 +1,48 @@ +/* + * CIS 341 Homework 4 + * Thomas Delacour & Max McCarthy + */ + +/** + * Computes longest common subsequence of two strings a and b. + */ +global buf = new int[]{0}; + +string lcs(int i, int j, string a, string b) { + if (i < 0 | j < 0) { + return ""; + } + + var a_chars = array_of_string(a); + var b_chars = array_of_string(b); + + var last_char_a = a_chars[i]; + var last_char_b = b_chars[j]; + + if (last_char_a == last_char_b) { + var prev_lcs = lcs(i - 1, j - 1, a, b); + buf[0] = a_chars[i]; + var next_char = string_of_array(buf); + return string_cat(prev_lcs, next_char); + } + + var left_lcs = lcs(i, j - 1, a, b); + var right_lcs = lcs(i - 1, j, a, b); + + var left_len = length_of_string(left_lcs); + var right_len = length_of_string(right_lcs); + + if (left_len < right_len) { + return right_lcs; + } else { + return left_lcs; + } +} + +int program(int argc, string[] argv) { + var tomato = "TOMATO"; + var orating = "ORATING"; + print_string(lcs(5, 6, tomato, orating)); + return 0; +} + diff --git a/hw5/oatprograms/leastsquare.oat b/hw5/oatprograms/leastsquare.oat new file mode 100644 index 0000000..bb97a72 --- /dev/null +++ b/hw5/oatprograms/leastsquare.oat @@ -0,0 +1,40 @@ + +int program(int argc, string[] argv) { + var n = 500; + return leastsquare(n); +} + +/*finds the least number of squares to sum up to n*/ + +int leastsquare(int n) { + var cache = new int[]{n+1}; + cache[0] = 0; + cache[1] = 1; + cache[2] = 2; + cache[3] = 3; + for (var i = 4; i < n + 1; i=i+1;) { + /*set to some arbitrary high number*/ + cache[i] = i; + + for (var k = 1; k < n; k = k + 1;) { + var temp = k*k; + if (temp > i) { + + } else { + cache[i] = min(cache[i], 1 + cache[i - temp]); + } + } + } + return cache[n]; +} + + + + +int min(int y, int x) { + if (x > y) { + return y; + } else { + return x; + } +} diff --git a/hw5/oatprograms/lfsr.oat b/hw5/oatprograms/lfsr.oat new file mode 100644 index 0000000..1320b2a --- /dev/null +++ b/hw5/oatprograms/lfsr.oat @@ -0,0 +1,44 @@ +global lfsr_iterations = 5; +global lfsr_length = 4; +global lfsr_init_values = new bool[]{true, false, true, false}; + +bool xor(bool x, bool y) { + return (x & !y) | (!x & y); +} + +string string_of_bool(bool b) { + if (b) { return "T"; } + else { return "F"; } +} + +void print_lfsr(bool[] lfsr_register, int len) { + for (var i = 0; i < len; i = i + 1;) { + print_string(string_of_bool(lfsr_register[i])); + } + return; +} + +int program(int argc, string[] argv) { + /* Initialize the working register */ + var lfsr_register = new bool[lfsr_length]{i->false}; + for (var i=0; i < lfsr_length; i=i+1;) { + lfsr_register[i] = lfsr_init_values[i]; + } + + /* Do the computations */ + for (var i = 0; i < lfsr_iterations; i = i + 1;) { + var new_first = + xor(lfsr_register[lfsr_length - 1], lfsr_register[lfsr_length - 2]); + for (var j = lfsr_length - 1; j > 0; j = j - 1;) { + lfsr_register[j] = lfsr_register[j - 1]; + } + lfsr_register[0] = new_first; + } + + /* Print the initial and final bool arrays with a space separator */ + print_lfsr(lfsr_init_values, lfsr_length); + print_string(" "); + print_lfsr(lfsr_register, lfsr_length); + + return 0; +} diff --git a/hw5/oatprograms/lfsr2.oat b/hw5/oatprograms/lfsr2.oat new file mode 100644 index 0000000..80d6484 --- /dev/null +++ b/hw5/oatprograms/lfsr2.oat @@ -0,0 +1,15 @@ +global lfsr_length = 4; +global lfsr_init_values = new bool[]{true, false, true, false}; + +void print_lfsr(bool[] lfsr_register, int len) { + for (var i = 0; i < len; i = i + 1;) { + var x = lfsr_register[i]; + } + return; +} + +int program(int argc, string[] argv) { + /* Print the initial and final bool arrays with a space separator */ + print_lfsr(lfsr_init_values, lfsr_length); + return 0; +} diff --git a/hw5/oatprograms/lib10.oat b/hw5/oatprograms/lib10.oat new file mode 100644 index 0000000..19f9cf3 --- /dev/null +++ b/hw5/oatprograms/lib10.oat @@ -0,0 +1,7 @@ +int my_length_of_string (string str) { + return length_of_array (array_of_string (str)); +} + +int program (int argc, string[] argv) { + return my_length_of_string ("Hello?"); +} diff --git a/hw5/oatprograms/lib11.oat b/hw5/oatprograms/lib11.oat new file mode 100644 index 0000000..e152db9 --- /dev/null +++ b/hw5/oatprograms/lib11.oat @@ -0,0 +1,13 @@ +int program (int argc, string[] argv) { + var arr = array_of_string("1234967890"); + var sum = 0; + + for (var i=0; i<10; i=i+1;) { + arr[i] = i; + } + for (var i=0; i<10; i=i+1;) { + sum = sum + arr[i]; + } + + return sum; +} diff --git a/hw5/oatprograms/lib12.oat b/hw5/oatprograms/lib12.oat new file mode 100644 index 0000000..a0d9775 --- /dev/null +++ b/hw5/oatprograms/lib12.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr = oat_alloc_array(10); + return arr[10]; +} + diff --git a/hw5/oatprograms/lib13.oat b/hw5/oatprograms/lib13.oat new file mode 100644 index 0000000..a6e0132 --- /dev/null +++ b/hw5/oatprograms/lib13.oat @@ -0,0 +1,25 @@ +global str1 = "Hello "; + +string string_concat (string str1, string str2) { + var arr1 = array_of_string (str1); + var arr2 = array_of_string (str2); + var len1 = length_of_array (arr1); + var len2 = length_of_array (arr2); + var arr3 = new int[len1+len2]; + var i = 0; + for(var j=0; j arr[i+start]}; + return string_of_array (r); +} + +int program (int argc, string [] argv) { + print_string (sub(argv[1], 3, 5)); + return 0; +} diff --git a/hw5/oatprograms/lib2.oat b/hw5/oatprograms/lib2.oat new file mode 100644 index 0000000..1fdfd84 --- /dev/null +++ b/hw5/oatprograms/lib2.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{0,0}, new int[]{1,1}, new int[]{2,2}, new int[]{3,3}}; + var len = length_of_array (arr[2]); + return len; +} diff --git a/hw5/oatprograms/lib3.oat b/hw5/oatprograms/lib3.oat new file mode 100644 index 0000000..fb0d642 --- /dev/null +++ b/hw5/oatprograms/lib3.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{0,0,0,0}, new int[]{1,1}, new int[]{2,2}, new int[]{3,3}}; + var len = length_of_array (arr[0]); + return len; +} diff --git a/hw5/oatprograms/lib4.oat b/hw5/oatprograms/lib4.oat new file mode 100644 index 0000000..d2beb1a --- /dev/null +++ b/hw5/oatprograms/lib4.oat @@ -0,0 +1,11 @@ +global str = "hello"; + +int program (int argc, string[] argv) { + var arr = array_of_string (str); + var s = 0; + for (var i=0; i<5; i=i+1;) { + s = s + arr[i]; + } + print_int(s); + return s; +} diff --git a/hw5/oatprograms/lib5.oat b/hw5/oatprograms/lib5.oat new file mode 100644 index 0000000..017c9ea --- /dev/null +++ b/hw5/oatprograms/lib5.oat @@ -0,0 +1,9 @@ +int program (int argc, string[] argv) { + var str = "hello"; + var arr = array_of_string (str); + var s = 0; + for (var i=0; i<5; i=i+1;) { + s = s + arr[i]; + } + return s; +} diff --git a/hw5/oatprograms/lib6.oat b/hw5/oatprograms/lib6.oat new file mode 100644 index 0000000..69aa763 --- /dev/null +++ b/hw5/oatprograms/lib6.oat @@ -0,0 +1,12 @@ +int program (int argc, string[] argv) { + var arr1 = new int[]{111,112,113,114,115}; + var str = string_of_array (arr1); + var arr2 = array_of_string (str); + var s = 0; + for (var i=0; i<5; i=i+1;) { + s = s + arr2[i]; + } + print_int(s); + return s; +} + diff --git a/hw5/oatprograms/lib7.oat b/hw5/oatprograms/lib7.oat new file mode 100644 index 0000000..bb012f2 --- /dev/null +++ b/hw5/oatprograms/lib7.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var arr1 = new int[]{111,112,113,114,115}; + var str = string_of_array (arr1); + var arr2 = array_of_string (str); + var s = 0; + for (var i=0; i<5; i=i+1;) { + s = s + arr2[i]; + } + return s; +} + diff --git a/hw5/oatprograms/lib8.oat b/hw5/oatprograms/lib8.oat new file mode 100644 index 0000000..743daea --- /dev/null +++ b/hw5/oatprograms/lib8.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var str = "Hello world!"; + print_string (str); + return 0; +} diff --git a/hw5/oatprograms/lib9.oat b/hw5/oatprograms/lib9.oat new file mode 100644 index 0000000..2096cb8 --- /dev/null +++ b/hw5/oatprograms/lib9.oat @@ -0,0 +1,6 @@ +int program(int argc, string[] argv) { + for (var i=1; i= 0) & (j >= 0) & (i < len) & (j < len)) { + return count + board[i][j]; + } else { + return count; + } +} + +int val_at(int[][] board, int i, int j) { + var alive = board[i][j]; + var count = 0; + count = check(board, i-1, j-1, count); + count = check(board, i-1, j , count); + count = check(board, i-1, j+1, count); + + count = check(board, i , j-1, count); + count = check(board, i , j+1, count); + + count = check(board, i+1, j-1, count); + count = check(board, i+1, j , count); + count = check(board, i+1, j+1, count); + + if (alive == 1) { + if (count < 2) { + return 0; + } else if (count < 4) { + return 1; + } + return 0; + } + if (count == 3) { + return 1; + } else { + return 0; + } + return 0; +} + +int program (int argc, string[] argv) { + var board = new int[][]{ new int[]{0, 0, 0, 0}, + new int[]{0, 1, 1, 1}, + new int[]{1, 1, 1, 0}, + new int[]{0, 0, 0, 0} }; + + var new_board = new int[][4]; + for (var i=0; i < 4; i=i+1;) { + new_board[i] = new int[4]; + for (var j=0; j < 4; j=j+1;) { new_board[i][j] = val_at(board, i,j); } + } + + for (var i = 0; i < len; i = i+1;) { + for (var j = 0; j < len; j = j+1;) { + print_int(new_board[i][j]); + } + } + return 0; +} diff --git a/hw5/oatprograms/matrixmult.oat b/hw5/oatprograms/matrixmult.oat new file mode 100644 index 0000000..1560b5d --- /dev/null +++ b/hw5/oatprograms/matrixmult.oat @@ -0,0 +1,69 @@ + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +int program(int argc, string[] argv) +{ + var a = new int[][]{new int[]{1, 3, 4}, + new int[]{2, 0, 1}}; + var b = new int[][]{new int[]{1, 2, 3, 1}, + new int[]{2, 2, 2, 2}, + new int[]{3, 2, 1, 4}}; + var c = new int[][]{new int[]{0, 0, 0, 0}, + new int[]{0, 0, 0, 0}}; + + matrix_Mult(a, b, c); + prnNx4(c, 2); + + matrix_MultAlt(a, b, c); /* alternate form that calls dot3 */ + prnNx4(c, 2); + return 0; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void matrix_Mult(int[][] a1, int [][] a2, int [][] a3) +{ + for(var i = 0; i < 2; i=i+1;) { + for(var j = 0; j < 4; j=j+1;) { + for(var k = 0; k < 3; k=k+1;) { + a3[i][j] = a3[i][j] + a1[i][k] * a2[k][j]; + } + } + } + return; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void matrix_MultAlt(int[][] a1, int[][] a2, int[][] a3) +{ + for(var i = 0; i < 2; i=i+1;) { + for(var j = 0; j < 4; j=j+1;) { + a3[i][j] = dot3(a1, a2, i, j); + } + } + return; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +int dot3(int[][] a1, int[][] a2, int row, int col) +{ + var sum = 0; + for(var k = 0; k < 3; k=k+1;) { + sum = sum + a1[row][k] * a2[k][col]; + } + return sum; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void prnNx4 (int[][] ar, int n) +{ + for(var i = 0; i < n; i=i+1;) + { + for(var j = 0; j < 4; j=j+1;) + { + print_int(ar[i][j]); + print_string (" "); + } + print_string("\t"); + } + return; +} + diff --git a/hw5/oatprograms/maxsubsequence.oat b/hw5/oatprograms/maxsubsequence.oat new file mode 100644 index 0000000..31b8ca1 --- /dev/null +++ b/hw5/oatprograms/maxsubsequence.oat @@ -0,0 +1,26 @@ +int maxsum(int[] arr, int size) { + var maxarr = new int[size]{i->0}; + var maxs = 0; + maxarr[0] = arr[0]; + for(var i = 0; i < size; i = i+1;){ + for(var j = 0; j < i; j=j+1;){ + if(arr[i] > arr[j] & maxarr[i] < maxarr[j] + arr[i]){ + maxarr[i] = maxarr[j] + arr[i]; + } + } + if(maxs < maxarr[i]){ + maxs = maxarr[i]; + } + } + return maxs; +} + +int program (int argc, string[] argv) { + var array = new int[]{1,101,2,3,101,4,5}; + var max_ans = maxsum(array, 7); + return max_ans; +} + + + + diff --git a/hw5/oatprograms/msort.oat b/hw5/oatprograms/msort.oat new file mode 100644 index 0000000..7c576c6 --- /dev/null +++ b/hw5/oatprograms/msort.oat @@ -0,0 +1,68 @@ +int program (int argc, string[] argv) { + var i = 0; + var a = new int[]{126,125,124,123,122,121,120,119,118,117}; + print_string (string_of_array(a)); + oat_mergesort(a,0,9); + print_string (" "); + print_string (string_of_array(a)); + print_string (" "); + return i; +} + +void oat_mergesort(int[] a, int low, int high) +{ + var mid=0; + if(low>1; + oat_mergesort(a,low,mid); + oat_mergesort(a,mid+1,high); + merge(a,low,high,mid); + } + return; +} + +void merge(int[] a, int low, int high, int mid) +{ + var i=0; + var j=0; + var k=0; + var c=new int[50]{i1->0}; + i=low; + j=mid+1; + k=low; + while((i<=mid)&(j<=high)) + { + if(a[i]>1; + oat_mergesort(a,low,mid); + oat_mergesort(a,mid+1,high); + merge(a,low,high,mid); + } + return; +} + +void merge(int[] a, int low, int high, int mid) +{ + var i=0; + var j=0; + var k=0; + var c=new int[50]{i2->0}; + i=low; + j=mid+1; + k=low; + while((i<=mid)&(j<=high)) + { + if(a[i]= 0) { + t = t - b; + } + return t; +} + +int div (int a, int b) { + var result = 0; + var num = a; + var denom = b; + while (num > 0) { + num = num - denom; + result = result + 1; + } + return result; +} + +int no_of_factors(int n) { + var num_fact = 1; + var input = n; + for (var i = 2; i * i < input + 1; i=i+1;) { + var power = 0; + while (mod(n, i) == 0) { + n = div(n, i); + power = power + 1; + } + num_fact = num_fact * (power + 1); + } + if (n > 1) { + num_fact = num_fact * 2; + } + return num_fact; +} + +int program (int argc, string[] argv) { + return no_of_factors(6400); +} diff --git a/hw5/oatprograms/path1.oat b/hw5/oatprograms/path1.oat new file mode 100644 index 0000000..8de1752 --- /dev/null +++ b/hw5/oatprograms/path1.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = 17; + return x; +} diff --git a/hw5/oatprograms/path2.oat b/hw5/oatprograms/path2.oat new file mode 100644 index 0000000..c80300b --- /dev/null +++ b/hw5/oatprograms/path2.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var x = 17; + var y = 18; + return x + y; +} diff --git a/hw5/oatprograms/path3.oat b/hw5/oatprograms/path3.oat new file mode 100644 index 0000000..da7f0c9 --- /dev/null +++ b/hw5/oatprograms/path3.oat @@ -0,0 +1,5 @@ +global arr = new int[]{1, 2, 3, 4}; + +int program(int argc, string[] args) { + return arr[2]; +} diff --git a/hw5/oatprograms/phase2_1.oat b/hw5/oatprograms/phase2_1.oat new file mode 100644 index 0000000..d3c10cb --- /dev/null +++ b/hw5/oatprograms/phase2_1.oat @@ -0,0 +1,7 @@ +int x = 3; +string y = "hello"; + +int program(int argc, string[] argv) { + print_string(y); + return 0; +} diff --git a/hw5/oatprograms/qs_bs.oat b/hw5/oatprograms/qs_bs.oat new file mode 100644 index 0000000..3a42712 --- /dev/null +++ b/hw5/oatprograms/qs_bs.oat @@ -0,0 +1,52 @@ +int partition(int[] a, int low_ind, int hi_ind) { + var pivot = a[hi_ind]; + var i = low_ind - 1; + for (var j = low_ind; j < hi_ind; j=j+1;) { + if (a[j] <= pivot) { + i = i + 1; + var atemp1 = a[i]; + a[i] = a[j]; + a[j] = atemp1; + } + } + var atemp2 = a[i+1]; + a[i+1] = a[hi_ind]; + a[hi_ind] = atemp2; + return i+1; +} + +void quicksort(int[] a, int low_ind, int hi_ind) { + if (low_ind < hi_ind) { + var p = partition(a, low_ind, hi_ind); + quicksort(a, low_ind, p-1); + quicksort(a, p+1, hi_ind); + } + return ; +} + +int int_division (int a, int b) { + var btemp = 0; + var i = 0; + while (a > btemp) { + btemp = btemp + b; + i = i + 1; + } + return i; +} + +int binary_search (int[] a, int e, int max, int min) { + var mid = min + int_division (max - min, 2); + if (a[mid] == e) { + return mid; + } + if (a[mid] > e) { + return binary_search (a, e, mid - 1, min); + } + return binary_search (a, e, max, mid + 1); +} + +int program (int argc, string[] argv) { + var a = new int[] {5, 9, 6, 4, 2, 7, 10, 100, 1000, 99, 55, 999, 33, 4, 20}; + quicksort (a, 0, 14); + return binary_search (a, 10, 14, 0) + 7 * binary_search (a, 4, 14, 0) + 23 * binary_search (a, 999, 14, 0); +} \ No newline at end of file diff --git a/hw5/oatprograms/qsort.oat b/hw5/oatprograms/qsort.oat new file mode 100644 index 0000000..f3f439f --- /dev/null +++ b/hw5/oatprograms/qsort.oat @@ -0,0 +1,53 @@ + +void quick_sort( int[] a, int l, int r) +{ + var j=0; + + if( l < r ) + { + /* divide and conquer */ + j = partition( a, l, r); + quick_sort( a, l, j-1); + quick_sort( a, j+1, r); + } + + return; +} + +int partition( int[] a, int l, int r) { + var pivot=a[l]; + var i =l; + var j = r+1; + var t=0; + var done = 0; + + while(done==0) + { + i = i + 1; + while( a[i] <= pivot & i <= r ) { + i = i + 1; + } + j = j - 1; + while( a[j] > pivot ) { + j = j - 1; + } + if( i >= j ) { done=1; } + if (done==0) { + t = a[i]; a[i] = a[j]; a[j] = t; + } + } + t = a[l]; a[l] = a[j]; a[j] = t; + return j; +} + +int program (int argc, string[] argv) { + + var a = new int[]{ 107, 112, 121, 102, 123, 115, 104, 111, 109}; + + print_string (string_of_array (a)); + quick_sort( a, 0, 8); + print_string (string_of_array (a)); + + return 255; +} + diff --git a/hw5/oatprograms/regalloctest.oat b/hw5/oatprograms/regalloctest.oat new file mode 100644 index 0000000..46f2d2b --- /dev/null +++ b/hw5/oatprograms/regalloctest.oat @@ -0,0 +1,24 @@ +int program(int argc, string[] argv) { + var x = 0; + for (var i = 0; i < 10000000; i = i + 1;) { + var a = 0; + var b = a + i; + var c = b + i; + var d = c + i; + var e = d + i; + var f = e + i; + var g = f + i; + var h = g + i; + var j = h + i; + var k = j + i; + var l = k + i; + var m = l + i; + var n = m + i; + var o = n + i; + var p = o + i; + var q = p + i; + var r = q + i; + x = x + r; + } + return x; +} diff --git a/hw5/oatprograms/regalloctest2.oat b/hw5/oatprograms/regalloctest2.oat new file mode 100644 index 0000000..990c425 --- /dev/null +++ b/hw5/oatprograms/regalloctest2.oat @@ -0,0 +1,34 @@ +int foo(int x, int y, int z) { + var a = x + y; + var b = y + z; + return a + b; +} + +int program(int argc, string[] argv) { + var x = 0; + for (var i = 0; i < 10000000; i = i + 1;) { + var a = 0; + var b = a + i; + var c = b + i; + var d = c + i; + d = d + foo(a, b, c); + var e = d + i; + var f = e + i; + var g = f + i; + var h = g + i; + var j = h + i; + j = j + foo(f, g, h); + var k = j + i; + var l = k + i; + var m = l + i; + var n = m + i; + n = n + foo(k, l, m); + var o = n + i; + var p = o + i; + var q = p + i; + var r = q + i; + x = x + r; + } + print_int(x); + return 0; +} diff --git a/hw5/oatprograms/regex.oat b/hw5/oatprograms/regex.oat new file mode 100644 index 0000000..5364401 --- /dev/null +++ b/hw5/oatprograms/regex.oat @@ -0,0 +1,34 @@ +int reg_match(int[] str, int[] reg, int p1, int p2, int last) { + if (str[p1] == 0 & reg[p2] == 0) { + return 1; + } + if (str[p1] == 0 & reg[p2] != 0) { + return 0; + } + if (str[p1] != 0 & reg[p2] == 0) { + return 0; + } + if (reg[p2+1] == 42) { + return reg_match(str, reg, p1, p2+1, reg[p2]); + } + if (reg[p2] == 42) { + var result = reg_match(str, reg, p1, p2+1, 0); + if (result == 1) { + return 1; + } + if (str[p1] == last | last == 46) { + return reg_match(str, reg, p1+1, p2, last); + } + return 0; + } + if (str[p1] == reg[p2] | reg[p2] == 46) { + return reg_match(str, reg, p1+1, p2+1, 0); + } + return 0; +} + +int program(int argc, string[] argv) { + var str = new int[]{97, 98, 99, 99, 99, 99, 99, 100, 101, 102, 0}; + var reg = new int[]{97, 103, 42, 46, 99, 42, 99, 42, 100, 101, 42, 102, 0}; + return reg_match(str, reg, 0, 0, 0); +} diff --git a/hw5/oatprograms/reverse.oat b/hw5/oatprograms/reverse.oat new file mode 100644 index 0000000..d7ab3f9 --- /dev/null +++ b/hw5/oatprograms/reverse.oat @@ -0,0 +1,31 @@ +int mod_ten (int n) { + if (n < 10) { + return n; + } + + return mod_ten (n - 10); +} + +int div_ten (int n) { + var c = 0; + while (n >= 10) { + n = n - 10; + c = c + 1; + } + return c; +} + +int reversed (int n) { + var r = 0; + while (n != 0) { + var n_mod_ten = mod_ten(n); + r = (r * 10) + n_mod_ten; + n = div_ten(n); + } + return r; +} + +int program (int argc, string[] argv) { + var n = 321; + return reversed(n); +} \ No newline at end of file diff --git a/hw5/oatprograms/rod_cutting.oat b/hw5/oatprograms/rod_cutting.oat new file mode 100644 index 0000000..dfe09b6 --- /dev/null +++ b/hw5/oatprograms/rod_cutting.oat @@ -0,0 +1,62 @@ +bool arr_eq(int[] arr1, int[] arr2, int n) { + var flag = true; + for(var i = 0; i < n; i = i + 1;) { + flag = flag & (arr1[i] == arr2[i]); + } + return flag; +} + +void clear_arr(int[] arr, int length) { + for (var i = 0; i < length; i = i + 1;) { arr[i] = 0; } + return; +} + +/* Adapted from CLRS */ +int optimal_cuts (int[] prices, int length, int[] choices) { + var max_price = new int[length + 1]; + max_price[0] = 0; + var first_cut = new int[length + 1]; + clear_arr(first_cut, length + 1); + + for (var j = 1; j <= length; j = j+1;) { + var max_j = 0; + for (var i = 1; i <= j; i = i+1;) { + var new_soln = prices[i] + max_price[j - i]; + if (new_soln > max_j) { + max_j = new_soln; + first_cut[j] = i; + } + } + max_price[j] = max_j; + } + + var n = length; + /* First cut stores the largest optimal cut that can be made */ + /* We can recurse downwards to construct the final answer */ + while (n > 0) { + var cut = first_cut[n]; + choices[cut] = choices[cut] + 1; + n = n - cut; + } + + return max_price[length]; +} + +int program (int argc, string[] argv) { + var prices = new int[] {0, 1, 5, 11, 13, 15, 17, 17, 20, 24, 30}; + var length = 10; + var cuts = new int[length + 1]; + clear_arr(cuts, length + 1); + + var max_price = optimal_cuts(prices, length, cuts); + + var expected_max_price = 35; + var expected_cuts = new int[]{0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0}; + + if (expected_max_price == max_price & + arr_eq(expected_cuts, cuts, length + 1)) { + return max_price; + } else { + return 0; + } +} diff --git a/hw5/oatprograms/run1.oat b/hw5/oatprograms/run1.oat new file mode 100644 index 0000000..a1162e2 --- /dev/null +++ b/hw5/oatprograms/run1.oat @@ -0,0 +1,21 @@ +global i = 42; + +int f(int x) { + return x; +} + +int g(int[] y) { + return y[2]; +} + +int program (int argc, string[] argv) { + var garr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + var arr = new int[]{1, 2, 3, 4}; + var p=0; + + for (var j=0; j<100; j=j+1; ) { + p=p+1; + } + + return g(arr) + f(i) + f(arr[3]) + f(garr[1][1]) + f(p); +} diff --git a/hw5/oatprograms/run10.oat b/hw5/oatprograms/run10.oat new file mode 100644 index 0000000..9b83d8d --- /dev/null +++ b/hw5/oatprograms/run10.oat @@ -0,0 +1,9 @@ +int[] f (int[] arr) { + return arr; +} + +int program (int argc, string[] argv) { + var garr = new int[][] {new int[]{1, 2, 3}, new int[]{4, 5, 6}}; + var arr = f(garr[1]); + return arr[1]; +} diff --git a/hw5/oatprograms/run11.oat b/hw5/oatprograms/run11.oat new file mode 100644 index 0000000..55ade43 --- /dev/null +++ b/hw5/oatprograms/run11.oat @@ -0,0 +1,28 @@ +global i = 1; + +int f(int[] arr) { + return arr[3]; +} + +int[] g() { + var arr = new int[] {99, 1, 99, 99}; + return arr; +} + +int program (int argc, string[] argv) { + var arr1 = new int[] {99, 1, 99}; + var arr2 = new int[][] {new int[]{99,99,99}, + new int[]{99,1,99}, + new int[]{99,99,99}}; + + var c = 1; + var arr4 = g(); + var arr3 = new int[] {99, 99, 99, 1}; + c = c + i; + c = c + arr1[1]; + c = c + arr2[1][1]; + c = c + arr3[3]; + c = c + f(arr3); + c = c + arr4[1]; + return c; +} diff --git a/hw5/oatprograms/run13.oat b/hw5/oatprograms/run13.oat new file mode 100644 index 0000000..ddec733 --- /dev/null +++ b/hw5/oatprograms/run13.oat @@ -0,0 +1,7 @@ +int f(int x, int y) { + return x; +} + +int program (int argc, string[] argv) { + return f(1, 2); +} diff --git a/hw5/oatprograms/run14.oat b/hw5/oatprograms/run14.oat new file mode 100644 index 0000000..d556347 --- /dev/null +++ b/hw5/oatprograms/run14.oat @@ -0,0 +1,19 @@ +int f(int[] a) { + return a[1]; +} + +int g(int x) { + var arr = new int[3]{i->0}; + for (var i = 0; i < 3; i=i+1;) { arr[i] = x; } + return arr[1]; +} + +int program (int argc, string[] argv) { + var a = new int[3]{i->0}; + for (var i=0; i < 3; i=i+1;) { a[i] = i; } + var arr = new int[4]{i->0}; + for (var i=0; i < 4; i=i+1;) { arr[i] = i*i; } + var arr0 = new int[3]{i->0}; + for (var i=0; i < 3; i=i+1;) { arr0[i] = 2*i; } + return arr[3] + a[1] + f(arr0) + g(4); +} diff --git a/hw5/oatprograms/run15.oat b/hw5/oatprograms/run15.oat new file mode 100644 index 0000000..9d96465 --- /dev/null +++ b/hw5/oatprograms/run15.oat @@ -0,0 +1,15 @@ +int f(int[][] a) { + return a[1][1]; +} + +int g(int x) { + var arr = new int[][3]{i-> new int[3]{j -> x}}; + return arr[1][1]; +} + +int program (int argc, string[] argv) { + var a = new int[][3]{i -> new int[3]{j -> j}}; + var arr = new int[][4]{i -> new int[5]{j -> i*j }}; + var arr0 = new int[][3]{i -> new int[3]{j -> i*j}}; + return arr[3][4] + a[1][2] + f(arr0) + g(4); +} diff --git a/hw5/oatprograms/run16.oat b/hw5/oatprograms/run16.oat new file mode 100644 index 0000000..9c0049b --- /dev/null +++ b/hw5/oatprograms/run16.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var x = 10; + var a = new int[][3]{i -> new int[3]{j -> x+i+j}}; + var b = a; + return b[2][1]; +} diff --git a/hw5/oatprograms/run17.oat b/hw5/oatprograms/run17.oat new file mode 100644 index 0000000..1a5ee03 --- /dev/null +++ b/hw5/oatprograms/run17.oat @@ -0,0 +1,12 @@ +int program (int argc, string[] argv) { + var x = 10; + var a = new int[][3]; + for (var i = 0; i<3; i = i+1;) { + a[i] = new int[3]; + for (var j = 0; j<3; j=j+1;) { + a[i][j] = x+i+j; + } + } + var b = a; + return b[2][2]; +} diff --git a/hw5/oatprograms/run18.oat b/hw5/oatprograms/run18.oat new file mode 100644 index 0000000..793af78 --- /dev/null +++ b/hw5/oatprograms/run18.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{1, 100, 999}; + return a[2]; +} diff --git a/hw5/oatprograms/run19.oat b/hw5/oatprograms/run19.oat new file mode 100644 index 0000000..9c76a76 --- /dev/null +++ b/hw5/oatprograms/run19.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var i=999; + var a = new int[]{1, 100, 999}; + return a[2]; +} diff --git a/hw5/oatprograms/run2.oat b/hw5/oatprograms/run2.oat new file mode 100644 index 0000000..8a2fd49 --- /dev/null +++ b/hw5/oatprograms/run2.oat @@ -0,0 +1,18 @@ +global i=0; + +int f(int x, int y) { + var r = 0; + if (x >= 1) { + r = 1 + f (x-1, y); + } else { + r = x + y; + } + return r; +} + +int program (int argc, string[] argv) { + var x = 3; + var y = 3; + + return f(x, y)+i; +} diff --git a/hw5/oatprograms/run20.oat b/hw5/oatprograms/run20.oat new file mode 100644 index 0000000..6978566 --- /dev/null +++ b/hw5/oatprograms/run20.oat @@ -0,0 +1,6 @@ +int f() {return 19;} + +int program (int argc, string[] argv) { + var a = new int[]{1, 100, 19}; + return a[2]; +} diff --git a/hw5/oatprograms/run21.oat b/hw5/oatprograms/run21.oat new file mode 100644 index 0000000..58bfb4a --- /dev/null +++ b/hw5/oatprograms/run21.oat @@ -0,0 +1,5 @@ + +int program (int argc, string[] argv) { + var i= new int[]{99,0}; + return i[0]; +} diff --git a/hw5/oatprograms/run22.oat b/hw5/oatprograms/run22.oat new file mode 100644 index 0000000..1e4c461 --- /dev/null +++ b/hw5/oatprograms/run22.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var strs = new string[]{"abc", "def"}; + print_string (strs[0]); + return 0; +} diff --git a/hw5/oatprograms/run23.oat b/hw5/oatprograms/run23.oat new file mode 100644 index 0000000..7aa00e6 --- /dev/null +++ b/hw5/oatprograms/run23.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var strs = new string[][]{new string[]{"abc", "def"}, + new string[]{"789", "123"}}; + print_string (strs[1][1]); + return 0; +} diff --git a/hw5/oatprograms/run24.oat b/hw5/oatprograms/run24.oat new file mode 100644 index 0000000..a373076 --- /dev/null +++ b/hw5/oatprograms/run24.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{}; + return 0; +} diff --git a/hw5/oatprograms/run25.oat b/hw5/oatprograms/run25.oat new file mode 100644 index 0000000..3d54e9e --- /dev/null +++ b/hw5/oatprograms/run25.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var a = new int[3]{i -> 110}; + var str = string_of_array (a); + print_string (str); + return 0; +} diff --git a/hw5/oatprograms/run26.oat b/hw5/oatprograms/run26.oat new file mode 100644 index 0000000..4e1f768 --- /dev/null +++ b/hw5/oatprograms/run26.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 0; +} diff --git a/hw5/oatprograms/run27.oat b/hw5/oatprograms/run27.oat new file mode 100644 index 0000000..ad9574f --- /dev/null +++ b/hw5/oatprograms/run27.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var i=99; + return i; +} diff --git a/hw5/oatprograms/run28.oat b/hw5/oatprograms/run28.oat new file mode 100644 index 0000000..25d5676 --- /dev/null +++ b/hw5/oatprograms/run28.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var i=9; + var j=i+i; + return i+i*i-j>>2<<2>>>2; +} diff --git a/hw5/oatprograms/run29.oat b/hw5/oatprograms/run29.oat new file mode 100644 index 0000000..6fb41b6 --- /dev/null +++ b/hw5/oatprograms/run29.oat @@ -0,0 +1,6 @@ +global b=true; +int program (int argc, string[] argv) { + var i=0; + if (b) { i=1; } + return i; +} diff --git a/hw5/oatprograms/run3.oat b/hw5/oatprograms/run3.oat new file mode 100644 index 0000000..3484306 --- /dev/null +++ b/hw5/oatprograms/run3.oat @@ -0,0 +1,6 @@ +global arr = int[] null; + +int program (int argc, string[] argv) { + arr = new int[] {1,2}; + return arr[1]; +} diff --git a/hw5/oatprograms/run30.oat b/hw5/oatprograms/run30.oat new file mode 100644 index 0000000..cb9983f --- /dev/null +++ b/hw5/oatprograms/run30.oat @@ -0,0 +1,4 @@ +global i=9; +int program (int argc, string[] argv) { + return i; +} diff --git a/hw5/oatprograms/run31.oat b/hw5/oatprograms/run31.oat new file mode 100644 index 0000000..c358275 --- /dev/null +++ b/hw5/oatprograms/run31.oat @@ -0,0 +1,5 @@ +global i=9; +int program (int argc, string[] argv) { + var j = i; + return j; +} diff --git a/hw5/oatprograms/run32.oat b/hw5/oatprograms/run32.oat new file mode 100644 index 0000000..ade21f7 --- /dev/null +++ b/hw5/oatprograms/run32.oat @@ -0,0 +1,12 @@ +global i=11; +int f () { + var i=12; + return i; +} +int g() { + var i=10; + return i; +} +int program (int argc, string[] argv) { + return f() + g() + i; +} diff --git a/hw5/oatprograms/run33.oat b/hw5/oatprograms/run33.oat new file mode 100644 index 0000000..7fe7413 --- /dev/null +++ b/hw5/oatprograms/run33.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var b = new bool[]{true, false}; + var i = 0; + if (b[0]) { i = 1; } + return i; +} diff --git a/hw5/oatprograms/run34.oat b/hw5/oatprograms/run34.oat new file mode 100644 index 0000000..7b187f5 --- /dev/null +++ b/hw5/oatprograms/run34.oat @@ -0,0 +1,12 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{0,1,2,3}, + new int[]{4,5,6,7}, + new int[]{8,9,10,11}}; + var s=0; + for(var i=0; i<3; i=i+1;) { + for(var j=0; j<4; j=j+1;) { + s=s+a[i][j]; + } + } + return s; +} diff --git a/hw5/oatprograms/run35.oat b/hw5/oatprograms/run35.oat new file mode 100644 index 0000000..8462f77 --- /dev/null +++ b/hw5/oatprograms/run35.oat @@ -0,0 +1,14 @@ +global a= int[][] null; + +int program (int argc, string[] argv) { + a = new int[][]{new int[]{0,1,2,3}, + new int[]{4,5,6,7}, + new int[]{8,9,10,11}}; + var s=0; + for(var i=0; i<3; i=i+1;) { + for(var j=0; j<4; j=j+1;) { + s=s+a[i][j]; + } + } + return s; +} diff --git a/hw5/oatprograms/run36.oat b/hw5/oatprograms/run36.oat new file mode 100644 index 0000000..3058e90 --- /dev/null +++ b/hw5/oatprograms/run36.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{0,0}; + return a[1]; +} diff --git a/hw5/oatprograms/run37.oat b/hw5/oatprograms/run37.oat new file mode 100644 index 0000000..221d5c6 --- /dev/null +++ b/hw5/oatprograms/run37.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return a[0][1]; +} diff --git a/hw5/oatprograms/run38.oat b/hw5/oatprograms/run38.oat new file mode 100644 index 0000000..5739949 --- /dev/null +++ b/hw5/oatprograms/run38.oat @@ -0,0 +1,12 @@ +int f1() { return f2(); } +int f2() { return f3(); } +int f3() { return f4(); } +int f4() { return f5(); } +int f5() { return f6(); } +int f6() { return f7(); } +int f7() { return f8(); } +int f8() { return f9(); } +int f9() { return 31; } +int program (int argc, string[] argv) { + return f1(); +} diff --git a/hw5/oatprograms/run39.oat b/hw5/oatprograms/run39.oat new file mode 100644 index 0000000..397da9c --- /dev/null +++ b/hw5/oatprograms/run39.oat @@ -0,0 +1,12 @@ +int f1(int i) { return f2(i); } +int f2(int i) { return f3(i); } +int f3(int i) { return f4(i); } +int f4(int i) { return f5(i); } +int f5(int i) { return f6(i); } +int f6(int i) { return f7(i); } +int f7(int i) { return f8(i); } +int f8(int i) { return f9(i); } +int f9(int i) { return i; } +int program (int argc, string[] argv) { + return f1(argc); +} diff --git a/hw5/oatprograms/run4.oat b/hw5/oatprograms/run4.oat new file mode 100644 index 0000000..77c9593 --- /dev/null +++ b/hw5/oatprograms/run4.oat @@ -0,0 +1,6 @@ +global arr = int[] null; + +int program (int argc, string[] argv) { + arr = new int[]{17,42}; + return arr[1]; +} diff --git a/hw5/oatprograms/run40.oat b/hw5/oatprograms/run40.oat new file mode 100644 index 0000000..0af7b53 --- /dev/null +++ b/hw5/oatprograms/run40.oat @@ -0,0 +1,10 @@ +global i=8; +int f() { + var j=0; + j=g(); + return j; +} +int g() {return i;} +int program(int argc, string[] argv) { + return f(); +} diff --git a/hw5/oatprograms/run41.oat b/hw5/oatprograms/run41.oat new file mode 100644 index 0000000..ce3c276 --- /dev/null +++ b/hw5/oatprograms/run41.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5+x6+x7+x8; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw5/oatprograms/run42.oat b/hw5/oatprograms/run42.oat new file mode 100644 index 0000000..b1164ce --- /dev/null +++ b/hw5/oatprograms/run42.oat @@ -0,0 +1,16 @@ +int program(int argc, string[] argv) { + var a1=new int[][3]{i->new int[1]{j->0}}; + var a2=new int[][3]{i->new int[1]{j->0}}; + var a3=new int[][3]{i->new int[1]{j->0}}; + var a4=new int[][3]{i->new int[1]{j->0}}; + var a5=new int[3]{i->i}; + a2[0] = a5; + a2[0][0] = 2; + a1 = a2; + a3 = a1; + a1 = a4; + a2 = a3; + a4 = a2; + a3 = a4; + return a3[0][0]; +} diff --git a/hw5/oatprograms/run43.oat b/hw5/oatprograms/run43.oat new file mode 100644 index 0000000..04e74a7 --- /dev/null +++ b/hw5/oatprograms/run43.oat @@ -0,0 +1,35 @@ +global a = int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] null; + +int program (int argc, string[] argv) { + a = new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][]{ + new int[][][][][][][][][][][]{ + new int[][][][][][][][][][]{ + new int[][][][][][][][][]{ + new int[][][][][][][][]{ + new int[][][][][][][]{ + new int[][][][][][]{ + new int[][][][][]{ + new int[][][][]{ + new int[][][]{ + new int[][]{ + new int[]{42}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + return a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]; +} diff --git a/hw5/oatprograms/run44.oat b/hw5/oatprograms/run44.oat new file mode 100644 index 0000000..3e3ecc6 --- /dev/null +++ b/hw5/oatprograms/run44.oat @@ -0,0 +1,18 @@ +global str = string[][][][][][][][][][] null; + +int program (int argc, string[] argv) { + str = new string[][][][][][][][][][1]{i1 -> + new string[][][][][][][][][1]{i2 -> + new string[][][][][][][][1]{i3 -> + new string[][][][][][][1]{i4 -> + new string[][][][][][1]{i5 -> + new string[][][][][1]{i6 -> + new string[][][][1]{i7 -> + new string[][][1]{i8 -> + new string[][1]{i9 -> + new string[1]{i10 -> "hello"}}}}}}}}}}; + + print_string (str[0][0][0][0][0][0][0][0][0][0]); + return 0; +} + diff --git a/hw5/oatprograms/run45.oat b/hw5/oatprograms/run45.oat new file mode 100644 index 0000000..02eade4 --- /dev/null +++ b/hw5/oatprograms/run45.oat @@ -0,0 +1,37 @@ +global a = string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] null; + + +int program (int argc, string[] argv) { + a = new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][]{ + new string[][][][][][][][][][][]{ + new string[][][][][][][][][][]{ + new string[][][][][][][][][]{ + new string[][][][][][][][]{ + new string[][][][][][][]{ + new string[][][][][][]{ + new string[][][][][]{ + new string[][][][]{ + new string[][][]{ + new string[][]{ + new string[]{"42"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + print_string (a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]); + return 0; +} diff --git a/hw5/oatprograms/run46.oat b/hw5/oatprograms/run46.oat new file mode 100644 index 0000000..12dcdf0 --- /dev/null +++ b/hw5/oatprograms/run46.oat @@ -0,0 +1,37 @@ + +int program (int argc, string[] argv) { +var a = + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][]{ + new string[][][][][][][][][][][]{ + new string[][][][][][][][][][]{ + new string[][][][][][][][][]{ + new string[][][][][][][][]{ + new string[][][][][][][]{ + new string[][][][][][]{ + new string[][][][][]{ + new string[][][][]{ + new string[][][]{ + new string[][]{ + new string[]{"42"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + + print_string (a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]); + return 0; +} diff --git a/hw5/oatprograms/run47.oat b/hw5/oatprograms/run47.oat new file mode 100644 index 0000000..c2b1032 --- /dev/null +++ b/hw5/oatprograms/run47.oat @@ -0,0 +1,11 @@ +global a = 1; + +int f() { + a = a + 1; + return a; +} + +int program (int argc, string[] argv) { + var b = new int[f()]{i -> i}; + return a + b[0] + b[1]; +} diff --git a/hw5/oatprograms/run48.oat b/hw5/oatprograms/run48.oat new file mode 100644 index 0000000..789d22a --- /dev/null +++ b/hw5/oatprograms/run48.oat @@ -0,0 +1,11 @@ +global a = 1; + +int f() { + a = a + 1; + return a; +} + +int program (int argc, string[] argv) { + var b = new int[f()]{i -> f()}; + return a + b[0] + b[1]; +} diff --git a/hw5/oatprograms/run49.oat b/hw5/oatprograms/run49.oat new file mode 100644 index 0000000..b53b94f --- /dev/null +++ b/hw5/oatprograms/run49.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + print_string ("abc"); + return 0; +} diff --git a/hw5/oatprograms/run5.oat b/hw5/oatprograms/run5.oat new file mode 100644 index 0000000..2dfbfec --- /dev/null +++ b/hw5/oatprograms/run5.oat @@ -0,0 +1,6 @@ +global arr= int[][] null; + +int program (int argc, string[] argv) { + arr = new int[][] {new int[]{1,2}, new int[]{3,4}}; + return arr[1][1]; +} diff --git a/hw5/oatprograms/run50.oat b/hw5/oatprograms/run50.oat new file mode 100644 index 0000000..3f26739 --- /dev/null +++ b/hw5/oatprograms/run50.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + print_string ("abcde"); + return 0; +} diff --git a/hw5/oatprograms/run51.oat b/hw5/oatprograms/run51.oat new file mode 100644 index 0000000..19af8e5 --- /dev/null +++ b/hw5/oatprograms/run51.oat @@ -0,0 +1,8 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5+x6+x7+x8; +} +int program (int argc, string[] argv) { + var x = f(1,2,3,4,5,-5,-4,-3); + print_int(x); + return 41; +} diff --git a/hw5/oatprograms/run52.oat b/hw5/oatprograms/run52.oat new file mode 100644 index 0000000..8347c0c --- /dev/null +++ b/hw5/oatprograms/run52.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw5/oatprograms/run53.oat b/hw5/oatprograms/run53.oat new file mode 100644 index 0000000..5e9a98d --- /dev/null +++ b/hw5/oatprograms/run53.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var str = string_of_array (new int[]{110, 110, 110}); + print_string (str); + return 0; +} diff --git a/hw5/oatprograms/run54.oat b/hw5/oatprograms/run54.oat new file mode 100644 index 0000000..238febe --- /dev/null +++ b/hw5/oatprograms/run54.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw5/oatprograms/run55.oat b/hw5/oatprograms/run55.oat new file mode 100644 index 0000000..34c756c --- /dev/null +++ b/hw5/oatprograms/run55.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw5/oatprograms/run56.oat b/hw5/oatprograms/run56.oat new file mode 100644 index 0000000..8c9daa5 --- /dev/null +++ b/hw5/oatprograms/run56.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x4; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw5/oatprograms/run6.oat b/hw5/oatprograms/run6.oat new file mode 100644 index 0000000..d30dd17 --- /dev/null +++ b/hw5/oatprograms/run6.oat @@ -0,0 +1,6 @@ +global arr= int[][] null; + +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return arr[0][0]; +} diff --git a/hw5/oatprograms/run60.oat b/hw5/oatprograms/run60.oat new file mode 100644 index 0000000..3b2d0ae --- /dev/null +++ b/hw5/oatprograms/run60.oat @@ -0,0 +1,6 @@ +global i = 3; + +int program(int argc, string[] argv) { + i = 341; + return i; +} diff --git a/hw5/oatprograms/run61.oat b/hw5/oatprograms/run61.oat new file mode 100644 index 0000000..b6b7947 --- /dev/null +++ b/hw5/oatprograms/run61.oat @@ -0,0 +1,6 @@ +global s = "341"; + +int program(int argc, string[] argv) { + print_string(s); + return 0; +} diff --git a/hw5/oatprograms/run7.oat b/hw5/oatprograms/run7.oat new file mode 100644 index 0000000..3c7afe2 --- /dev/null +++ b/hw5/oatprograms/run7.oat @@ -0,0 +1,6 @@ +global arr = int[][][] null; + +int program (int argc, string[] argv) { + arr = new int[][][]{new int[][]{new int[]{1,2}, new int[]{3,4}}, new int[][]{new int[]{5}}, new int[][]{new int[]{10,20}, new int[]{30,40}}}; + return arr[2][0][1]; +} diff --git a/hw5/oatprograms/run8.oat b/hw5/oatprograms/run8.oat new file mode 100644 index 0000000..548ca08 --- /dev/null +++ b/hw5/oatprograms/run8.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr= new int[] {1,2}; + + return arr[1]; +} diff --git a/hw5/oatprograms/run9.oat b/hw5/oatprograms/run9.oat new file mode 100644 index 0000000..197f527 --- /dev/null +++ b/hw5/oatprograms/run9.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr=new int[][] {new int []{1,2}, new int[]{3,4}}; + + return arr[1][1]; +} diff --git a/hw5/oatprograms/runtime-fail1.oat b/hw5/oatprograms/runtime-fail1.oat new file mode 100644 index 0000000..a0cdc50 --- /dev/null +++ b/hw5/oatprograms/runtime-fail1.oat @@ -0,0 +1,6 @@ +global arr = int[][] null; + +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return arr[1][3]; +} diff --git a/hw5/oatprograms/runtime-fail2.oat b/hw5/oatprograms/runtime-fail2.oat new file mode 100644 index 0000000..4d54f38 --- /dev/null +++ b/hw5/oatprograms/runtime-fail2.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{}; + return a[0]; +} diff --git a/hw5/oatprograms/runtime-fail3.oat b/hw5/oatprograms/runtime-fail3.oat new file mode 100644 index 0000000..2ad327c --- /dev/null +++ b/hw5/oatprograms/runtime-fail3.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{0,0}; + return a[-1]; +} diff --git a/hw5/oatprograms/runtime-fail4.oat b/hw5/oatprograms/runtime-fail4.oat new file mode 100644 index 0000000..5e27495 --- /dev/null +++ b/hw5/oatprograms/runtime-fail4.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{0,0}, new int[]{0,0}}; + return a[1][3]; +} diff --git a/hw5/oatprograms/selectionsort.oat b/hw5/oatprograms/selectionsort.oat new file mode 100644 index 0000000..71b9252 --- /dev/null +++ b/hw5/oatprograms/selectionsort.oat @@ -0,0 +1,38 @@ +int getminindex(int[] a, int s, int b) +{ + var i=s; + var min=a[s]; + var mi=s; + for(; i < b; i=i+1;) + { + if ( a[i] < min ) { min = a[i]; mi = i; } + } + return mi; +} + +void selectionsort(int[] a, int s) +{ + var t=0; + var mi=0; + for(var i=0; i= w | j >= h) { + return 100; + } + if (i == w-1 & j == h-1) { + dp[i][j] = matrix[i][j]; + return dp[i][j]; + } + if (dp[i][j] != 0) { + return dp[i][j]; + } + var go_down_val = shortest_path_dp(matrix, dp, i, j+1, w, h); + var go_right_val = shortest_path_dp(matrix, dp, i+1, j, w, h); + if (go_down_val < go_right_val) { + dp[i][j] = go_down_val + matrix[i][j]; + } else { + dp[i][j] = go_right_val + matrix[i][j]; + } + return dp[i][j]; +} + +int program(int argc, string[] argv) { + var matrix = new int[][5]; + for (var i = 0; i < 5; i=i+1;) { + matrix[i] = new int[5]; + } + for (var i = 0; i < 5; i=i+1;) { + for (var j = 0; j < 5; j=j+1;) { + matrix[i][j] = 2*(i+1) + (j+1); + } + } + matrix[0][4] = 50; + matrix[1][3] = 50; + matrix[2][2] = 50; + return shortest_path(matrix, 5, 5); +} \ No newline at end of file diff --git a/hw5/oatprograms/sieve.oat b/hw5/oatprograms/sieve.oat new file mode 100644 index 0000000..9f1673b --- /dev/null +++ b/hw5/oatprograms/sieve.oat @@ -0,0 +1,30 @@ +int sieve(int n) { + var arr = new bool[n]{i->false}; + for (var i=0; i < n; i=i+1;) { arr[i] = true; } + + arr[0] = false; + arr[1] = false; + + for(var i = 0; i < n; i=i+1;) { + if(arr[i]){ + for(var j = i * 2; j < n; j=j+i;){ + arr[j] = false; + } + } + } + +var count = 0; + for(var i = 0; i < n; i=i+1;){ + if(arr[i]) { + count = count + 1; + } + } + + return count; + +} + +int program(int argc, string[] argv) { + var n = 100; + return sieve(n); +} diff --git a/hw5/oatprograms/sqrt.oat b/hw5/oatprograms/sqrt.oat new file mode 100644 index 0000000..9eed049 --- /dev/null +++ b/hw5/oatprograms/sqrt.oat @@ -0,0 +1,44 @@ +global l2 = int[]{8, 9, 10, 11, 12, 13, 14, 15}; + +int sqrt (int n) { + if (n < 0) { + return 0; + } + + var s = 0; + while (n > 0) { + var d = s * s; + if (d > n) { + n = -1; + } else { + s = s + 1; + } + } + return s - 1; +} + +int sum (int[] l) { + var sum = 0; + for (var i = 0; i < 8; i = i + 1;) { + sum = sum + l[i]; + } + return sum; +} + +int program (int argc, string[] argv) { + var l1 = new int[8]; + l1[0] = 0; + l1[1] = 1; + l1[2] = 2; + l1[3] = 3; + l1[4] = 4; + l1[5] = 5; + l1[6] = 6; + l1[7] = 7; + + var s1 = sum(l1); + var s2 = sum(l2); + var s = s1 + s2; + var rt = sqrt(s); + return rt; +} \ No newline at end of file diff --git a/hw5/oatprograms/tc1.oat b/hw5/oatprograms/tc1.oat new file mode 100644 index 0000000..7d1dd22 --- /dev/null +++ b/hw5/oatprograms/tc1.oat @@ -0,0 +1 @@ +global i = true; diff --git a/hw5/oatprograms/tc10.oat b/hw5/oatprograms/tc10.oat new file mode 100644 index 0000000..82952d5 --- /dev/null +++ b/hw5/oatprograms/tc10.oat @@ -0,0 +1,3 @@ +bool f(int[] a){ + return !a; +} diff --git a/hw5/oatprograms/tc11.oat b/hw5/oatprograms/tc11.oat new file mode 100644 index 0000000..9892ac1 --- /dev/null +++ b/hw5/oatprograms/tc11.oat @@ -0,0 +1,3 @@ +int f() { + return !0; +} diff --git a/hw5/oatprograms/tc12.oat b/hw5/oatprograms/tc12.oat new file mode 100644 index 0000000..1cb5a9c --- /dev/null +++ b/hw5/oatprograms/tc12.oat @@ -0,0 +1,5 @@ +void f() {return;} +void g() { + int i = f(); + return; +} diff --git a/hw5/oatprograms/tc13.oat b/hw5/oatprograms/tc13.oat new file mode 100644 index 0000000..2cb74ea --- /dev/null +++ b/hw5/oatprograms/tc13.oat @@ -0,0 +1,6 @@ +int f() {return 0;} + +int g() { + f(); + return 0; +} diff --git a/hw5/oatprograms/tc14.oat b/hw5/oatprograms/tc14.oat new file mode 100644 index 0000000..f81d7eb --- /dev/null +++ b/hw5/oatprograms/tc14.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{"hello"}; + return 0; +} diff --git a/hw5/oatprograms/tc15.oat b/hw5/oatprograms/tc15.oat new file mode 100644 index 0000000..63751e7 --- /dev/null +++ b/hw5/oatprograms/tc15.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new string[]{1}; + return 0; +} diff --git a/hw5/oatprograms/tc16.oat b/hw5/oatprograms/tc16.oat new file mode 100644 index 0000000..0a9ee44 --- /dev/null +++ b/hw5/oatprograms/tc16.oat @@ -0,0 +1,5 @@ +int f ( int x ) { + var x = 0; + x = x + x - x * x >> x << x | x & -~!x >>> x; + return x; +} diff --git a/hw5/oatprograms/tc17.oat b/hw5/oatprograms/tc17.oat new file mode 100644 index 0000000..deb1c95 --- /dev/null +++ b/hw5/oatprograms/tc17.oat @@ -0,0 +1,4 @@ +void f() { + var x = length_of_array(3); + return; +} diff --git a/hw5/oatprograms/tc18.oat b/hw5/oatprograms/tc18.oat new file mode 100644 index 0000000..815a7ab --- /dev/null +++ b/hw5/oatprograms/tc18.oat @@ -0,0 +1,3 @@ +int g() { + return f(); +} diff --git a/hw5/oatprograms/tc19.oat b/hw5/oatprograms/tc19.oat new file mode 100644 index 0000000..92fd7f4 --- /dev/null +++ b/hw5/oatprograms/tc19.oat @@ -0,0 +1,4 @@ +int f(int x, int y) {return 0;} +int g() { + return f(0); +} diff --git a/hw5/oatprograms/tc2.oat b/hw5/oatprograms/tc2.oat new file mode 100644 index 0000000..9e21e6c --- /dev/null +++ b/hw5/oatprograms/tc2.oat @@ -0,0 +1 @@ +global a = int[] null; diff --git a/hw5/oatprograms/tc20.oat b/hw5/oatprograms/tc20.oat new file mode 100644 index 0000000..39cdb24 --- /dev/null +++ b/hw5/oatprograms/tc20.oat @@ -0,0 +1,5 @@ +void f(int x, int y) {return;} +int g() { + f(0,1,2); + return 0; +} diff --git a/hw5/oatprograms/tc3.oat b/hw5/oatprograms/tc3.oat new file mode 100644 index 0000000..eb88f43 --- /dev/null +++ b/hw5/oatprograms/tc3.oat @@ -0,0 +1,5 @@ +bool f(int a) { + var b = true; + if (a) { b=true; } else { b=false; } + return b; +} diff --git a/hw5/oatprograms/tc4.oat b/hw5/oatprograms/tc4.oat new file mode 100644 index 0000000..2aa04a5 --- /dev/null +++ b/hw5/oatprograms/tc4.oat @@ -0,0 +1,3 @@ +int f() { + return false + 1; +} diff --git a/hw5/oatprograms/tc5.oat b/hw5/oatprograms/tc5.oat new file mode 100644 index 0000000..200f638 --- /dev/null +++ b/hw5/oatprograms/tc5.oat @@ -0,0 +1,3 @@ +int f() { + return (false * true); +} diff --git a/hw5/oatprograms/tc6.oat b/hw5/oatprograms/tc6.oat new file mode 100644 index 0000000..5bf7f21 --- /dev/null +++ b/hw5/oatprograms/tc6.oat @@ -0,0 +1,3 @@ +int f(int i) {return i;} + +int g(int j) {return g(true);} diff --git a/hw5/oatprograms/tc7.oat b/hw5/oatprograms/tc7.oat new file mode 100644 index 0000000..fbf91fa --- /dev/null +++ b/hw5/oatprograms/tc7.oat @@ -0,0 +1,6 @@ +int f() {return 0;} + +int g() { + for(; f(); ){} + return 0; +} diff --git a/hw5/oatprograms/tc8.oat b/hw5/oatprograms/tc8.oat new file mode 100644 index 0000000..c290fc6 --- /dev/null +++ b/hw5/oatprograms/tc8.oat @@ -0,0 +1,5 @@ +void f() { + var a = int[]{1}; + while (a) {} + return; +} diff --git a/hw5/oatprograms/tc9.oat b/hw5/oatprograms/tc9.oat new file mode 100644 index 0000000..cfd5675 --- /dev/null +++ b/hw5/oatprograms/tc9.oat @@ -0,0 +1,4 @@ +int f() { + var a = 1; + return; +} diff --git a/hw5/oatprograms/tc_ok1.oat b/hw5/oatprograms/tc_ok1.oat new file mode 100644 index 0000000..b1642b8 --- /dev/null +++ b/hw5/oatprograms/tc_ok1.oat @@ -0,0 +1 @@ +int f (int f) {return f;} diff --git a/hw5/oatprograms/tc_ok2.oat b/hw5/oatprograms/tc_ok2.oat new file mode 100644 index 0000000..aaa2314 --- /dev/null +++ b/hw5/oatprograms/tc_ok2.oat @@ -0,0 +1 @@ +int f() {var f=0; return f;} diff --git a/hw5/oatprograms/tc_ok4.oat b/hw5/oatprograms/tc_ok4.oat new file mode 100644 index 0000000..1b7a1d3 --- /dev/null +++ b/hw5/oatprograms/tc_ok4.oat @@ -0,0 +1,5 @@ +int f() { + var i = 0; + var arr = new int[3]{j -> 0}; + return i; +} diff --git a/hw5/oatprograms/tc_ok5.oat b/hw5/oatprograms/tc_ok5.oat new file mode 100644 index 0000000..bf9c71a --- /dev/null +++ b/hw5/oatprograms/tc_ok5.oat @@ -0,0 +1,6 @@ +global i = true; + +int f() { + var i = 0; + return i; +} diff --git a/hw5/oatprograms/tc_ok6.oat b/hw5/oatprograms/tc_ok6.oat new file mode 100644 index 0000000..29b6aa2 --- /dev/null +++ b/hw5/oatprograms/tc_ok6.oat @@ -0,0 +1,27 @@ +int f() { + var i1 = 3 + 4; + var i2 = 3 * 4; + var i3 = 3 - 4; + + var b1 = 3 == 4; + var b2 = 3 != 4; + var b6 = 3 < 4; + var b7 = 3 <= 4; + var b8 = 3 > 4; + var b9 = 3 >= 4; + + var i4 = 3 [&] 4; + var b10 = true & false; + + var i5 = 3 [|] 4; + var b11 = true | false; + + var i6 = 3 << 4; + var i7 = 3 >> 4; + var i8 = 3 >>> 4; + + var i9 = - 3; + var i10 = ~ 4; + var b12 = !false; + return 0; +} diff --git a/hw5/oatprograms/tc_ok7.oat b/hw5/oatprograms/tc_ok7.oat new file mode 100644 index 0000000..40fbba1 --- /dev/null +++ b/hw5/oatprograms/tc_ok7.oat @@ -0,0 +1,7 @@ +int f() { + return g(); +} + +int g() { + return f(); +} diff --git a/hw5/oatprograms/tc_ok8.oat b/hw5/oatprograms/tc_ok8.oat new file mode 100644 index 0000000..73e78f1 --- /dev/null +++ b/hw5/oatprograms/tc_ok8.oat @@ -0,0 +1,10 @@ +int f() { + var a1 = new int[]{1, 2, 3}; + var b = new string[]{"a", "b", "c", "d"}; + var s = string_of_array(a1); + var a2 = array_of_string("abc"); + print_string("hello"); + print_int(3); + print_bool(true); + return 0; +} diff --git a/hw5/oatprograms/toascii.oat b/hw5/oatprograms/toascii.oat new file mode 100644 index 0000000..8c93026 --- /dev/null +++ b/hw5/oatprograms/toascii.oat @@ -0,0 +1,69 @@ +/* +Takes a .gim graphics file; +prints a simple ascii representation of the colors. +Optimized for light-text-on-dark-background terminals +(inverts the colors), and subsamples the height by .5 +to better maintain aspect ratio of square files. + + -- John Hewitt, CIS 341 2017sp +*/ + +int program (int argc, string[] argv) { + var s = argv[1]; + var width = get_width(s); + var height = get_height(s); + var bytes = load_image(s); + print_string(string_of_int(width)); + print_string("x"); + print_string(string_of_int(height)); + print_string("\n"); + var rowlen = 0; + var row = new int[width]; + var off = 1; + for (var i=0; i < width*height; i=i+1;) { + /*print_string(string_of_int(i)); + print_string("x"); + print_string(string_of_int(rowlen)); + print_string("x"); + print_string(string_of_int(width)); + print_string("x"); + print_string(string_of_int(bytes[i])); + print_string("\n");*/ + if (bytes[i] > 230) { + row[rowlen] = 64; /* @ */ + } else if (bytes[i] > 204) { + row[rowlen] = 37; /* % */ + } else if (bytes[i] > 179) { + row[rowlen] = 35; /* # */ + } else if (bytes[i] > 153) { + row[rowlen] = 42; /* * */ + } else if (bytes[i] > 128) { + row[rowlen] = 43; /* + */ + } else if (bytes[i] > 102) { + row[rowlen] = 61; /* = */ + } else if (bytes[i] > 77) { + row[rowlen] = 58; /* : */ + } else if (bytes[i] > 51) { + row[rowlen] = 45; /* - */ + } else if (bytes[i] > 26) { + row[rowlen] = 46; /* . */ + } else { + row[rowlen] = 32; /* */ + } + if (rowlen == width-1) { + var test = off [&] 1; + if (test == 1) { + print_string(string_of_array(row)); + print_string("\n"); + off = 0; + + } else { + off = 1; + } + rowlen = 0; + } else { + rowlen = rowlen + 1; + } + } + return 0; +} diff --git a/hw5/oatprograms/toposort.oat b/hw5/oatprograms/toposort.oat new file mode 100644 index 0000000..20b2245 --- /dev/null +++ b/hw5/oatprograms/toposort.oat @@ -0,0 +1,54 @@ +/* Sumit Shyamsukha (ssumit) and Robert Zajac (rzajac) */ +/* CIS341 Spring 2017 */ + +/* 0 is white, 1 is gray, 2 is black */ +global color = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global startTimes = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global finishTimes = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global topoSort = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global numVertices = 16; +global index = 15; + +void dfs(int[][] adj) { + + for (var i = 0; i < numVertices; i=i+1;) { + if (color[i] == 0) { + dfsHelper(adj, i, 0); + } + } + return; +} + +void dfsHelper(int[][] adj, int s, int t) { + color[s] = 1; + startTimes[s] = t; + + var stringRep = string_of_array(adj[s]); + var length = length_of_string(stringRep); + + for (var i = 0; i < length; i=i+1;) { + var neighbor = adj[s][i]; + if (color[neighbor] == 0) { + dfsHelper(adj, neighbor, t + 1); + } + } + + color[s] = 2; + finishTimes[s] = t + 1; + topoSort[index] = s; + index = index - 1; + + return; +} + +int program(int argc, string[] argv) { + /* Graph taken from https://i.stack.imgur.com/zuLmn.png */ + var adjList = new int[][]{new int[]{7, 10, 13, 14}, new int[]{2, 9, 13}, new int[]{10, 12, 13, 14}, new int[]{6, 8, 9, 11}, new int[]{7}, new int[]{6, 7, 9, 10}, new int[]{15}, new int[]{14}, new int[]{15}, new int[]{11, 14}, new int[]{14}, new int[]{}, new int[]{}, new int[]{}, new int[]{}, new int[]{}}; + dfs(adjList); + for (var i = 0; i < numVertices; i=i+1;) { + print_int(topoSort[i]); + print_string (" "); + } + print_string ("-"); + return 0; +} \ No newline at end of file diff --git a/hw5/oatprograms/union_find.oat b/hw5/oatprograms/union_find.oat new file mode 100644 index 0000000..c550a9e --- /dev/null +++ b/hw5/oatprograms/union_find.oat @@ -0,0 +1,58 @@ +int[] create_ufind(int len) +{ + var arr = new int[len]; + for(var i = 0; i < len; i = i + 1;) + { + arr[i] = i; + } + return arr; + +} + +void union(int[] comps, int u, int v) +{ + var cU = find(comps, u); + var cV = find(comps, v); + + if(cU == cV) + { + return; + } + + comps[cU] = cV; + return; +} + +int find(int[] comps, int u) +{ + var root = u; + while(root != comps[root]) + { + root = comps[root]; + } + + while(u != root) + { + var parent = comps[u]; + comps[u] = root; + u = parent; + + } + + return root; + +} + +int program (int argc, string[] argv) { + var uf = create_ufind(8); + union(uf, 0, 7); + union(uf, 1, 6); + union(uf, 2, 5); + union(uf, 5, 0); + + for(var i = 0; i < 8; i = i + 1;){ + print_int(find(uf, i)); + print_string(" "); + } + return 0; +} diff --git a/hw5/oatprograms/xor_bool.oat b/hw5/oatprograms/xor_bool.oat new file mode 100644 index 0000000..d8b6b5c --- /dev/null +++ b/hw5/oatprograms/xor_bool.oat @@ -0,0 +1,17 @@ +bool xor(bool x, bool y) { + return (x & !y) | (!x & y); +} + +int to_int(bool b) { + if (b) { + return 1; + } else { + return 0; + } +} + +int program(int argc, string[] argv) { + var t = true; + var f = false; + return to_int(xor(t, t)); +} \ No newline at end of file diff --git a/hw5/oatprograms/xor_shift.oat b/hw5/oatprograms/xor_shift.oat new file mode 100644 index 0000000..7d08dae --- /dev/null +++ b/hw5/oatprograms/xor_shift.oat @@ -0,0 +1,27 @@ +int xor (int x, int y) { + return ~(x [&] y) [&] (x [|] y); +} + +int xor_shift_plus (int[] s) { + var x = s[0]; + var y = s[1]; + + s[0] = y; + x = xor(x, x << 23); + x = xor(x, x >> 17); + x = xor(x, xor(y, y >> 26)); + s[1] = x; + + return x + y; +} + +int program (int argc, string[] argv) { + var seed = new int[2]{i->0}; + for (var i=0; i < 2; i=i+1;) { seed[i] = 100 * (i + 1); } + + print_int(xor_shift_plus(seed)); + print_string("\n"); + print_int(xor_shift_plus(seed)); + + return 0; +} \ No newline at end of file diff --git a/hw5/parser.mly b/hw5/parser.mly new file mode 100644 index 0000000..2036fc7 --- /dev/null +++ b/hw5/parser.mly @@ -0,0 +1,239 @@ +%{ +open Ast + +let loc (startpos:Lexing.position) (endpos:Lexing.position) (elt:'a) : 'a node = + { elt ; loc=Range.mk_lex_range startpos endpos } + +%} + +/* Declare your tokens here. */ +%token EOF +%token INT +%token NULL +%token STRING +%token IDENT +%token UIDENT + +%token TINT /* int */ +%token TVOID /* void */ +%token TSTRING /* string */ +%token IF /* if */ +%token IFQ /* if? */ +%token ELSE /* else */ +%token WHILE /* while */ +%token RETURN /* return */ +%token VAR /* var */ +%token STRUCT /* struct */ +%token SEMI /* ; */ +%token COMMA /* , */ +%token LBRACE /* { */ +%token RBRACE /* } */ +%token PLUS /* + */ +%token DASH /* - */ +%token STAR /* * */ +%token EQEQ /* == */ +%token EQ /* = */ +%token LPAREN /* ( */ +%token RPAREN /* ) */ +%token LBRACKET /* [ */ +%token RBRACKET /* ] */ +%token TILDE /* ~ */ +%token BANG /* ! */ +%token GLOBAL /* global */ +%token FOR /* for */ +%token TBOOL /* bool */ +%token LENGTH +%token TRUE +%token FALSE +%token DOT /* . */ +%token NEW /* new */ +%token GT /* > */ +%token GTEQ /* >= */ +%token LT /* < */ +%token LTEQ /* <= */ +%token BANGEQ /* != */ +%token BAR /* | */ +%token AMPER /* & */ +%token IOR /* [|] */ +%token IAND /* [&] */ +%token LTLT /* << */ +%token GTGT /* >> */ +%token GTGTGT /* >>> */ +%token ARROW /* -> */ +%token QUESTION /* ? */ + +%left IOR +%left IAND +%left BAR +%left AMPER +%left EQEQ BANGEQ +%left LT LTEQ GT GTEQ +%left LTLT GTGTGT GTGT +%left PLUS DASH +%left STAR +%left DOT +%nonassoc LOW +%nonassoc QUESTION +%nonassoc BANG +%nonassoc TILDE +%nonassoc LBRACKET +%nonassoc LPAREN + +/* ---------------------------------------------------------------------- */ + +%start prog +%start exp_top +%start stmt_top +%type exp_top +%type stmt_top + +%type prog +%type exp +%type stmt +%type block +%type ty +%% + +exp_top: + | e=exp EOF { e } + +stmt_top: + | s=stmt EOF { s } + +prog: + | p=list(decl) EOF { p } + +decl: + | GLOBAL name=IDENT EQ init=gexp SEMI + { Gvdecl (loc $startpos $endpos { name; init }) } + | frtyp=ret_ty fname=IDENT LPAREN args=arglist RPAREN body=block + { Gfdecl (loc $startpos $endpos { frtyp; fname; args; body }) } + | STRUCT name=UIDENT LBRACE fs=separated_list(SEMI, decl_field) RBRACE + { Gtdecl (loc $startpos $endpos (name, fs)) } + +decl_field: + | t=ty id=IDENT { { fieldName=id; ftyp=t } } + +arglist: + | l=separated_list(COMMA, pair(ty,IDENT)) { l } + +ty: + | TINT { TInt } + | r=rtyp { TRef r } %prec LOW + | r=rtyp QUESTION { TNullRef r } + | LPAREN t=ty RPAREN { t } + | TBOOL { TBool } + +%inline ret_ty: + | TVOID { RetVoid } + | t=ty { RetVal t } + +%inline rtyp: + | TSTRING { RString } + | t=ty LBRACKET RBRACKET { RArray t } + | id=UIDENT { RStruct id } + | LPAREN RPAREN ARROW ret=ret_ty { RFun ([], ret) } + | LPAREN t=ty RPAREN ARROW ret=ret_ty { RFun ([t], ret) } + | LPAREN t=ty COMMA l=separated_list(COMMA, ty) RPAREN ARROW ret=ret_ty + { RFun (t :: l, ret) } + +%inline bop: + | PLUS { Add } + | DASH { Sub } + | STAR { Mul } + | EQEQ { Eq } + | BANGEQ { Neq } + | LT { Lt } + | LTEQ { Lte } + | GT { Gt } + | GTEQ { Gte } + | AMPER { And } + | BAR { Or } + | IAND { IAnd } + | IOR { IOr } + | LTLT { Shl } + | GTGT { Shr } + | GTGTGT { Sar } + +%inline uop: + | DASH { Neg } + | BANG { Lognot } + | TILDE { Bitnot } + +gexp: + | r=rtyp NULL{ loc $startpos $endpos @@ CNull r } + | TRUE { loc $startpos $endpos @@ CBool true } + | FALSE { loc $startpos $endpos @@ CBool false } + | i=INT { loc $startpos $endpos @@ CInt i } + | s=STRING { loc $startpos $endpos @@ CStr s } + | NEW t=ty LBRACKET RBRACKET LBRACE cs=separated_list(COMMA, gexp) RBRACE + { loc $startpos $endpos @@ CArr (t, cs) } + | NEW i=UIDENT LBRACE fs=separated_list(SEMI, gfield) RBRACE + { loc $startpos $endpos @@ CStruct (i, fs) } + | id=IDENT {loc $startpos $endpos @@ Id id } + +gfield: + | id=IDENT EQ e=gexp { (id, e) } + +lhs: + | id=IDENT { loc $startpos $endpos @@ Id id } + | e=exp LBRACKET i=exp RBRACKET + { loc $startpos $endpos @@ Index (e, i) } + | e=exp DOT id=IDENT { loc $startpos $endpos @@ Proj (e, id) } + +exp: + | r=rtyp NULL { loc $startpos $endpos @@ CNull r } + | TRUE { loc $startpos $endpos @@ CBool true } + | FALSE { loc $startpos $endpos @@ CBool false } + | i=INT { loc $startpos $endpos @@ CInt i } + | s=STRING { loc $startpos $endpos @@ CStr s } + | NEW t=ty LBRACKET RBRACKET LBRACE cs=separated_list(COMMA, exp) RBRACE + { loc $startpos $endpos @@ CArr (t, cs) } + | NEW t=UIDENT LBRACE cs=separated_list(SEMI, field) RBRACE + { loc $startpos $endpos @@ CStruct(t, cs) } + | e=exp DOT id=IDENT { loc $startpos $endpos @@ Proj(e, id) } + | NEW t=ty LBRACKET e1=exp RBRACKET LBRACE u=IDENT ARROW e2=exp RBRACE + { loc $startpos $endpos @@ NewArr(t, e1, u, e2) } + | id=IDENT { loc $startpos $endpos @@ Id id } + | e=exp LBRACKET i=exp RBRACKET + { loc $startpos $endpos @@ Index (e, i) } + | e=exp LPAREN es=separated_list(COMMA, exp) RPAREN + { loc $startpos $endpos @@ Call (e,es) } + | e1=exp b=bop e2=exp { loc $startpos $endpos @@ Bop (b, e1, e2) } + | u=uop e=exp { loc $startpos $endpos @@ Uop (u, e) } + | LENGTH LPAREN e=exp RPAREN + { loc $startpos $endpos @@ Length(e) } + | LPAREN e=exp RPAREN { e } + +field: + | id=IDENT EQ e=exp { (id, e) } + +vdecl: + | VAR id=IDENT EQ init=exp { (id, init) } + +stmt: + | d=vdecl SEMI { loc $startpos $endpos @@ Decl(d) } + | p=lhs EQ e=exp SEMI { loc $startpos $endpos @@ Assn(p,e) } + | e=exp LPAREN es=separated_list(COMMA, exp) RPAREN SEMI + { loc $startpos $endpos @@ SCall (e, es) } + | ifs=if_stmt { ifs } + | RETURN SEMI { loc $startpos $endpos @@ Ret(None) } + | RETURN e=exp SEMI { loc $startpos $endpos @@ Ret(Some e) } + | WHILE LPAREN e=exp RPAREN b=block + { loc $startpos $endpos @@ While(e, b) } + | FOR LPAREN ds=separated_list(COMMA, vdecl) SEMI e=exp? SEMI s=stmt? RPAREN b=block + { loc $startpos $endpos @@ For(ds,e,s,b) } + +block: + | LBRACE stmts=list(stmt) RBRACE { stmts } + +if_stmt: + | IF LPAREN e=exp RPAREN b1=block b2=else_stmt + { loc $startpos $endpos @@ If(e,b1,b2) } + | IFQ LPAREN r=rtyp id=IDENT EQ e=exp RPAREN b1=block b2=else_stmt + { loc $startpos $endpos @@ Cast(r, id, e, b1, b2) } + +else_stmt: + | (* empty *) { [] } + | ELSE b=block { b } + | ELSE ifs=if_stmt { [ ifs ] } diff --git a/hw5/runtime.c b/hw5/runtime.c new file mode 100644 index 0000000..d1b32af --- /dev/null +++ b/hw5/runtime.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include + +/* Oat Internal Functions --------------------------------------------------- */ + +int64_t* oat_malloc(int64_t size) { + return (int64_t*)calloc(size, sizeof(char)); +} + +int64_t* oat_alloc_array (int64_t size) { + assert (size >= 0); + int64_t *arr = (int64_t*)malloc(sizeof(int64_t) * (size+1)); + arr[0] = size; + return arr; +} + +void oat_assert_not_null (int8_t* ptr) { + if (ptr == NULL) { + fprintf(stderr, "Attempted to dereference null pointer"); + exit(1); + } +} + +void oat_assert_array_length (int64_t *array, int64_t ind) { + if (array == NULL) { + fprintf(stderr, "Attempted to index null array"); + exit(1); + } else if ((ind < 0) || (*array <= ind)) { + fprintf(stderr, "Out of bounds index %ld for array length %ld", + (long)ind, (long)*array); + exit(1); + } +} + + +/* Oat Builtin Functions ---------------------------------------------------- */ + +int64_t* array_of_string (char *str) { + int64_t len, i, *arr; + + assert (NULL != str); + + len = strlen(str); + assert (len >= 0); + + arr = (int64_t*)malloc(sizeof(int64_t) * (len+1)); + arr[0] = len; + for (i=0; i= 0); + + str = malloc(sizeof(char) * (len+1)); + + for (i=0; i None + +(* globals ------------------------------------------------------------------ *) +let add_global (c:t) (id:id) (bnd:Ast.ty) : t = {c with globals = (id, bnd)::c.globals} +let lookup_global (id : Ast.id) (c : t) : Ast.ty = List.assoc id c.globals +let lookup_global_option id c : Ast.ty option = + try Some (List.assoc id c.globals) with Not_found -> None + +(* general-purpose lookup: for local _or_ global *) +let lookup id c : Ast.ty = + match lookup_local_option id c with + | None -> lookup_global id c + | Some x -> x + +let lookup_option id c : Ast.ty option = + match lookup_local_option id c with + | None -> lookup_global_option id c + | Some x -> Some x + + +(* structures --------------------------------------------------------------- *) +let add_struct c id bnd = {c with structs=(id, bnd)::c.structs} +let lookup_struct id c = List.assoc id c.structs + +let lookup_struct_option id c = + try Some (lookup_struct id c) with Not_found -> None + +let lookup_field_option st_name f_name c = + let rec lookup_field_aux f_name l = + match l with + | [] -> None + | h :: t -> if h.fieldName = f_name then Some h.ftyp else lookup_field_aux f_name t in + match lookup_struct_option st_name c with + | None -> None + | Some x -> lookup_field_aux f_name x + +let lookup_field st_name f_name c = + match lookup_field_option st_name f_name c with + | None -> failwith "StructCtxt.lookup_field: Not found" + | Some x -> x diff --git a/hw5/team.txt b/hw5/team.txt new file mode 100644 index 0000000..e69de29 diff --git a/hw5/typechecker.ml b/hw5/typechecker.ml new file mode 100644 index 0000000..d18718f --- /dev/null +++ b/hw5/typechecker.ml @@ -0,0 +1,214 @@ +open Ast +open Astlib +open Tctxt + +(* Error Reporting ---------------------------------------------------------- *) +(* NOTE: Use type_error to report error messages for ill-typed programs. *) + +exception TypeError of string + +let type_error (l : 'a node) err = + let (_, (s, e), _) = l.loc in + raise (TypeError (Printf.sprintf "[%d, %d] %s" s e err)) + + +(* initial context: G0 ------------------------------------------------------ *) +(* The Oat types of the Oat built-in functions *) +let builtins = + [ "array_of_string", ([TRef RString], RetVal (TRef(RArray TInt))) + ; "string_of_array", ([TRef(RArray TInt)], RetVal (TRef RString)) + ; "length_of_string", ([TRef RString], RetVal TInt) + ; "string_of_int", ([TInt], RetVal (TRef RString)) + ; "string_cat", ([TRef RString; TRef RString], RetVal (TRef RString)) + ; "print_string", ([TRef RString], RetVoid) + ; "print_int", ([TInt], RetVoid) + ; "print_bool", ([TBool], RetVoid) + ] + +(* binary operation types --------------------------------------------------- *) +let typ_of_binop : Ast.binop -> Ast.ty * Ast.ty * Ast.ty = function + | Add | Mul | Sub | Shl | Shr | Sar | IAnd | IOr -> (TInt, TInt, TInt) + | Lt | Lte | Gt | Gte -> (TInt, TInt, TBool) + | And | Or -> (TBool, TBool, TBool) + | Eq | Neq -> failwith "typ_of_binop called on polymorphic == or !=" + +(* unary operation types ---------------------------------------------------- *) +let typ_of_unop : Ast.unop -> Ast.ty * Ast.ty = function + | Neg | Bitnot -> (TInt, TInt) + | Lognot -> (TBool, TBool) + +(* subtyping ---------------------------------------------------------------- *) +(* Decides whether H |- t1 <: t2 + - assumes that H contains the declarations of all the possible struct types + + - you will want to introduce addition (possibly mutually recursive) + helper functions to implement the different judgments of the subtyping + relation. We have included a template for subtype_ref to get you started. + (Don't forget about OCaml's 'and' keyword.) +*) +let rec subtype (c : Tctxt.t) (t1 : Ast.ty) (t2 : Ast.ty) : bool = + failwith "todo: subtype" + +(* Decides whether H |-r ref1 <: ref2 *) +and subtype_ref (c : Tctxt.t) (t1 : Ast.rty) (t2 : Ast.rty) : bool = + failwith "todo: subtype_ref" + + +(* well-formed types -------------------------------------------------------- *) +(* Implement a (set of) functions that check that types are well formed according + to the H |- t and related inference rules + + - the function should succeed by returning () if the type is well-formed + according to the rules + + - the function should fail using the "type_error" helper function if the + type is not well-formed + + - l is just an ast node that provides source location information for + generating error messages (it's only needed for the type_error generation) + + - tc contains the structure definition context + *) +let rec typecheck_ty (l : 'a Ast.node) (tc : Tctxt.t) (t : Ast.ty) : unit = + failwith "todo: implement typecheck_ty" + +(* typechecking expressions ------------------------------------------------- *) +(* Typechecks an expression in the typing context c, returns the type of the + expression. This function should implement the inference rules given in the + oad.pdf specification. There, they are written: + + H; G; L |- exp : t + + See tctxt.ml for the implementation of the context c, which represents the + four typing contexts: H - for structure definitions G - for global + identifiers L - for local identifiers + + Returns the (most precise) type for the expression, if it is type correct + according to the inference rules. + + Uses the type_error function to indicate a (useful!) error message if the + expression is not type correct. The exact wording of the error message is + not important, but the fact that the error is raised, is important. (Our + tests also do not check the location information associated with the error.) + + Notes: - Structure values permit the programmer to write the fields in any + order (compared with the structure definition). This means that, given the + declaration struct T { a:int; b:int; c:int } The expression new T {b=3; c=4; + a=1} is well typed. (You should sort the fields to compare them.) + +*) +let rec typecheck_exp (c : Tctxt.t) (e : Ast.exp node) : Ast.ty = + failwith "todo: implement typecheck_exp" + +(* statements --------------------------------------------------------------- *) + +(* Typecheck a statement + This function should implement the statement typechecking rules from oat.pdf. + + Inputs: + - tc: the type context + - s: the statement node + - to_ret: the desired return type (from the function declaration) + + Returns: + - the new type context (which includes newly declared variables in scope + after this statement + - A boolean indicating the return behavior of a statement: + false: might not return + true: definitely returns + + in the branching statements, both branches must definitely return + + Intuitively: if one of the two branches of a conditional does not + contain a return statement, then the entier conditional statement might + not return. + + looping constructs never definitely return + + Uses the type_error function to indicate a (useful!) error message if the + statement is not type correct. The exact wording of the error message is + not important, but the fact that the error is raised, is important. (Our + tests also do not check the location information associated with the error.) + + - You will probably find it convenient to add a helper function that implements the + block typecheck rules. +*) +let rec typecheck_stmt (tc : Tctxt.t) (s:Ast.stmt node) (to_ret:ret_ty) : Tctxt.t * bool = + failwith "todo: implement typecheck_stmt" + + +(* struct type declarations ------------------------------------------------- *) +(* Here is an example of how to implement the TYP_TDECLOK rule, which is + is needed elswhere in the type system. + *) + +(* Helper function to look for duplicate field names *) +let rec check_dups fs = + match fs with + | [] -> false + | h :: t -> (List.exists (fun x -> x.fieldName = h.fieldName) t) || check_dups t + +let typecheck_tdecl (tc : Tctxt.t) id fs (l : 'a Ast.node) : unit = + if check_dups fs + then type_error l ("Repeated fields in " ^ id) + else List.iter (fun f -> typecheck_ty l tc f.ftyp) fs + +(* function declarations ---------------------------------------------------- *) +(* typecheck a function declaration + - extends the local context with the types of the formal parameters to the + function + - typechecks the body of the function (passing in the expected return type + - checks that the function actually returns +*) +let typecheck_fdecl (tc : Tctxt.t) (f : Ast.fdecl) (l : 'a Ast.node) : unit = + failwith "todo: typecheck_fdecl" + +(* creating the typchecking context ----------------------------------------- *) + +(* The following functions correspond to the + judgments that create the global typechecking context. + + create_struct_ctxt: - adds all the struct types to the struct 'H' + context (checking to see that there are no duplicate fields + + H |-s prog ==> H' + + + create_function_ctxt: - adds the the function identifiers and their + types to the 'G' context (ensuring that there are no redeclared + function identifiers) + + H ; G1 |-f prog ==> G2 + + + create_global_ctxt: - typechecks the global initializers and adds + their identifiers to the 'G' global context + + H ; G1 |-g prog ==> G2 + + + NOTE: global initializers may mention function identifiers as + constants, but can't mention other global values *) + +let create_struct_ctxt (p:Ast.prog) : Tctxt.t = + failwith "todo: create_struct_ctxt" + +let create_function_ctxt (tc:Tctxt.t) (p:Ast.prog) : Tctxt.t = + failwith "todo: create_function_ctxt" + +let create_global_ctxt (tc:Tctxt.t) (p:Ast.prog) : Tctxt.t = + failwith "todo: create_function_ctxt" + + +(* This function implements the |- prog and the H ; G |- prog + rules of the oat.pdf specification. +*) +let typecheck_program (p:Ast.prog) : unit = + let sc = create_struct_ctxt p in + let fc = create_function_ctxt sc p in + let tc = create_global_ctxt fc p in + List.iter (fun p -> + match p with + | Gfdecl ({elt=f} as l) -> typecheck_fdecl tc f l + | Gtdecl ({elt=(id, fs)} as l) -> typecheck_tdecl tc id fs l + | _ -> ()) p diff --git a/hw5/util/assert.ml b/hw5/util/assert.ml new file mode 100644 index 0000000..6789b43 --- /dev/null +++ b/hw5/util/assert.ml @@ -0,0 +1,160 @@ +(* This code is mostly based on a course held at *) +(* University of Pennsylvania (CIS341) by Steve Zdancewic. *) + +(* Author: Steve Zdancewic *) +(* Modified by: Manuel Rigger *) +(* Modified by: Yann Girsberger *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + + + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = (unit -> unit) + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = (assertion test) list + + +(**************) +(* Assertions *) +exception Timeout + +let timeout_assert (time : int) (a : assertion) : assertion = + fun () -> + let handler = Sys.Signal_handle (fun _ -> raise Timeout) in + let old = Sys.signal Sys.sigalrm handler in + let reset_sigalrm () = Sys.set_signal Sys.sigalrm old in + ignore (Unix.alarm time); + try begin a (); reset_sigalrm () end + with Timeout -> reset_sigalrm (); failwith @@ Printf.sprintf "Timed out after %d seconds" time + | exc -> reset_sigalrm (); raise exc + +let timeout_test (time : int) (t : assertion test) : assertion test = + let map_timeout l = List.map (fun (i, a) -> (i, timeout_assert time a)) l in + match t with + | GradedTest (s, i, ls) -> GradedTest (s, i, map_timeout ls) + | Test (s, ls) -> Test (s, map_timeout ls) + +let timeout_suite (time : int) (s : suite) : suite = + List.map (timeout_test time) s + +let timeout_assert_const (a: assertion) : assertion = + timeout_assert 10 a + +let assert_eq v1 v2 : assertion = + timeout_assert_const (fun () -> if v1 <> v2 then failwith "not equal" else ()) + +let assert_eqf f v2 : assertion = + timeout_assert_const (fun () -> if (f ()) <> v2 then failwith "not equal" else ()) + +let assert_eqfs f v2 : assertion = + timeout_assert_const (fun () -> + let s1 = f () in + if s1 <> v2 then failwith @@ Printf.sprintf "not equal\n\texpected:%s\n\tgot:%s\n" v2 s1 + else ()) + + +let assert_fail : assertion = fun () -> failwith "assert fail" + + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = (result test) list + +let run_assertion (f:assertion) : result = + try + f (); + Pass + with + | Failure m -> Fail m + | e -> Fail ("test threw exception: " ^ (Printexc.to_string e)) + +let run_test (t:assertion test) : result test = + let run_case (cn, f) = (cn, run_assertion f) in + begin match t with + | GradedTest (n,s,cases) -> + Printf.eprintf "Running test %s\n%!" n; + GradedTest(n,s,List.map run_case cases) + + | Test (n, cases) -> + Printf.eprintf "Running test %s\n%!" n; + Test(n, List.map run_case cases) + end + +let run_suite (s:suite):outcome = + List.map run_test s + + + + + +(***********************) +(* Reporting functions *) + +let result_test_to_string (name_pts:string) (r:result test): string = + let string_of_case (name, res) = + begin match res with + | Pass -> "passed - " ^ name + | Fail msg -> "FAILED - " ^ name ^ ": " ^ msg + end + in + begin match r with + | GradedTest (_, _, cases) + | Test (_, cases) -> + name_pts ^ + (List.fold_left (fun rest -> fun case -> rest ^ "\n" ^ (string_of_case case)) "" cases) + end + +(* returns (name_pts, passed, failed, total, points_earned, max_given, max_hidden) *) +let get_results (t:result test) = + let num_passed cases = + List.fold_left (fun cnt (_,r) -> match r with Pass -> cnt + 1 | _ -> cnt) 0 cases in + let num_failed cases = + List.fold_left (fun cnt (_,r) -> match r with Fail _ -> cnt + 1 | _ -> cnt) 0 cases in + begin match t with + | GradedTest (name,pts,cases) -> + let passed = num_passed cases in + let failed = num_failed cases in + let total = List.length cases in + if total > 0 then + let points_earned = ((float_of_int passed) /. (float_of_int total)) *. (float_of_int pts) in + let name_pts = Printf.sprintf "%s (%1.f/%d points)" name points_earned pts in + (name_pts, passed, failed, total, points_earned, pts, 0) + else + let name_pts = Printf.sprintf "%s (?/%d points)" name pts in + (name_pts, passed, failed, total, 0.0, 0, pts) + | Test(name, cases) -> + let total = List.length cases in + let passed = num_passed cases in + let failed = num_failed cases in + (name, passed, failed, total, 0.0, 0, 0) + end + +let outcome_to_string (o:outcome):string = + let sep = "\n---------------------------------------------------\n" in + let helper (passed, failed, total, pts, maxg, maxh, str) (t:result test) = + let (name_pts, p, f, tot, s, mg, mh) = get_results t in + (passed + p, failed + f, total + tot, s +. pts, maxg + mg, maxh + mh, + str ^ "\n" ^ ( + if f > 0 then (result_test_to_string name_pts t) else + if tot > 0 then (name_pts ^ ":\n OK") else + (name_pts ^ ":\n Hidden") + ) + ) in + let (p,f,tot,pts,maxg, maxh,str) = List.fold_left helper (0,0,0,0.0,0,0,"") o in + str ^ sep ^ (Printf.sprintf "Passed: %d/%d\nFailed: %d/%d\nScore: %1.f/%d (given)\n ?/%d (hidden)" p tot f tot pts maxg maxh) + + + + diff --git a/hw5/util/assert.mli b/hw5/util/assert.mli new file mode 100644 index 0000000..6b53684 --- /dev/null +++ b/hw5/util/assert.mli @@ -0,0 +1,51 @@ +(* CIS341 Assertion Testing and Grading Infrastructure *) +(* Author: Steve Zdancewic *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +exception Timeout + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = (unit -> unit) + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = (assertion test) list + + +(**************) +(* Assertions *) + +val assert_eq : 'a -> 'a -> assertion +val assert_eqf : (unit -> 'a) -> 'a -> assertion +val assert_eqfs : (unit -> string) -> string -> assertion +val assert_fail : assertion + +val timeout_assert : int -> assertion -> assertion +val timeout_test : int -> assertion test -> assertion test +val timeout_suite : int -> suite -> suite + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = (result test) list + +val run_assertion : assertion -> result +val run_test : assertion test -> result test +val run_suite : suite -> outcome + +(***********************) +(* Reporting functions *) + +val result_test_to_string : string -> result test -> string + +(* val get_results result test -> (string * int * int * int * float * int * int) *) +val outcome_to_string :outcome -> string diff --git a/hw5/util/platform.ml b/hw5/util/platform.ml new file mode 100644 index 0000000..807c27b --- /dev/null +++ b/hw5/util/platform.ml @@ -0,0 +1,156 @@ +(* -------------------------------------------------------------------------- *) +(** Assembling and linking for X86. Depends on the underlying OS platform *) + + +open Printf +open Unix + +exception PlatformError of string * string + + +(* paths -------------------------------------------------------------------- *) +let path_sep = "/" +let dot_path = "./" +let output_path = ref "output" +let libs = ref [] +let lib_paths = ref [] +let lib_search_paths = ref [] +let include_paths = ref [] +let executable_name = ref "a.out" + +(* unix utility scripts ----------------------------------------------------- *) +let pp_cmd = ref "cpp -E " +let rm_cmd = ref "rm -rf " + + +(* -------------------------------------------------------------------------- *) +(* Platform specific configuration: Unix/Linux vs. Mac OS X *) + +let os = + let ic = Unix.open_process_in "uname -s" in + let uname = input_line ic in + let () = close_in ic in + uname (* One of "Darwin" or "Linux" *) + + +let linux = ref false +let mangle name = if !linux then name else ("_" ^ name) + +let osx_target_triple = "x86_64-apple-macosx10.13.0" +let linux_target_triple = "x86_64-unknown-linux" +let target_triple = ref osx_target_triple +let platform_flags = ref "" + + +(* Set the link commands properly, ensure output directory exists *) +let configure_os () = + if os = "Linux" then + begin + linux := true; + target_triple := linux_target_triple; + platform_flags := "" + end + else + if os = "Darwin" then + begin + linux := false; + target_triple := osx_target_triple; + platform_flags := "-fno-asynchronous-unwind-tables -mstackrealign" + end + else + failwith @@ "Unsupported OS detected: " ^ os + +(* verbose compiler output -------------------------------------------------- *) +let verbose = ref false +let verb msg = (if !verbose then (print_string msg; flush Stdlib.stdout)) + +let verb_os () = + verb @@ Printf.sprintf "* PLATFORM: %s TRIPLE: %s FLAGS %s\n" + os !target_triple !platform_flags + +let enable_verbose () = + verbose := true; + verb_os () + +(* create the output directory, which is assumed to exist *) +let create_output_dir () = + try ignore (stat !output_path) + with Unix_error (ENOENT,_,_) -> + (verb @@ Printf.sprintf "creating output directory: %s\n" !output_path); + mkdir !output_path 0o755 + + +(* clang invocation stuff --------------------------------------------------- *) +let common_flags = "-Wno-override-module" +let clang_ll_mode = "-S" +let as_mode = "-c" +let opt_level = ref "-O1 -Wall" +let clang args = + Printf.sprintf "clang %s -o " (String.concat " " args) + +let clang_cmd () = clang [clang_ll_mode; !opt_level; common_flags; !platform_flags] +let as_cmd () = clang [as_mode; !opt_level; common_flags; !platform_flags] +let link_cmd () = clang [common_flags; !opt_level; !platform_flags] + + +(* filename munging --------------------------------------------------------- *) +let path_to_basename_ext (path:string) : string * string = + (* The path is of the form ... "foo/bar/baz/.ext" *) + let paths = Str.split (Str.regexp_string path_sep) path in + let _ = if (List.length paths) = 0 then failwith @@ sprintf "bad path: %s" path in + let filename = List.hd (List.rev paths) in + match Str.split (Str.regexp_string ".") filename with + | [root] -> root, "" + | [root; ext] -> root, ext + | _ -> failwith @@ sprintf "bad filename: %s" filename + + +(* compilation and shell commands-------------------------------------------- *) + +(* Platform independent shell command *) +let sh (cmd:string) (ret:string -> int -> 'a) : 'a = + verb (sprintf "* %s\n" cmd); + match (system cmd) with + | WEXITED i -> ret cmd i + | WSIGNALED i -> raise (PlatformError (cmd, sprintf "Signaled with %d." i)) + | WSTOPPED i -> raise (PlatformError (cmd, sprintf "Stopped with %d." i)) + +(* Generate a file name that does not already exist. + basedir includes the path separator +*) +let gen_name (basedir:string) (basen:string) (baseext:string) : string = + let rec nocollide ofs = + let nfn = sprintf "%s/%s%s%s" basedir basen + (if ofs = 0 then "" else "_"^(string_of_int ofs)) baseext + in + try ignore (stat nfn); nocollide (ofs + 1) + with Unix_error (ENOENT,_,_) -> nfn + in nocollide 0 + + +let raise_error cmd i = + if i <> 0 then raise (PlatformError (cmd, sprintf "Exited with status %d." i)) + +let ignore_error _ _ = () + +let preprocess (dot_oat:string) (dot_i:string) : unit = + sh (sprintf "%s%s %s %s" !pp_cmd + (List.fold_left (fun s -> fun i -> s ^ " -I" ^ i) "" !include_paths) + dot_oat dot_i) raise_error + +let clang_compile (dot_ll:string) (dot_s:string) : unit = + sh (sprintf "%s%s %s" (clang_cmd ()) dot_s dot_ll) raise_error + +let assemble (dot_s:string) (dot_o:string) : unit = + sh (sprintf "%s%s %s" (as_cmd ()) dot_o dot_s) raise_error + +let link (mods:string list) (out_fn:string) : unit = + sh (sprintf "%s%s %s %s %s %s" (link_cmd ()) out_fn + (String.concat " " (mods @ !lib_paths)) + (List.fold_left (fun s -> fun i -> s ^ " -L" ^ i) "" !lib_search_paths) + (List.fold_left (fun s -> fun i -> s ^ " -I" ^ i) "" !include_paths) + (List.fold_left (fun s -> fun l -> s ^ " -l" ^ l) "" !libs)) + raise_error + + + diff --git a/hw5/util/range.ml b/hw5/util/range.ml new file mode 100644 index 0000000..03901c4 --- /dev/null +++ b/hw5/util/range.ml @@ -0,0 +1,41 @@ +open Lexing + +type pos = int * int (* Line number and column *) +type t = string * pos * pos + +let line_of_pos (l,_) = l +let col_of_pos (_,c) = c +let mk_pos line col = (line, col) + +let file_of_range (f,_,_) = f +let start_of_range (_,s,_) = s +let end_of_range (_,_,e) = e +let mk_range f s e = (f,s,e) +let valid_pos (l,c) = l >= 0 && c >=0 + +let merge_range ((f,s1,e1) as r1) ((f',s2,e2) as r2) = + if f <> f' then failwith @@ Printf.sprintf "merge_range called on different files: %s and %s" f f' + else + if not (valid_pos s1) then r2 else + if not (valid_pos s2) then r1 else + mk_range f (min s1 s2) (max e1 e2) + +let string_of_range (f,(sl,sc),(el,ec)) = + Printf.sprintf "%s:[%d.%d-%d.%d]" f sl sc el ec + +let ml_string_of_range (f,(sl,sc),(el,ec)) = + Printf.sprintf "(\"%s\", (%d, %d), (%d, %d))" f sl sc el ec + +let norange = ("__internal", (0,0), (0,0)) + +(* Creates a Range.pos from the Lexing.position data *) +let pos_of_lexpos (p:position) : pos = + mk_pos (p.pos_lnum) (p.pos_cnum - p.pos_bol) + +let mk_lex_range (p1:position) (p2:position) : t = + mk_range p1.pos_fname (pos_of_lexpos p1) (pos_of_lexpos p2) + +(* Expose the lexer state as a Range.t value *) +let lex_range lexbuf : t = + mk_lex_range (lexeme_start_p lexbuf) (lexeme_end_p lexbuf) + diff --git a/hw5/util/range.mli b/hw5/util/range.mli new file mode 100644 index 0000000..c14f54f --- /dev/null +++ b/hw5/util/range.mli @@ -0,0 +1,53 @@ +(* Ranges and utilities on ranges. *) + +(* A range represents a segment of text in a given file; it has a + * beginning and ending position specified in terms of line and column + * numbers. A range is associated with tokens during lexing to allow + * the compiler to give better error messages during lexing and + * parsing. + *) + +(* a position in the source file; line number and column *) +type pos = int * int + +(* a range of positions in a particular file *) +type t = string * pos * pos + +(* line of position *) +val line_of_pos : pos -> int + +(* column of position *) +val col_of_pos : pos -> int + +(* new position with given line and col *) +val mk_pos : int -> int -> pos + +(* the filename a range is in *) +val file_of_range : t -> string + +(* the beginning of the range *) +val start_of_range : t -> pos + +(* the end of the range *) +val end_of_range : t -> pos + +(* create a new range from the given filename and start, end positions *) +val mk_range : string -> pos -> pos -> t + +(* merge two ranges together *) +val merge_range : t -> t -> t + +(* pretty-print a range *) +val string_of_range : t -> string + +(* print a range as an ocaml value *) +val ml_string_of_range : t -> string + +(* use to tag generated AST nodes where range does not apply *) +val norange : t + +val pos_of_lexpos : Lexing.position -> pos + +val mk_lex_range : Lexing.position -> Lexing.position -> t + +val lex_range : Lexing.lexbuf -> t diff --git a/hw5/x86/testX86.ml b/hw5/x86/testX86.ml new file mode 100644 index 0000000..1b23983 --- /dev/null +++ b/hw5/x86/testX86.ml @@ -0,0 +1,34 @@ +open X86 +open Cunit + +let hello_label = mk_lbl_named "hellostr" +let puts_label = mk_lbl_named "_puts" (* gcc on linux/mac uses _ to munge names *) + +let main_seq = [ + Push (esp); + Mov (ebp, esp); + + Add (esp, Imm (-8l)); (* Not sure why this has to be 8 *) + Mov (stack_offset 0l, Lbl hello_label); + Call (Lbl puts_label); + + Mov (esp, ebp); + Pop (ebp); + Ret +] + +let main_bb = { + (mk_insn_block (mk_lbl_named "_main") main_seq) with + global = true +} + +let hello_data = { + link = false; + label = (mk_lbl_named "hellostr"); + value = GStringz "Hello, world!" +} + +let cu = [Data hello_data; Code main_bb] + +let _ = + print_endline (string_of_cunit cu) diff --git a/hw5/x86/x86.ml b/hw5/x86/x86.ml new file mode 100644 index 0000000..802ee18 --- /dev/null +++ b/hw5/x86/x86.ml @@ -0,0 +1,165 @@ +(* X86lite language representation. *) + +(* assembler syntax --------------------------------------------------------- *) + +(* Labels for code blocks and global data. *) +type lbl = string + +type quad = int64 + +(* Immediate operands *) +type imm = Lit of quad + | Lbl of lbl + +(* Registers: + instruction pointer: rip + arguments: rdi, rsi, rdx, rcx, r09, r08 + callee-save: rbx, rbp, r12-r15 +*) +type reg = Rip + | Rax | Rbx | Rcx | Rdx | Rsi | Rdi | Rbp | Rsp + | R08 | R09 | R10 | R11 | R12 | R13 | R14 | R15 + +type operand = Imm of imm (* immediate *) + | Reg of reg (* register *) + | Ind1 of imm (* indirect: displacement *) + | Ind2 of reg (* indirect: (%reg) *) + | Ind3 of (imm * reg) (* indirect: displacement(%reg) *) + +(* Condition Codes *) +type cnd = Eq | Neq | Gt | Ge | Lt | Le + +type opcode = Movq | Pushq | Popq + | Leaq + | Incq | Decq | Negq | Notq + | Addq | Subq | Imulq | Xorq | Orq | Andq + | Shlq | Sarq | Shrq + | Jmp | J of cnd + | Cmpq | Set of cnd + | Callq | Retq + +(* An instruction is an opcode plus its operands. + Note that arity and other constraints about the operands + are not checked. *) +type ins = opcode * operand list + +type data = Asciz of string + | Quad of imm + +type asm = Text of ins list (* code *) + | Data of data list (* data *) + +(* labeled blocks of data or code *) +type elem = { lbl: lbl; global: bool; asm: asm } + +type prog = elem list + +(* Provide some syntactic sugar for writing x86 code in OCaml files. *) +module Asm = struct + let (~$) i = Imm (Lit (Int64.of_int i)) (* int64 constants *) + let (~$$) l = Imm (Lbl l) (* label constants *) + let (~%) r = Reg r (* registers *) + + (* helper functions for building blocks of data or code *) + let data l ds = { lbl = l; global = true; asm = Data ds } + let text l is = { lbl = l; global = false; asm = Text is } + let gtext l is = { lbl = l; global = true; asm = Text is } +end + +(* pretty printing ----------------------------------------------------------- *) + +let string_of_reg : reg -> string = function + | Rip -> "%rip" + | Rax -> "%rax" | Rbx -> "%rbx" | Rcx -> "%rcx" | Rdx -> "%rdx" + | Rsi -> "%rsi" | Rdi -> "%rdi" | Rbp -> "%rbp" | Rsp -> "%rsp" + | R08 -> "%r8 " | R09 -> "%r9 " | R10 -> "%r10" | R11 -> "%r11" + | R12 -> "%r12" | R13 -> "%r13" | R14 -> "%r14" | R15 -> "%r15" + +let string_of_byte_reg : reg -> string = function + | Rip -> failwith "%rip used as byte register" + | Rax -> "%al" | Rbx -> "%bl" | Rcx -> "%cl" | Rdx -> "%dl" + | Rsi -> "%sil" | Rdi -> "%dil" | Rbp -> "%bpl" | Rsp -> "%spl" + | R08 -> "%r8b" | R09 -> "%r9b" | R10 -> "%r10b" | R11 -> "%r11b" + | R12 -> "%r12b" | R13 -> "%r13b" | R14 -> "%r14b" | R15 -> "%r15b" + +let string_of_lbl (l:lbl) : string = l + +let string_of_imm : imm -> string = function + | Lit i -> Int64.to_string i + | Lbl l -> string_of_lbl l + +let string_of_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_byte_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_byte_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_jmp_operand : operand -> string = function + | Imm i -> string_of_imm i + | Reg r -> "*" ^ string_of_reg r + | Ind1 i -> "*" ^ string_of_imm i + | Ind2 r -> "*" ^ "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> "*" ^ string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_cnd : cnd -> string = function + | Eq -> "e" | Neq -> "ne" | Gt -> "g" + | Ge -> "ge" | Lt -> "l" | Le -> "le" + +let string_of_opcode : opcode -> string = function + | Movq -> "movq" | Pushq -> "pushq" | Popq -> "popq" + | Leaq -> "leaq" + | Incq -> "incq" | Decq -> "decq" | Negq -> "negq" | Notq -> "notq" + | Addq -> "addq" | Subq -> "subq" | Imulq -> "imulq" + | Xorq -> "xorq" | Orq -> "orq" | Andq -> "andq" + | Shlq -> "shlq" | Sarq -> "sarq" | Shrq -> "shrq" + | Jmp -> "jmp" | J c -> "j" ^ string_of_cnd c + | Cmpq -> "cmpq" | Set c -> "set" ^ string_of_cnd c + | Callq -> "callq" | Retq -> "retq" + +let map_concat s f l = String.concat s @@ List.map f l + +let string_of_shift op = function + | [ Imm i ; dst ] as args -> + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " string_of_operand args + | [ Reg Rcx ; dst ] -> + Printf.sprintf "\t%s\t%%cl, %s" (string_of_opcode op) (string_of_operand dst) + | args -> failwith (Printf.sprintf "shift instruction has invalid operands: %s\n" + (map_concat ", " string_of_operand args)) + +let string_of_ins (op, args: ins) : string = + match op with + | Shlq | Sarq | Shrq -> string_of_shift op args + | _ -> + let f = match op with + | J _ | Jmp | Callq -> string_of_jmp_operand + | Set _ -> string_of_byte_operand + | _ -> string_of_operand + in + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " f args + +let string_of_data : data -> string = function + | Asciz s -> "\t.asciz\t" ^ "\"" ^ (String.escaped s) ^ "\"" + | Quad i -> "\t.quad\t" ^ string_of_imm i + +let string_of_asm : asm -> string = function + | Text is -> "\t.text\n" ^ map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n" ^ map_concat "\n" string_of_data ds + +let string_of_elem {lbl; global; asm} : string = + let sec, body = match asm with + | Text is -> "\t.text\n", map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n", map_concat "\n" string_of_data ds + in + let glb = if global then "\t.globl\t" ^ string_of_lbl lbl ^ "\n" else "" in + sec ^ glb ^ string_of_lbl lbl ^ ":\n" ^ body + +let string_of_prog (p:prog) : string = + String.concat "\n" @@ List.map string_of_elem p diff --git a/hw6/.ocamlinit b/hw6/.ocamlinit new file mode 100644 index 0000000..a6a06df --- /dev/null +++ b/hw6/.ocamlinit @@ -0,0 +1,10 @@ +#use "topfind";; + +#directory "_build" +#directory "_build/util" +#directory "_build/x86" +#directory "_build/grading" +#directory "_build/ll" + +#load_rec "x86.cmo" +#load_rec "ll.cmo" diff --git a/hw6/Makefile b/hw6/Makefile new file mode 100644 index 0000000..a26b7a9 --- /dev/null +++ b/hw6/Makefile @@ -0,0 +1,39 @@ +INCLUDES= util,x86,ll +SUBMIT := solver.ml alias.ml backend.ml dce.ml constprop.ml team.txt + +HWNAME := hw06 +ZIPNAME := $(HWNAME)-submit.zip + +# diffent compilation cmd for Ocaml >= 4.08.1 +# otherwise package `num` won't be correctly located +OCAMLNEW := $(shell expr `ocaml --version | sed -e 's/^.* //g' -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40800) +ifeq "$(OCAMLNEW)" "1" + LIBS = unix,str + PKGS = -package num +else + LIBS = unix,str,nums + PKGS = +endif + +all: main.native + +.PHONY: test +test: main.native + ./main.native --test + +.PHONY: main.native +main.native: $(SUBMIT) ast.ml astlib.ml backend.ml driver.ml main.ml runtime.c + ocamlbuild -Is $(INCLUDES) $(PKGS) -libs $(LIBS) main.native -use-menhir -yaccflag --explain + +.PHONY: printanalysis.native +printanalysis.native: $(SUBMIT) ast.ml astlib.ml backend.ml driver.ml main.ml runtime.c + ocamlbuild -Is $(INCLUDES) $(PKGS) -libs $(LIBS) printanalysis.native -use-menhir -yaccflag --explain + + +zip: $(SUBMIT) + zip '$(ZIPNAME)' $(SUBMIT) + +.PHONY: clean +clean: + ocamlbuild -clean + rm -rf output a.out diff --git a/hw6/README b/hw6/README new file mode 100644 index 0000000..bf019f5 --- /dev/null +++ b/hw6/README @@ -0,0 +1,69 @@ +Using main.native for testing: + +* To run the automated test harness do: + - on OS X: ./main.native --test + - on Linux: ./main.native -linux --test + +* To compile ll files using the Compiler Design backend: + ./main.native path/to/foo.ll + + - creates output/foo.s backend assembly code + - creates output/foo.o assembled object file + - creates a.out linked executable + + NOTE: by default the .s and .o files are created in + a directory called output, and the filenames are + chosen so that multiple runs of the compiler will + not overwrite previous outputs. foo.ll will be + compiled first to foo.s then foo_1.s, foo_2.s, etc. + + +* To compile ll files using the clang backend: + ./main.native --clang path/to/foo.ll + +* Useful flags: + + --print-ll + echoes the ll program to the terminal + + --print-x86 + echoes the resulting .s file to the terminal + + --simulate-x86 + runs the resulting .s file through the reference + x86 simulator and outputs the result to the console + + --execute-x86 + runs the resulting a.out file natively + (applies to either the Compiler Design backend or clang-compiled code) + + -v + generates verbose output, showing which commands are used + for linking, etc. + + -op + change the output path [DEFAULT=output] + + -o + change the generated executable's name [DEFAULT=a.out] + + -S + stop after generating .s files + + -c + stop after generating .o files + + -h or --help + display the list of options + +* Example uses: + +Run the test case /programs/factrect.ll using the Compiler Design backend: + + +./main.native --execute-x86 programs/factrect.ll +--------------------------------------------------------------- Executing: a.out +* a.out returned 120 + + +Run the test diff --git a/hw6/alias.ml b/hw6/alias.ml new file mode 100644 index 0000000..3bfcc28 --- /dev/null +++ b/hw6/alias.ml @@ -0,0 +1,96 @@ +(** Alias Analysis *) + +open Ll +open Datastructures + +(* The lattice of abstract pointers ----------------------------------------- *) +module SymPtr = + struct + type t = MayAlias (* uid names a pointer that may be aliased *) + | Unique (* uid is the unique name for a pointer *) + | UndefAlias (* uid is not in scope or not a pointer *) + + let compare : t -> t -> int = Pervasives.compare + + let to_string = function + | MayAlias -> "MayAlias" + | Unique -> "Unique" + | UndefAlias -> "UndefAlias" + + end + +(* The analysis computes, at each program point, which UIDs in scope are a unique name + for a stack slot and which may have aliases *) +type fact = SymPtr.t UidM.t + +(* flow function across Ll instructions ------------------------------------- *) +(* TASK: complete the flow function for alias analysis. + + - After an alloca, the defined UID is the unique name for a stack slot + - A pointer returned by a load, call, bitcast, or GEP may be aliased + - A pointer passed as an argument to a call, bitcast, GEP, or store + may be aliased + - Other instructions do not define pointers + + *) +let insn_flow ((u,i):uid * insn) (d:fact) : fact = + failwith "Alias.insn_flow unimplemented" + + +(* The flow function across terminators is trivial: they never change alias info *) +let terminator_flow t (d:fact) : fact = d + +(* module for instantiating the generic framework --------------------------- *) +module Fact = + struct + type t = fact + let forwards = true + + let insn_flow = insn_flow + let terminator_flow = terminator_flow + + (* UndefAlias is logically the same as not having a mapping in the fact. To + compare dataflow facts, we first remove all of these *) + let normalize : fact -> fact = + UidM.filter (fun _ v -> v != SymPtr.UndefAlias) + + let compare (d:fact) (e:fact) : int = + UidM.compare SymPtr.compare (normalize d) (normalize e) + + let to_string : fact -> string = + UidM.to_string (fun _ v -> SymPtr.to_string v) + + (* TASK: complete the "combine" operation for alias analysis. + + The alias analysis should take the join over predecessors to compute the + flow into a node. You may find the UidM.merge function useful. + + It may be useful to define a helper function that knows how to take the + join of two SymPtr.t facts. + *) + let combine (ds:fact list) : fact = + failwith "Alias.Fact.combine not implemented" + end + +(* instantiate the general framework ---------------------------------------- *) +module Graph = Cfg.AsGraph (Fact) +module Solver = Solver.Make (Fact) (Graph) + +(* expose a top-level analysis operation ------------------------------------ *) +let analyze (g:Cfg.t) : Graph.t = + (* the analysis starts with every node set to bottom (the map of every uid + in the function to UndefAlias *) + let init l = UidM.empty in + + (* the flow into the entry node should indicate that any pointer parameter + to the function may be aliased *) + let alias_in = + List.fold_right + (fun (u,t) -> match t with + | Ptr _ -> UidM.add u SymPtr.MayAlias + | _ -> fun m -> m) + g.Cfg.args UidM.empty + in + let fg = Graph.of_cfg init alias_in g in + Solver.solve fg + diff --git a/hw6/analysis.ml b/hw6/analysis.ml new file mode 100644 index 0000000..1f1e1bf --- /dev/null +++ b/hw6/analysis.ml @@ -0,0 +1,37 @@ +open Ll +open Datastructures + + + +(* Because the cfg instance of the dataflow graph uses _basic blocks_ as nodes, + we need a way to recover the dataflow facts at individual instructions + within the block. Depending on the direction of the analysis, this amounts to + propagating information either forward or backwards through the block. + + The following helper functions construct maps from each instruction or terminator + to the corresponding dataflow fact. *) + +(* Compute IN for each instruction in a block, given IN of the first instruction *) +let block_flow_forwards_map (fi:uid * insn -> 'd -> 'd) + (ft:terminator -> 'd -> 'd) + ({insns; term}:block) (d_in:'d) : uid -> 'd = + let t_id, t = term in + let m, d_tmn = List.fold_left (fun (m, d) (u,i) -> + let d' = fi (u,i) d in + UidM.add u d m, d') + (UidM.empty, d_in) insns in + let m' = UidM.add t_id d_tmn m in + fun u -> UidM.find u m' + +(* Compute OUT for each instruction in a block, given OUT of the terminator*) +let block_flow_backwards_map (fi:uid * insn -> 'd -> 'd) + (ft:terminator -> 'd -> 'd) + ({insns; term}:block) (d_out:'d) : uid -> 'd = + let t_id, t = term in + let d_ins = ft t d_out in + let m, _ = List.fold_right (fun (u,i) (m, d) -> + let d' = fi (u,i) d in + UidM.add u d m, d') + insns (UidM.empty, d_ins) in + let m' = UidM.add t_id d_out m in + fun u -> UidM.find u m' diff --git a/hw6/analysistests.ml b/hw6/analysistests.ml new file mode 100644 index 0000000..059c580 --- /dev/null +++ b/hw6/analysistests.ml @@ -0,0 +1,295 @@ +open Datastructures + +let liveness_analysis_tests = + [ "llprograms/analysis9.ll", lblm[ + "_entry", uids[] + ; "body", uids["1"; "2"; "d0"; "d1"] + ; "end", uids["1"] + ; "guard", uids["1"; "2"; "d0"] + ] + ; "llprograms/analysis8.ll", lblm[ + "_entry", uids[] + ] + ; "llprograms/analysis7.ll", lblm[ + "_entry", uids[] + ; "body", uids["1"; "4"] + ; "end", uids["1"] + ; "guard", uids["1"; "4"] + ] + ; "llprograms/analysis5.ll", lblm[ + "_entry", uids[] + ] + ; "llprograms/analysis4.ll", lblm[ + "_entry", uids["argc"] + ; "l1", uids["2"; "3"] + ; "l2", uids["3"] + ] + ; "llprograms/analysis3.ll", lblm[ + "_entry", uids[] + ; "l2", uids["1"] + ; "l3", uids["2"] + ; "l4", uids["3"] + ; "l5", uids["4"] + ; "l6", uids["5"] + ; "l7", uids["6"] + ; "l8", uids["7"] + ; "l9", uids["8"] + ; "lexit", uids["9"] + ] + ; "llprograms/analysis2.ll", lblm[ + "_entry", uids["argc"] + ; "l1", uids["1"; "3"] + ; "l2", uids[] + ] + ; "llprograms/analysis19.ll", lblm[ + "_entry", uids[] + ] + ; "llprograms/analysis18.ll", lblm[ + "_entry", uids[] + ; "bar", uids["1"; "2"; "3"; "4"] + ; "foo", uids["1"; "sa"] + ] + ; "llprograms/analysis16.ll", lblm[ + "_entry", uids[] + ; "continue_loop", uids["1"; "2"; "5"] + ; "else", uids["1"; "2"; "5"; "7"] + ; "foo", uids["1"; "2"] + ; "if", uids["1"; "2"; "5"; "7"] + ; "loop", uids["1"; "2"] + ; "reta", uids["1"] + ; "retb", uids["2"] + ] + ; "llprograms/analysis15.ll", lblm[ + "_entry", uids[] + ] + ; "llprograms/analysis14.ll", lblm[ + "_entry", uids[] + ] + ; "llprograms/analysis13.ll", lblm[ + "_entry", uids[] + ; "correct", uids["7"] + ; "five", uids["1"; "6"; "7"] + ; "four", uids["1"; "5"; "6"; "7"] + ; "one", uids["1"; "2"; "3"; "4"; "5"; "6"; "7"] + ; "three", uids["1"; "4"; "5"; "6"; "7"] + ; "two", uids["1"; "3"; "4"; "5"; "6"; "7"] + ; "wrong", uids["1"] + ] + ; "llprograms/analysis12.ll", lblm[ + "_entry", uids[] + ] + ; "llprograms/analysis11.ll", lblm[ + "_entry", uids[] + ; "foo", uids[] + ] + ; "llprograms/analysis10.ll", lblm[ + "_entry", uids[] + ; "else", uids["1"; "7"] + ; "merge", uids["1"; "7"] + ; "then", uids["1"; "7"] + ] + ; "llprograms/analysis1.ll", lblm[ + "_entry", uids["argc"] + ; "l1", uids["1"; "3"] + ] + ] + +let alias_analysis_tests = + let open Alias.SymPtr in + [ "llprograms/analysis9.ll", lblm[ + "_entry", uidm["1", Unique; "2", Unique; "argv", MayAlias] + ; "body", uidm["1", Unique; "2", Unique; "argv", MayAlias] + ; "end", uidm["1", Unique; "2", Unique; "argv", MayAlias] + ; "guard", uidm["1", Unique; "2", Unique; "argv", MayAlias] + ] + ; "llprograms/analysis8.ll", lblm[ + "_entry", uidm["argv", MayAlias; "tmp1", Unique] + ] + ; "llprograms/analysis7.ll", lblm[ + "_entry", uidm["2", Unique; "4", Unique; "argv", MayAlias] + ; "body", uidm["2", Unique; "4", Unique; "argv", MayAlias] + ; "end", uidm["2", Unique; "4", Unique; "argv", MayAlias] + ; "guard", uidm["2", Unique; "4", Unique; "argv", MayAlias] + ] + ; "llprograms/analysis5.ll", lblm[ + "_entry", uidm["argv", MayAlias] + ] + ; "llprograms/analysis4.ll", lblm[ + "_entry", uidm["3", Unique; "arcv", MayAlias] + ; "l1", uidm["3", MayAlias; "6", MayAlias; "7", MayAlias; "arcv", MayAlias] + ; "l2", uidm["3", MayAlias; "6", MayAlias; "7", MayAlias; "arcv", MayAlias] + ] + ; "llprograms/analysis3.ll", lblm[ + "_entry", uidm["arcv", MayAlias] + ; "l2", uidm["arcv", MayAlias] + ; "l3", uidm["arcv", MayAlias] + ; "l4", uidm["arcv", MayAlias] + ; "l5", uidm["arcv", MayAlias] + ; "l6", uidm["arcv", MayAlias] + ; "l7", uidm["arcv", MayAlias] + ; "l8", uidm["arcv", MayAlias] + ; "l9", uidm["arcv", MayAlias] + ; "lexit", uidm["arcv", MayAlias] + ] + ; "llprograms/analysis2.ll", lblm[ + "_entry", uidm["3", Unique; "arcv", MayAlias] + ; "l1", uidm["3", MayAlias; "5", MayAlias; "arcv", MayAlias] + ; "l2", uidm["3", Unique; "arcv", MayAlias] + ] + ; "llprograms/analysis19.ll", lblm[ + "_entry", uidm["1", Unique; "2", MayAlias; "arcv", MayAlias] + ] + ; "llprograms/analysis18.ll", lblm[ + "_entry", uidm["1", Unique; "arcv", MayAlias] + ; "bar", uidm["1", Unique; "arcv", MayAlias; "sa", Unique; "sb", Unique; "sc", Unique] + ; "foo", uidm["1", Unique; "arcv", MayAlias; "sa", Unique; "sb", Unique; "sc", Unique] + ] + ; "llprograms/analysis16.ll", lblm[ + "_entry", uidm["1", Unique; "2", Unique; "arcv", MayAlias] + ; "continue_loop", uidm["1", Unique; "2", Unique; "arcv", MayAlias] + ; "else", uidm["1", Unique; "2", Unique; "arcv", MayAlias] + ; "foo", uidm["1", Unique; "2", Unique; "arcv", MayAlias] + ; "if", uidm["1", Unique; "2", Unique; "arcv", MayAlias] + ; "loop", uidm["1", Unique; "2", Unique; "arcv", MayAlias] + ; "reta", uidm["1", Unique; "2", Unique; "arcv", MayAlias] + ; "retb", uidm["1", Unique; "2", Unique; "arcv", MayAlias] + ] + ; "llprograms/analysis15.ll", lblm[ + "_entry", uidm["arcv", MayAlias; "head", MayAlias; "link", MayAlias; "link2", MayAlias; "next", MayAlias; "next2", MayAlias; "val", MayAlias; "val2", MayAlias] + ] + ; "llprograms/analysis14.ll", lblm[ + "_entry", uidm["1", MayAlias; "2", MayAlias; "arcv", MayAlias] + ] + ; "llprograms/analysis13.ll", lblm[ + "_entry", uidm["arcv", MayAlias] + ; "correct", uidm["arcv", MayAlias] + ; "five", uidm["arcv", MayAlias] + ; "four", uidm["arcv", MayAlias] + ; "one", uidm["arcv", MayAlias] + ; "three", uidm["arcv", MayAlias] + ; "two", uidm["arcv", MayAlias] + ; "wrong", uidm["arcv", MayAlias] + ] + ; "llprograms/analysis12.ll", lblm[ + "_entry", uidm["arcv", MayAlias] + ] + ; "llprograms/analysis11.ll", lblm[ + "_entry", uidm["argv", MayAlias] + ; "foo", uidm["4", Unique; "5", Unique] + ] + ; "llprograms/analysis10.ll", lblm[ + "_entry", uidm["4", Unique; "7", Unique; "argv", MayAlias] + ; "else", uidm["4", Unique; "7", Unique; "argv", MayAlias] + ; "merge", uidm["4", Unique; "7", Unique; "argv", MayAlias] + ; "then", uidm["4", Unique; "7", Unique; "argv", MayAlias] + ] + ; "llprograms/analysis1.ll", lblm[ + "_entry", uidm["3", Unique; "arcv", MayAlias] + ; "l1", uidm["3", MayAlias; "4", MayAlias; "arcv", MayAlias] + ] + ] + +let constprop_analysis_tests = + let open Constprop.SymConst in + [ "llprograms/analysis9.ll", lblm[ + "_entry", uidm["1", NonConst; "2", NonConst; "argc", NonConst; "argv", NonConst; "d0", Const (1L)] + ; "body", uidm["1", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "argc", NonConst; "argv", NonConst; "d0", Const (1L); "d1", Const (5L); "d2", Const (11L)] + ; "end", uidm["1", NonConst; "10", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "argc", NonConst; "argv", NonConst; "d0", Const (1L); "d1", Const (5L); "d2", Const (11L)] + ; "guard", uidm["1", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "argc", NonConst; "argv", NonConst; "d0", Const (1L); "d1", Const (5L); "d2", Const (11L)] + ] + ; "llprograms/analysis8.ll", lblm[ + "_entry", uidm["a", Const (1L); "argc", NonConst; "argv", NonConst; "b", Const (3L); "c", Const (6L); "d", Const (10L); "e", Const (15L); "f", Const (21L); "g", Const (28L); "h", Const (36L); "i", Const (45L); "j", Const (55L); "k", Const (66L); "l", Const (78L); "m", Const (91L); "n", NonConst; "o", NonConst; "p", NonConst; "q", NonConst; "r", NonConst; "s", NonConst; "t", NonConst; "tmp1", NonConst; "tmp2", NonConst; "u", NonConst; "v", NonConst; "w", NonConst; "x", NonConst; "y", NonConst; "z", NonConst] + ] + ; "llprograms/analysis7.ll", lblm[ + "_entry", uidm["1", Const (10L); "2", NonConst; "3", Const (1L); "4", NonConst; "argc", NonConst; "argv", NonConst] + ; "body", uidm["1", Const (10L); "2", NonConst; "3", Const (1L); "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "argc", NonConst; "argv", NonConst] + ; "end", uidm["1", Const (10L); "2", NonConst; "3", Const (1L); "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "argc", NonConst; "argv", NonConst] + ; "guard", uidm["1", Const (10L); "2", NonConst; "3", Const (1L); "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "argc", NonConst; "argv", NonConst] + ] + ; "llprograms/analysis6.ll", lblm[ + "_entry", uidm["1", Const (2L); "2", Const (3L); "3", Const (4L); "argc", NonConst; "argv", NonConst] + ; "else", uidm["1", Const (2L); "2", Const (3L); "3", Const (4L); "4", Const (1L); "argc", NonConst; "argv", NonConst] + ; "merge", uidm["1", Const (2L); "2", Const (3L); "3", Const (4L); "4", Const (1L); "argc", NonConst; "argv", NonConst] + ; "then", uidm["1", Const (2L); "2", Const (3L); "3", Const (4L); "4", Const (1L); "argc", NonConst; "argv", NonConst] + ] + ; "llprograms/analysis5.ll", lblm[ + "_entry", uidm["1", Const (7L); "2", Const (7L); "3", Const (14L); "argc", NonConst; "argv", NonConst] + ] + ; "llprograms/analysis4.ll", lblm[ + "_entry", uidm["1", Const (49L); "2", NonConst; "3", NonConst; "arcv", NonConst; "argc", NonConst] + ; "l1", uidm["1", Const (49L); "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "arcv", NonConst; "argc", NonConst] + ; "l2", uidm["1", Const (49L); "10", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "arcv", NonConst; "argc", NonConst] + ] + ; "llprograms/analysis3.ll", lblm[ + "_entry", uidm["1", Const (14L); "arcv", NonConst; "argc", NonConst] + ; "l2", uidm["1", Const (14L); "2", Const (28L); "arcv", NonConst; "argc", NonConst] + ; "l3", uidm["1", Const (14L); "2", Const (28L); "3", Const (-4L); "arcv", NonConst; "argc", NonConst] + ; "l4", uidm["1", Const (14L); "2", Const (28L); "3", Const (-4L); "4", Const (-8L); "arcv", NonConst; "argc", NonConst] + ; "l5", uidm["1", Const (14L); "2", Const (28L); "3", Const (-4L); "4", Const (-8L); "5", Const (15L); "arcv", NonConst; "argc", NonConst] + ; "l6", uidm["1", Const (14L); "2", Const (28L); "3", Const (-4L); "4", Const (-8L); "5", Const (15L); "6", Const (3L); "arcv", NonConst; "argc", NonConst] + ; "l7", uidm["1", Const (14L); "2", Const (28L); "3", Const (-4L); "4", Const (-8L); "5", Const (15L); "6", Const (3L); "7", Const (3L); "arcv", NonConst; "argc", NonConst] + ; "l8", uidm["1", Const (14L); "2", Const (28L); "3", Const (-4L); "4", Const (-8L); "5", Const (15L); "6", Const (3L); "7", Const (3L); "8", Const (67L); "arcv", NonConst; "argc", NonConst] + ; "l9", uidm["1", Const (14L); "2", Const (28L); "3", Const (-4L); "4", Const (-8L); "5", Const (15L); "6", Const (3L); "7", Const (3L); "8", Const (67L); "9", Const (188L); "arcv", NonConst; "argc", NonConst] + ; "lexit", uidm["1", Const (14L); "2", Const (28L); "3", Const (-4L); "4", Const (-8L); "5", Const (15L); "6", Const (3L); "7", Const (3L); "8", Const (67L); "9", Const (188L); "arcv", NonConst; "argc", NonConst] + ] + ; "llprograms/analysis2.ll", lblm[ + "_entry", uidm["1", Const (49L); "2", NonConst; "3", NonConst; "4", Const (0L); "arcv", NonConst; "argc", NonConst] + ; "l1", uidm["1", Const (49L); "2", NonConst; "3", NonConst; "4", Const (0L); "5", NonConst; "arcv", NonConst; "argc", NonConst] + ; "l2", uidm["1", Const (49L); "2", NonConst; "3", NonConst; "4", Const (0L); "arcv", NonConst; "argc", NonConst] + ] + ; "llprograms/analysis19.ll", lblm[ + "_entry", uidm["1", NonConst; "2", NonConst; "3", NonConst; "arcv", NonConst; "argc", NonConst] + ] + ; "llprograms/analysis18.ll", lblm[ + "_entry", uidm["1", NonConst; "2", Const (14L); "3", Const (42L); "4", Const (40L); "arcv", NonConst; "argc", NonConst] + ; "bar", uidm["1", NonConst; "2", Const (14L); "3", Const (42L); "4", Const (40L); "arcv", NonConst; "argc", NonConst; "sa", NonConst; "sb", NonConst; "sc", NonConst] + ; "foo", uidm["1", NonConst; "2", Const (14L); "3", Const (42L); "4", Const (40L); "arcv", NonConst; "argc", NonConst; "res", NonConst; "sa", NonConst; "sb", NonConst; "sc", NonConst; "v1", NonConst; "v2", NonConst; "v3", NonConst; "v4", NonConst] + ] + ; "llprograms/analysis17.ll", lblm[ + "_entry", uidm["i1", Const (2L); "i2", Const (3L); "sx", NonConst; "sy", NonConst; "v1", NonConst; "v2", NonConst; "v3", NonConst; "x", NonConst; "y", NonConst] + ; "l1", uidm["a1", NonConst; "arg1", Const (12L); "i1", Const (2L); "i2", Const (3L); "sx", NonConst; "sy", NonConst; "v1", NonConst; "v2", NonConst; "v3", NonConst; "v4", NonConst; "x", NonConst; "y", NonConst] + ] + ; "llprograms/analysis16.ll", lblm[ + "_entry", uidm["1", NonConst; "2", NonConst; "arcv", NonConst; "argc", NonConst] + ; "continue_loop", uidm["1", NonConst; "10", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "arcv", NonConst; "argc", NonConst] + ; "else", uidm["1", NonConst; "10", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "arcv", NonConst; "argc", NonConst] + ; "foo", uidm["1", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "arcv", NonConst; "argc", NonConst] + ; "if", uidm["1", NonConst; "10", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "arcv", NonConst; "argc", NonConst] + ; "loop", uidm["1", NonConst; "10", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "arcv", NonConst; "argc", NonConst] + ; "reta", uidm["1", NonConst; "10", NonConst; "11", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst; "arcv", NonConst; "argc", NonConst] + ; "retb", uidm["1", NonConst; "12", NonConst; "2", NonConst; "3", NonConst; "4", NonConst; "arcv", NonConst; "argc", NonConst] + ] + ; "llprograms/analysis15.ll", lblm[ + "_entry", uidm["1", NonConst; "arcv", NonConst; "argc", NonConst; "head", NonConst; "link", NonConst; "link2", NonConst; "next", NonConst; "next2", NonConst; "val", NonConst; "val2", NonConst] + ] + ; "llprograms/analysis14.ll", lblm[ + "_entry", uidm["1", NonConst; "2", NonConst; "3", Const (2L); "4", Const (0L); "arcv", NonConst; "argc", NonConst] + ] + ; "llprograms/analysis13.ll", lblm[ + "_entry", uidm["1", Const (0L); "2", Const (1L); "3", Const (2L); "4", Const (3L); "5", Const (4L); "6", Const (5L); "7", Const (7L); "arcv", NonConst; "argc", NonConst; "cmp1", Const (1L)] + ; "correct", uidm["1", Const (0L); "2", Const (1L); "3", Const (2L); "4", Const (3L); "5", Const (4L); "6", Const (5L); "7", Const (7L); "arcv", NonConst; "argc", NonConst; "cmp1", Const (1L); "cmp2", Const (1L); "cmp3", Const (1L); "cmp4", Const (1L); "cmp5", Const (1L); "cmp6", Const (1L)] + ; "five", uidm["1", Const (0L); "2", Const (1L); "3", Const (2L); "4", Const (3L); "5", Const (4L); "6", Const (5L); "7", Const (7L); "arcv", NonConst; "argc", NonConst; "cmp1", Const (1L); "cmp2", Const (1L); "cmp3", Const (1L); "cmp4", Const (1L); "cmp5", Const (1L); "cmp6", Const (1L)] + ; "four", uidm["1", Const (0L); "2", Const (1L); "3", Const (2L); "4", Const (3L); "5", Const (4L); "6", Const (5L); "7", Const (7L); "arcv", NonConst; "argc", NonConst; "cmp1", Const (1L); "cmp2", Const (1L); "cmp3", Const (1L); "cmp4", Const (1L); "cmp5", Const (1L)] + ; "one", uidm["1", Const (0L); "2", Const (1L); "3", Const (2L); "4", Const (3L); "5", Const (4L); "6", Const (5L); "7", Const (7L); "arcv", NonConst; "argc", NonConst; "cmp1", Const (1L); "cmp2", Const (1L)] + ; "three", uidm["1", Const (0L); "2", Const (1L); "3", Const (2L); "4", Const (3L); "5", Const (4L); "6", Const (5L); "7", Const (7L); "arcv", NonConst; "argc", NonConst; "cmp1", Const (1L); "cmp2", Const (1L); "cmp3", Const (1L); "cmp4", Const (1L)] + ; "two", uidm["1", Const (0L); "2", Const (1L); "3", Const (2L); "4", Const (3L); "5", Const (4L); "6", Const (5L); "7", Const (7L); "arcv", NonConst; "argc", NonConst; "cmp1", Const (1L); "cmp2", Const (1L); "cmp3", Const (1L)] + ; "wrong", uidm["1", Const (0L); "2", Const (1L); "3", Const (2L); "4", Const (3L); "5", Const (4L); "6", Const (5L); "7", Const (7L); "arcv", NonConst; "argc", NonConst; "cmp1", Const (1L); "cmp2", Const (1L); "cmp3", Const (1L); "cmp4", Const (1L); "cmp5", Const (1L); "cmp6", Const (1L)] + ] + ; "llprograms/analysis12.ll", lblm[ + "_entry", uidm["1", Const (14L); "2", Const (-1L); "3", Const (1L); "4", Const (2L); "5", Const (0L); "6", Const (0L); "7", Const (14L); "8", Const (14L); "9", Const (14L); "arcv", NonConst; "argc", NonConst] + ] + ; "llprograms/analysis11.ll", lblm[ + "_entry", uidm["1", Const (1L); "2", Const (2L); "3", Const (3L); "argc", NonConst; "argv", NonConst] + ; "foo", uidm["4", NonConst; "5", NonConst; "6", NonConst; "7", NonConst; "8", NonConst; "9", NonConst] + ] + ; "llprograms/analysis10.ll", lblm[ + "_entry", uidm["1", Const (30L); "2", Const (6L); "3", Const (3L); "4", NonConst; "5", NonConst; "6", Const (12L); "7", NonConst; "8", NonConst; "9", Const (1L); "argc", NonConst; "argv", NonConst] + ; "else", uidm["1", Const (30L); "12", NonConst; "13", NonConst; "2", Const (6L); "3", Const (3L); "4", NonConst; "5", NonConst; "6", Const (12L); "7", NonConst; "8", NonConst; "9", Const (1L); "argc", NonConst; "argv", NonConst] + ; "merge", uidm["1", Const (30L); "10", NonConst; "11", NonConst; "12", NonConst; "13", NonConst; "14", NonConst; "15", Const (30L); "16", NonConst; "2", Const (6L); "3", Const (3L); "4", NonConst; "5", NonConst; "6", Const (12L); "7", NonConst; "8", NonConst; "9", Const (1L); "argc", NonConst; "argv", NonConst] + ; "then", uidm["1", Const (30L); "10", NonConst; "11", NonConst; "2", Const (6L); "3", Const (3L); "4", NonConst; "5", NonConst; "6", Const (12L); "7", NonConst; "8", NonConst; "9", Const (1L); "argc", NonConst; "argv", NonConst] + ] + ; "llprograms/analysis1.ll", lblm[ + "_entry", uidm["1", Const (49L); "2", NonConst; "3", NonConst; "arcv", NonConst; "argc", NonConst] + ; "l1", uidm["1", Const (49L); "2", NonConst; "3", NonConst; "4", NonConst; "arcv", NonConst; "argc", NonConst] + ] + ] diff --git a/hw6/ast.ml b/hw6/ast.ml new file mode 100644 index 0000000..43dc4ac --- /dev/null +++ b/hw6/ast.ml @@ -0,0 +1,95 @@ + +type 'a node = { elt : 'a; loc : Range.t } + +(** val no_loc : 'a1 -> 'a1 node **) + +let no_loc x = + { elt = x; loc = Range.norange } + +type id = string + +type ty = +| TBool +| TInt +| TRef of rty +| TNullRef of rty +and rty = +| RString +| RStruct of id +| RArray of ty +| RFun of ty list * ret_ty +and ret_ty = +| RetVoid +| RetVal of ty + +type unop = +| Neg +| Lognot +| Bitnot + +type binop = +| Add +| Sub +| Mul +| Eq +| Neq +| Lt +| Lte +| Gt +| Gte +| And +| Or +| IAnd +| IOr +| Shl +| Shr +| Sar + +type exp = +| CNull of rty +| CBool of bool +| CInt of int64 +| CStr of string +| Id of id +| CArr of ty * exp node list +| NewArr of ty * exp node +| NewArrInit of ty * exp node * id * exp node +| Index of exp node * exp node +| Length of exp node +| CStruct of id * (id * exp node) list +| Proj of exp node * id +| Call of exp node * exp node list +| Bop of binop * exp node * exp node +| Uop of unop * exp node + + +type cfield = id * exp node + +type vdecl = id * exp node + +type stmt = +| Assn of exp node * exp node +| Decl of vdecl +| Ret of exp node option +| SCall of exp node * exp node list +| If of exp node * stmt node list * stmt node list +| Cast of rty * id * exp node * stmt node list * stmt node list +| For of vdecl list * exp node option * stmt node option * stmt node list +| While of exp node * stmt node list + +type block = stmt node list + +type gdecl = { name : id; init : exp node } + +type fdecl = { frtyp : ret_ty; fname : id; args : (ty * id) list; body : block } + +type field = { fieldName : id; ftyp : ty } + +type tdecl = id * field list + +type decl = +| Gvdecl of gdecl node +| Gfdecl of fdecl node +| Gtdecl of tdecl node + +type prog = decl list diff --git a/hw6/astlib.ml b/hw6/astlib.ml new file mode 100644 index 0000000..ffb0e8f --- /dev/null +++ b/hw6/astlib.ml @@ -0,0 +1,497 @@ +(* astlib.ml *) + +(* Helper functions of abstract syntax of trees. *) +(******************************************************************************) + +open Format +open Ast +open Range + +(* Precedence for expressions and operators *) +(* Higher precedences bind more tightly *) + +let prec_of_binop = function +| Mul -> 100 +| Add | Sub -> 90 +| Shl | Shr | Sar -> 80 +| Lt | Lte | Gt | Gte -> 70 +| Eq | Neq -> 60 +| And -> 50 +| Or -> 40 +| IAnd -> 30 +| IOr -> 20 + +let prec_of_unop = function _ -> 110 + +let prec_of_exp = function +| Bop (o,_,_) -> prec_of_binop o +| Uop (o,_) -> prec_of_unop o +| _ -> 130 + + +(* Pretty Printer for AST *) +let string_of_unop = function +| Neg -> "-" +| Lognot -> "!" +| Bitnot -> "~" + +let string_of_binop = function +| Mul -> "*" +| Add -> "+" +| Sub -> "-" +| Shl -> "<<" +| Shr -> ">>" +| Sar -> ">>>" +| Lt -> "<" +| Lte -> "<=" +| Gt -> ">" +| Gte -> ">=" +| Eq -> "==" +| Neq -> "!=" +| And -> "&" +| Or -> "|" +| IAnd -> "[&]" +| IOr -> "[|]" + +let print_id_aux fmt (x:id) = pp_print_string fmt x + +let rec print_list_aux fmt sep pp l = + begin match l with + | [] -> () + | [h] -> pp fmt h + | h::tl -> pp fmt h; sep (); + print_list_aux fmt sep pp tl + end + +let rec print_ty_aux fmt t = + let pps = pp_print_string fmt in + match t with + | TBool -> pps "bool" + | TInt -> pps "int" + | TRef r -> print_rty_aux fmt r + | TNullRef r -> pps "("; print_rty_aux fmt r; pps ")?" + +and print_ret_ty_aux fmt t = + let pps = pp_print_string fmt in + begin match t with + | RetVoid -> pps "void" + | RetVal t -> print_ty_aux fmt t + end + +and print_rty_aux fmt r = + let pps = pp_print_string fmt in + begin match r with + | RString -> pps "string" + | RArray t -> print_ty_aux fmt t; pps "[]" + | RStruct id -> pps id + | RFun (ts, t) -> pps "("; + print_list_aux fmt (fun () -> pps ", ") print_ty_aux ts; + pps ")"; pps "->"; print_ret_ty_aux fmt t + end + +and print_exp_aux level fmt e = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let this_level = prec_of_exp e.elt in + + if this_level < level then pps "("; + begin match e.elt with + | CNull r -> print_rty_aux fmt r; pps "null" + | CBool v -> pps (if v then "true" else "false") + | CInt v -> pps (Int64.to_string v) + | CStr v -> pps (Printf.sprintf "%S" v) + | CArr (ty,vs) -> begin + pps "new "; print_ty_aux fmt ty; pps "[]"; + pps "{"; + pp_open_hbox fmt (); + print_list_aux fmt (fun () -> pps ","; pp_print_space fmt()) (print_exp_aux 0) vs; + pp_close_box fmt (); + pps "}"; + end + | Length l -> pps "length( "; print_exp_aux this_level fmt l; pps " )" + | Id id -> print_id_aux fmt id + | Index (e,i) -> print_exp_aux this_level fmt e; pps "["; print_exp_aux 0 fmt i; pps "]" + | Call (e, es) -> print_exp_aux this_level fmt e; print_exps_aux "(" ")" fmt es + | NewArr(ty, e1) -> + pps "new"; print_ty_aux fmt ty; + pps "["; print_exp_aux this_level fmt e1; pps "]" + | NewArrInit (ty, e1, u, e2) -> + pps "new"; print_ty_aux fmt ty; + pps "["; print_exp_aux this_level fmt e1; + pps "] {"; pps u; pps "->"; print_exp_aux this_level fmt e2; pps "}" + | Bop (o,l,r) -> + pp_open_box fmt 0; + print_exp_aux this_level fmt l; + ppsp (); pps (string_of_binop o); ppsp (); + print_exp_aux this_level fmt r; + pp_close_box fmt () + | Uop (o,v) -> + pp_open_box fmt 0; + pps (string_of_unop o); + print_exp_aux this_level fmt v; + pp_close_box fmt () + | Proj (e, id) -> + pp_open_box fmt 0; + print_exp_aux this_level fmt e; + ppsp (); pps "."; ppsp (); pps id; + pp_close_box fmt () + | CStruct (t, l) -> + pps "new "; pps t; + pp_open_box fmt 0; + pps "{"; + List.iter (fun s -> print_cfield_aux this_level fmt s; pps "; ") l; + pps "}"; + pp_close_box fmt () + end; if this_level < level then pps ")" + +and print_cfield_aux l fmt (name, exp) = + pp_open_box fmt 0; + pp_print_string fmt name; + pp_print_string fmt "="; print_exp_aux l fmt exp; + pp_close_box fmt (); + +and print_exps_aux l r fmt es = + let pps = pp_print_string fmt in + pps l; + pp_open_hvbox fmt 0; + print_list_aux fmt + (fun () -> pps ","; pp_print_space fmt()) + (fun fmt -> fun e -> print_exp_aux 0 fmt e) es; + pp_close_box fmt (); + pps r + +let print_vdecl_aux semi fmt (id, init) = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + pp_open_hbox fmt (); + pps "var "; print_id_aux fmt id; + ppsp (); pps " ="; ppsp (); + print_exp_aux 0 fmt init; pps semi; + pp_close_box fmt () + +let rec print_block_aux fmt stmts = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let ppnl = pp_force_newline fmt in + + if (List.length stmts) > 0 then + begin pps "{"; ppnl (); pps " "; + pp_open_vbox fmt 0; + print_list_aux fmt (fun () -> ppsp ()) print_stmt_aux stmts; + pp_close_box fmt (); + ppnl (); pps "}" + end + else pps "{ }" + +and print_cond_aux fmt b_then opt_b_else = + let pps = pp_print_string fmt in + print_block_aux fmt b_then; + begin match opt_b_else with + | [] -> () + | b_else -> pps " else "; print_block_aux fmt b_else + end + +and print_stmt_aux fmt s = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + + begin match s.elt with + | Decl d -> print_vdecl_aux ";" fmt d + + | Assn (p,e) -> + pp_open_box fmt 0; + print_exp_aux 0 fmt p; + pps " ="; ppsp (); + print_exp_aux 0 fmt e; + pps ";"; pp_close_box fmt () + + | SCall (e, es) -> + print_exp_aux 0 fmt e; print_exps_aux "(" ")" fmt es; pps ";" + + | Ret (eo) -> + pps "return"; + begin match eo with + | None -> () + | Some e -> pps " "; print_exp_aux 0 fmt e + end; pps ";" + + | If (e, b_then, opt_b_else) -> + pps "if ("; print_exp_aux 0 fmt e; pps ") "; + print_cond_aux fmt b_then opt_b_else + + | Cast(t, id, e, b_null, b_notnull) -> + pps "ifnull ("; print_id_aux fmt id; pps "="; print_exp_aux 0 fmt e; + pps ") "; + print_cond_aux fmt b_null b_notnull + + | While(e, b) -> + pps "while ("; print_exp_aux 0 fmt e; pps ") "; + print_block_aux fmt b + + | For(decls, eo, so, body) -> + pps "for ("; pp_open_hvbox fmt 0; + print_list_aux fmt (fun () -> pps ","; ppsp ()) (print_vdecl_aux "") decls; + pps ";"; ppsp (); + begin match eo with + | None -> (); + | Some e -> print_exp_aux 0 fmt e; + end; + pps ";"; ppsp (); + begin match so with + | None -> () + | Some s -> print_stmt_aux fmt s + end; pp_close_box fmt (); + pps ") "; print_block_aux fmt body + end + +let print_fdecl_aux fmt {elt={frtyp; fname; args; body}} = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + let ppnl = pp_force_newline fmt in + + print_ret_ty_aux fmt frtyp; + pps @@ Printf.sprintf " %s(" fname; + pp_open_hbox fmt (); + print_list_aux fmt (fun () -> pps ","; ppsp ()) + (fun fmt -> fun (t, id) -> + print_ty_aux fmt t; + pps " "; + print_id_aux fmt id; + ) args; + pp_close_box fmt (); + pps ") "; print_block_aux fmt body; ppnl () + +let print_gdecl_aux fmt (gd:Ast.gdecl) = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + pp_open_hbox fmt (); + pps @@ Printf.sprintf "global %s =" gd.name; ppsp (); + print_exp_aux 0 fmt gd.init; pps ";"; + pp_close_box fmt () + +let print_field fmt f = + let pps = pp_print_string fmt in + pp_open_hbox fmt (); + print_ty_aux fmt f.ftyp; pps " "; pps f.fieldName; + pp_close_box fmt () + +let print_tdecl_aux fmt ((id, l):Ast.tdecl) = + let pps = pp_print_string fmt in + let ppsp = pp_print_space fmt in + pp_open_hbox fmt (); + pps @@ Printf.sprintf "struct %s =" id; ppsp (); + pps "{"; + List.iter (fun s -> print_field fmt s; pps "; ") l; + pps "}"; + pp_close_box fmt () + +let print_decl_aux fmt g = + begin match g with + | Gvdecl d -> print_gdecl_aux fmt d.elt + | Gfdecl f -> print_fdecl_aux fmt f + | Gtdecl t -> print_tdecl_aux fmt t.elt + end + +let print_prog_aux fmt p = + let ppnl = pp_force_newline fmt in + pp_open_vbox fmt 0; + List.iter (fun g -> print_decl_aux fmt g; ppnl (); ppnl ()) p; + pp_close_box fmt () + +let print ppx x : unit = + pp_open_hvbox std_formatter 0; + ppx std_formatter x; + pp_close_box std_formatter (); + pp_print_newline std_formatter () + +let string_of ppx x : string = + pp_open_hvbox str_formatter 0; + ppx str_formatter x; + pp_close_box str_formatter (); + flush_str_formatter () + +let print_prog (p:prog) : unit = print print_prog_aux p +let string_of_prog (p:prog) : string = string_of print_prog_aux p + +let print_stmt (s:stmt node) : unit = print print_stmt_aux s +let string_of_stmt (s:stmt node) : string = string_of print_stmt_aux s + +let print_block (b:block) : unit = print print_block_aux b +let string_of_block (b:block) : string = string_of print_block_aux b + +let print_exp (e:exp node) : unit = print (print_exp_aux 0) e +let string_of_exp (e:exp node) : string = string_of (print_exp_aux 0) e + +let print_ty (t:ty) : unit = print print_ty_aux t +let string_of_ty (t:ty) : string = string_of print_ty_aux t + +(* AST to ML *) + +let sp = Printf.sprintf + +let ml_string_of_list (f: 'a -> string) (l: 'a list) : string = + sp "[ %s ]" (String.concat " ; " (List.map f l)) + +let ml_string_of_option (f: 'a -> string) (o: 'a option) : string = + begin match o with + | None -> sp "None" + | Some x -> sp "Some (%s)" (f x) + end + +(* TODO Change ml string printing for loc *) + +let ml_string_of_node (f: 'a -> string) ({elt;loc}: 'a node) = + sp "{ elt = %s; loc = %s }" (f elt) (Range.ml_string_of_range loc) + +let rec ml_string_of_ty (t:ty) : string = + match t with + | TBool -> "TBool" + | TInt -> "TInt" + | TRef r -> sp "TRef (%s)" (ml_string_of_reft r) + | TNullRef r -> sp "TNullRef (%s)" (ml_string_of_reft r) + +and ml_string_of_ret_ty r = + match r with + | RetVoid -> "TVoid" + | RetVal t -> ml_string_of_ty t + + +and ml_string_of_reft (r:rty) : string = + match r with + | RString -> "RString" + | RArray t -> sp "(RArray (%s))" (ml_string_of_ty t) + | RStruct id -> sp "(RStruct (%s))" id + | RFun (ts, t) -> sp "RFun (%s, %s)" + (ml_string_of_list ml_string_of_ty ts) + (ml_string_of_ret_ty t) + + +let ml_string_of_id : id -> string = (sp "\"%s\"") + +let ml_string_of_binop : binop -> string = function + | Add -> "Add" + | Sub -> "Sub" + | Mul -> "Mul" + | Eq -> "Eq" + | Neq -> "Neq" + | Lt -> "Lt" + | Lte -> "Lte" + | Gt -> "Gt" + | Gte -> "Gte" + | And -> "And" + | Or -> "Or" + | IAnd -> "IAnd" + | IOr -> "IOr" + | Shl -> "Shl" + | Shr -> "Shr" + | Sar -> "Sar" + +let ml_string_of_unop : unop -> string = function + | Neg -> "Neg" + | Lognot -> "Lognot" + | Bitnot -> "Bitnot" + +let rec ml_string_of_exp_aux (e: exp) : string = + begin match e with + | CNull r -> sp "CNull %s" (ml_string_of_reft r) + | CBool b -> sp "CBool %b" b + | CInt i -> sp "CInt %LiL" i + | CStr s -> sp "CStr %S" s + | CArr (t,cs) -> sp "CArr (%s,%s)" + (ml_string_of_ty t) + (ml_string_of_list ml_string_of_exp cs) + | CStruct (id, l) -> sp "CStruct (%s, %s)" + id + (ml_string_of_list ml_string_of_field l) + | Id id -> sp "Id %s" (ml_string_of_id id) + | Index (e, i) -> sp "Index (%s, %s)" + (ml_string_of_exp e) (ml_string_of_exp i) + | Call (e, exps) -> sp "Call (%s, %s)" + (ml_string_of_exp e) + (ml_string_of_list ml_string_of_exp exps) + | NewArr (t,e1) -> sp "NewArr (%s,%s)" + (ml_string_of_ty t) (ml_string_of_exp e1) + | NewArrInit (t,e1,u,e2) -> sp "NewArrInit (%s,%s,%s,%s)" + (ml_string_of_ty t) (ml_string_of_exp e1) (ml_string_of_id u) (ml_string_of_exp e2) + | Proj(exp, id) -> sp "Proj (%s,%s)" (ml_string_of_exp exp) (ml_string_of_id id) + | Bop (b, e1, e2) -> sp "Bop (%s,%s,%s)" + (ml_string_of_binop b) (ml_string_of_exp e1) (ml_string_of_exp e2) + | Uop (u, e) -> sp "Uop (%s, %s)" + (ml_string_of_unop u) (ml_string_of_exp e) + | Length (e) -> sp "Length (%s)" (ml_string_of_exp e) + end + +and ml_string_of_exp (e:exp node) : string = + ml_string_of_node ml_string_of_exp_aux e + +and ml_string_of_field ((id, exp) : cfield) : string = + sp "%s = %s;" (ml_string_of_id id) (ml_string_of_exp exp) + +let ml_string_of_vdecl_aux (id,init:vdecl) : string = + sp "(%s, %s)" + (ml_string_of_id id) (ml_string_of_exp init) + +let ml_string_of_vdecl (d:vdecl node) : string = + ml_string_of_node ml_string_of_vdecl_aux d + +let rec ml_string_of_stmt_aux (s:stmt) : string = + match s with + | Assn (p, e) -> sp "Assn (%s,%s)" (ml_string_of_exp p) (ml_string_of_exp e) + | Decl d -> sp "Decl (%s)" (ml_string_of_vdecl_aux d) + | Ret e -> sp "Ret (%s)" (ml_string_of_option ml_string_of_exp e) + | SCall (exp, exps) -> + sp "SCall (%s, %s)" (ml_string_of_exp exp) (ml_string_of_list ml_string_of_exp exps) + | If (e,b1,b2) -> sp "If (%s,%s,%s)" + (ml_string_of_exp e) (ml_string_of_block b1) (ml_string_of_block b2) + | Cast (r, id, exp, null, notnull) -> + sp "Cast (%s,%s,%s,%s,%s)" + (ml_string_of_reft r) id (ml_string_of_exp exp) + (ml_string_of_block null) (ml_string_of_block notnull) + | For (d,e,s,b) -> sp "For (%s,%s,%s,%s)" + (ml_string_of_list ml_string_of_vdecl_aux d) + (ml_string_of_option ml_string_of_exp e) + (ml_string_of_option ml_string_of_stmt s) (ml_string_of_block b) + | While (e,b) -> sp "While (%s,%s)" (ml_string_of_exp e) (ml_string_of_block b) + +and ml_string_of_stmt (s:stmt node) : string = + ml_string_of_node ml_string_of_stmt_aux s + +and ml_string_of_block (b:block) : string = + ml_string_of_list ml_string_of_stmt b + +let ml_string_of_args : (ty * id) list -> string = + ml_string_of_list (fun (t,i) -> + sp "(%s,%s)" (ml_string_of_ty t) (ml_string_of_id i)) + +let rec ml_string_of_fdecl_aux (f:fdecl) : string = + sp "{ rtyp = %s; name = %s; args = %s; body = %s }" + (ml_string_of_ret_ty f.frtyp) (ml_string_of_id f.fname) + (ml_string_of_args f.args) (ml_string_of_block f.body) + +and ml_string_of_fdecl (f:fdecl node) : string = + ml_string_of_node ml_string_of_fdecl_aux f + +let ml_string_of_gdecl_aux (gd:gdecl) : string = + sp "{ name = %s; init = %s }" + (ml_string_of_id gd.name) (ml_string_of_exp gd.init) + +let ml_string_of_gdecl (d:gdecl node) : string = + ml_string_of_node ml_string_of_gdecl_aux d + +let ml_string_of_field {fieldName; ftyp} : string = + sp "{ fname = %s; typ = %s }" + (ml_string_of_id fieldName) (ml_string_of_ty ftyp) + +let ml_string_of_tdecl_aux (id,fs) : string = + sp "(id = %s, fs = (%s))" (ml_string_of_id id) (ml_string_of_list ml_string_of_field fs) + +let ml_string_of_tdecl (t:tdecl node) : string = + ml_string_of_node ml_string_of_tdecl_aux t + +let ml_string_of_decl : decl -> string = function + | Gvdecl d -> sp "Gvdecl (%s)" (ml_string_of_gdecl d) + | Gfdecl f -> sp "Gfdecl (%s)" (ml_string_of_fdecl f) + | Gtdecl t -> sp "Gtdecl (%s)" (ml_string_of_tdecl t) + +let ml_string_of_prog : prog -> string = + ml_string_of_list ml_string_of_decl diff --git a/hw6/backend.ml b/hw6/backend.ml new file mode 100644 index 0000000..5dc1055 --- /dev/null +++ b/hw6/backend.ml @@ -0,0 +1,847 @@ +(* ll ir compilation -------------------------------------------------------- *) +open Ll +open Llutil +open X86 + + +(* allocated llvmlite function bodies --------------------------------------- *) + +module Alloc = struct + +(* X86 locations *) +type loc = + | LVoid (* no storage *) + | LReg of X86.reg (* x86 register *) + | LStk of int (* a stack slot offset from %rbp (not a byte offset!)*) + | LLbl of X86.lbl (* an assembler label *) + +type operand = + | Null + | Const of int64 + | Gid of X86.lbl + | Loc of loc + +type insn = + | ILbl of loc + | PMov of (loc * ty * operand) list + | Binop of loc * bop * ty * operand * operand + | Alloca of loc * ty + | Load of loc * ty * operand + | Store of ty * operand * operand + | Icmp of loc * Ll.cnd * ty * operand * operand + | Call of loc * ty * operand * (ty * operand) list + | Bitcast of loc * ty * operand * ty + | Gep of loc * ty * operand * operand list + | Ret of ty * operand option + | Br of loc + | Cbr of operand * loc * loc + +let str_loc = function + | LVoid -> "LVoid" + | LReg r -> X86.string_of_reg r + | LStk n -> Printf.sprintf "LStk %d" n + | LLbl l -> l + +let str_operand = function + | Null -> "null" + | Const x -> "Const _" + | Gid l -> l + | Loc l -> str_loc l + + +module LocSet = Set.Make (struct type t = loc let compare = compare end) +module UidSet = Datastructures.UidS + +type fbody = (insn * LocSet.t) list + +let map_operand f g : Ll.operand -> operand = function + | Null -> Null + | Const i -> Const i + | Gid x -> Gid (g x) + | Id u -> Loc (f u) + +let map_insn f g : uid * Ll.insn -> insn = + let mo = map_operand f g in function + | x, Binop (b,t,o,o') -> Binop (f x, b,t,mo o,mo o') + | x, Alloca t -> Alloca (f x, t) + | x, Load (t,o) -> Load (f x, t, mo o) + | _, Store (t,o,o') -> Store (t, mo o, mo o') + | x, Icmp (c,t,o,o') -> Icmp (f x, c, t, mo o, mo o') + | x, Call (t,o,args) -> Call (f x, t, mo o, List.map (fun (t,o) -> t, mo o) args) + | x, Bitcast (t,o,t') -> Bitcast (f x, t, mo o, t') + | x, Gep (t,o,is) -> Gep (f x, t, mo o, List.map mo is) + +let map_terminator f g : uid * Ll.terminator -> insn = + let mo = map_operand f g in function + | _, Ret (t,None) -> Ret (t, None) + | _, Ret (t,Some o) -> Ret (t, Some (mo o)) + | _, Br l -> Br (f l) + | _, Cbr (o,l,l') -> Cbr (mo o,f l,f l') + +let map_lset f (s:UidSet.t) : LocSet.t = + UidSet.fold (fun x t -> LocSet.add (f x) t) s LocSet.empty + +let of_block + (f:Ll.uid -> loc) + (g:Ll.gid -> X86.lbl) + (live_in:uid -> UidSet.t) + (b:Ll.block) : fbody = + List.map (fun (u,i) -> + (* Uncomment this to enable verbose debugging output... *) + (* Platform.verb @@ Printf.sprintf + " * of_block: %s live_in = %s\n" u (UidSet.to_string (live_in u)); *) + map_insn f g (u,i), map_lset f @@ live_in u) b.insns + @ let x,t = b.term in + [map_terminator f g (x,t), map_lset f @@ live_in x] + +let of_lbl_block f g live_in (l,b:Ll.lbl * Ll.block) : fbody = + (ILbl (f l), map_lset f @@ live_in l)::of_block f g live_in b + +let of_cfg + (f : Ll.uid -> loc) + (g : Ll.gid -> X86.lbl) + (live_in : uid -> UidSet.t) + (e, bs : Ll.cfg) : fbody = + List.(flatten @@ of_block f g live_in e :: map (of_lbl_block f g live_in) bs) + +end + +module LocSet = Alloc.LocSet +module UidSet = Alloc.UidSet + +let str_locset (lo:LocSet.t) : string = + String.concat " " (List.map Alloc.str_loc (LocSet.elements lo)) + + +(* streams of x86 instructions ---------------------------------------------- *) + +type x86elt = + | I of X86.ins + | L of (X86.lbl * bool) + +type x86stream = x86elt list + +let lift : X86.ins list -> x86stream = + List.rev_map (fun i -> I i) + +let ( >@ ) x y = y @ x +let ( >:: ) x y = y :: x + +let prog_of_x86stream : x86stream -> X86.prog = + let rec loop p iis = function + | [] -> (match iis with [] -> p | _ -> failwith "stream has no initial label") + | (I i)::s' -> loop p (i::iis) s' + | (L (l,global))::s' -> loop ({ lbl=l; global; asm=Text iis }::p) [] s' + in loop [] [] + + +(* locals and layout -------------------------------------------------------- *) + +(* The layout for this version of the backend is slightly more complex + than we saw earlier. It consists of + - uid_loc a function that maps LL uids to their target x86 locations + - the number of bytes to be allocated on the stack due to spills +*) + +type layout = + { uid_loc : uid -> Alloc.loc + ; spill_bytes : int + } + +(* The liveness analysis will return a record, with fields live_in and live_out, + which are functions from uid to the set of variables that are live in (or + live out) at a given program point denoted by the uid *) +type liveness = Liveness.liveness + +(* The set of all caller-save registers available for register allocation *) +let caller_save : LocSet.t = + [ Rdi; Rsi; Rdx; Rcx; R09; R08; Rax; R10; R11 ] + |> List.map (fun r -> Alloc.LReg r) |> LocSet.of_list + +(* excludes Rbp, Rsp, and Rip, since they have special meanings + The current backend does not use callee-save registers except in + the special case of through registers. It uses R15 as a function + pointer, but ensures that it is saved/restored. +*) +let callee_save : LocSet.t = + [ Rbx; R12; R13; R14; R15 ] + |> List.map (fun r -> Alloc.LReg r) |> LocSet.of_list + +let arg_reg : int -> X86.reg option = function + | 0 -> Some Rdi + | 1 -> Some Rsi + | 2 -> Some Rdx + | 3 -> Some Rcx + | 4 -> Some R08 + | 5 -> Some R09 + | n -> None + +let arg_loc (n:int) : Alloc.loc = + match arg_reg n with + | Some r -> Alloc.LReg r + | None -> Alloc.LStk (n-4) + +let alloc_fdecl (layout:layout) (liveness:liveness) (f:Ll.fdecl) : Alloc.fbody = + let dst = List.map layout.uid_loc f.f_param in + let tdst = List.combine (fst f.f_ty) dst in + let movs = List.mapi (fun i (t,x) -> x, t, Alloc.Loc (arg_loc i)) tdst in + (Alloc.PMov movs, LocSet.of_list dst) + :: Alloc.of_cfg layout.uid_loc Platform.mangle liveness.live_in f.f_cfg + +(* compiling operands ------------------------------------------------------ *) + +let compile_operand : Alloc.operand -> X86.operand = + let open Alloc in function + | Null -> Asm.(~$0) + | Const i -> Asm.(Imm (Lit i)) + | Gid l -> Asm.(~$$l) + | Loc LVoid -> failwith "compiling uid without location" + | Loc (LStk i) -> Asm.(Ind3 (Lit (Int64.of_int @@ i * 8), Rbp)) + | Loc (LReg r) -> Asm.(~%r) + | Loc (LLbl l) -> Asm.(Ind1 (Lbl l)) + +let emit_mov (src:X86.operand) (dst:X86.operand) : x86stream = + let open X86 in match src, dst with + | Imm (Lbl l), Reg _ -> lift Asm.[ Leaq, [Ind3 (Lbl l, Rip); dst ] ] + | Imm (Lbl l), _ -> lift Asm.[ Leaq, [Ind3 (Lbl l, Rip); ~%Rax ] + ; Movq, [~%Rax; dst ] ] + | Reg r, Reg r' when r = r' -> [] + | Reg _, _ -> lift Asm.[ Movq, [src; dst] ] + | _, Reg _ -> lift Asm.[ Movq, [src; dst] ] + | _, _ -> lift Asm.[ Pushq, [src]; Popq, [dst] ] + + +(* compiling parallel moves ------------------------------------------------- *) + +(* Compiles a parallel move instruction into a sequence of moves, pushing and + popping values to the stack when there are not enough registers to directly + shuffle the sources to the targets. It uses liveness information to simply + not move dead operands. + + The PMov instruction is used at the beginning of a function declaration to + move the incoming arguments to their destination uids/registers. + compile_pmov is directly used when compiling a function call to move + the arguments. + + Inputs: + live - the liveness information + ol - a list of triples of the form (dest, type, src) + + Note: the destinations are assumed to be distinct, but might also be sources + + Outputs: + an x86 instruction stream that (efficiently) moves each src to its + destination + + The algorithm works like this: + 1. Filter out the triples in which srcs are dead or already in the right + place. (none of those need to be moved) + + Then do a recursive algorithm that processes the remaining list of triples: + 2. See if there are triples of the form (dest, type, src) where dest + is not also source in some other triple. For each such triple we can + directly move the src to its dest (which won't "clobber" some other + source). These are the "ready" moves. + + 3. If there are no "ready" moves to make (i.e. every destination is also + a source of some other triple), we pick the first triple, push its + src to the stack, recursively process the remaining list, and then + pop the stack into the destination. + + ol ol' 2 2 3 2 + x <- y x <- y w <- x MOV x, w MOV x, w MOV x, w + y <- y ==> ==> ------ ==> -------- ==> PUSH y ==> PUSH y + w <- x w <- x x <- y x <- y y <- z MOV z, y + y <- z y <- z y <- z y <- z POP x POP x + +*) + +let compile_pmov live (ol:(Alloc.loc * Ll.ty * Alloc.operand) list) : x86stream = + let open Alloc in + let module OpSet = Set.Make (struct type t = operand let compare = compare end) in + + (* Filter the moves to keep the needed ones: + The operands that actually need to be moved are those that are + - not in the right location already, and + - still live *) + let ol' = List.filter (fun (x, _, o) -> Loc x <> o && LocSet.mem x live) ol in + + let rec loop outstream ol = + (* Find the _set_ of all sources that still need to be moved. *) + let srcs = List.fold_left (fun s (_, _, o) -> OpSet.add o s) OpSet.empty ol in + match List.partition (fun (x, _, o) -> OpSet.mem (Loc x) srcs) ol with + | [], [] -> outstream + + (* when no moves are ready to be emitted, push onto stack *) + | (x,_,o)::ol', [] -> + let os = loop (outstream >:: I Asm.( Pushq, [compile_operand o])) + ol' in + os >:: I Asm.( Popq, [compile_operand (Loc x)] ) + + (* when some destination of a move is not also a source *) + | ol', ready -> + loop (List.fold_left (fun os (x,_,o) -> + os >@ + emit_mov (compile_operand o) (compile_operand (Loc x))) outstream ready) + ol' + in + loop [] ol' + + +(* compiling call ---------------------------------------------------------- *) + +let compile_call live (fo:Alloc.operand) (os:(ty * Alloc.operand) list) : x86stream = + let oreg, ostk, _ = + List.fold_left (fun (oreg, ostk, i) (t, o) -> + match arg_reg i with + | Some r -> (Alloc.LReg r, t, o)::oreg, ostk, i+1 + | None -> oreg, o::ostk, i+1 + ) ([], [], 0) os in + let nstack = List.length ostk in + let live' = LocSet.of_list @@ List.map (fun (r,_,_) -> r) oreg in + lift (List.map (fun o -> Pushq, [compile_operand o]) ostk) + >@ compile_pmov (LocSet.union live live') oreg + >:: I Asm.( Callq, [compile_operand fo] ) + >@ lift (if nstack <= 0 then [] + else Asm.[ Addq, [~$(nstack * 8); ~%Rsp] ]) + + +(* compiling getelementptr (gep) ------------------------------------------- *) + +let rec size_ty tdecls t : int = + begin match t with + | Void | I8 | Fun _ -> 0 + | I1 | I64 | Ptr _ -> 8 (* Target 64-bit only subset of X86 *) + | Struct ts -> List.fold_left (fun acc t -> acc + (size_ty tdecls t)) 0 ts + | Array (n, t) -> n * (size_ty tdecls t) + | Namedt id -> size_ty tdecls (List.assoc id tdecls) + end + +(* Compute the size of the offset (in bytes) of the nth element of a region + of memory whose types are given by the list. Also returns the nth type. *) +let index_into tdecls (ts:ty list) (n:int) : int * ty = + let rec loop ts n acc = + begin match (ts, n) with + | (u::_, 0) -> (acc, u) + | (u::us, n) -> loop us (n-1) (acc + (size_ty tdecls u)) + | _ -> failwith "index_into encountered bogus index" + end + in loop ts n 0 + +let imm_of_int (n:int) = Imm (Lit (Int64.of_int n)) + +let compile_getelementptr tdecls (t:Ll.ty) (o:Alloc.operand) + (path: Alloc.operand list) : x86stream = + + let rec loop ty path (code : x86stream) = + match (ty, path) with + | (_, []) -> code + + | (Struct ts, Alloc.Const n::rest) -> + let (offset, u) = index_into tdecls ts (Int64.to_int n) in + loop u rest @@ ( + code >:: I Asm.(Addq, [~$offset; ~%Rax]) + ) + + | (Array(_, u), Alloc.Const n::rest) -> + (* Statically calculate the offset *) + let offset = (size_ty tdecls u) * (Int64.to_int n) in + loop u rest @@ ( + code >:: I Asm.(Addq, [~$offset; ~%Rax]) + ) + + | (Array(_, u), offset_op::rest) -> + loop u rest @@ ( + code >@ + ([I Asm.(Movq, [~%Rax; ~%Rcx])] >@ + (emit_mov (compile_operand offset_op) (Reg Rax)) >@ + [I Asm.(Imulq, [imm_of_int @@ size_ty tdecls u; ~%Rax])] >@ + [I Asm.(Addq, [~%Rcx; ~%Rax])] + ) + ) + + | (Namedt t, p) -> loop (List.assoc t tdecls) p code + + | _ -> failwith "compile_gep encountered unsupported getelementptr data" in + + match t with + | Ptr t -> loop (Array(0, t)) path (emit_mov (compile_operand o) (Reg Rax)) + | _ -> failwith "compile_gep got incorrect parameters" + +(* compiling instructions within function bodies ---------------------------- *) + + +let compile_fbody tdecls (af:Alloc.fbody) : x86stream = + let rec loop (af:Alloc.fbody) (outstream:x86stream) : x86stream = + let cb = function + | Ll.Add -> Addq | Ll.Sub -> Subq | Ll.Mul -> Imulq + | Ll.Shl -> Shlq | Ll.Lshr -> Shrq | Ll.Ashr -> Sarq + | Ll.And -> Andq | Ll.Or -> Orq | Ll.Xor -> Xorq in + let cc = function + | Ll.Eq -> Set Eq | Ll.Ne -> Set Neq | Ll.Slt -> Set Lt + | Ll.Sle -> Set Le | Ll.Sgt -> Set Gt | Ll.Sge -> Set Ge in + let co = compile_operand in + + let open Alloc in + match af with + | [] -> outstream + + | (ILbl (LLbl l), _)::rest -> + loop rest @@ + (outstream + >:: L (l, false) ) + + | (PMov ol, live)::rest -> + loop rest @@ + ( outstream + >@ compile_pmov live ol ) + + | (Icmp (LVoid, _,_,_,_), _)::rest -> loop rest outstream + | (Binop (LVoid, _,_,_,_), _)::rest -> loop rest outstream + | (Alloca (LVoid, _), _)::rest -> loop rest outstream + | (Bitcast (LVoid, _,_,_), _)::rest -> loop rest outstream + | (Load (LVoid, _,_), _)::rest -> loop rest outstream + | (Gep (LVoid, _,_,_), _)::rest -> loop rest outstream + + | (Icmp (x, c,_,Loc (LReg o),o'), _)::rest -> + loop rest @@ + ( outstream + >@ lift Asm.[ Cmpq, [co o'; ~%o] + ; cc c, [co (Loc x)] + ; Andq, [~$1; co (Loc x)] ] ) + + + | (Icmp (x, c,_,o,o'), _)::rest -> + loop rest @@ + ( outstream + >@ emit_mov (co o) (Reg Rax) + >@ lift Asm.[ Cmpq, [co o'; ~%Rax] + ; cc c, [co (Loc x)] + ; Andq, [~$1; co (Loc x)] ] ) + + (* Shift instructions must use Rcx or Immediate as second arg *) + | (Binop (x, bop,_,o,o'), _)::rest + when (bop = Shl || bop = Lshr || bop = Ashr) + -> + loop rest @@ + ( outstream + >@ emit_mov (co o) (Reg Rax) + >@ emit_mov (co o') (Reg Rcx) + >@ lift Asm.[ cb bop, [~%Rcx; ~%Rax] + ; Movq, [~%Rax; co (Loc x)] ] ) + + | (Binop (LReg r, bop,_,o,o'), _)::rest + when Loc (LReg r) = o' && + (bop = Add || bop = Mul || bop = And || bop = Or || bop = Xor) -> + loop rest @@ + ( outstream + >:: I Asm.( cb bop, [co o; ~%r] ) ) + + + | (Binop (LReg r, b,_,o,o'), _)::rest when Loc (LReg r) <> o' -> + loop rest @@ + ( outstream + >@ emit_mov (co o) (Reg r) + >:: I Asm.( cb b, [co o'; ~%r] ) ) + + | (Binop (x, b,_,o,o'), _)::rest -> + loop rest @@ + ( outstream + >@ emit_mov (co o) (Reg Rax) + >@ lift Asm.[ cb b, [co o'; ~%Rax] + ; Movq, [~%Rax; co (Loc x)] ] ) + + | (Alloca (x, at), _)::rest -> + loop rest @@ + ( outstream + >@ lift Asm.[ Subq, [~$(size_ty tdecls at); ~%Rsp] + ; Movq, [~%Rsp; co (Loc x)] ] ) + + + | (Bitcast (x, _,o,_), _)::rest -> + loop rest @@ + ( outstream + >@ emit_mov (co o) (Reg Rax) + >:: I Asm.( Movq, [~%Rax; co (Loc x)] ) ) + + + | (Load (LReg x, _, Loc (LReg src)), _)::rest -> + loop rest @@ + ( outstream + >:: I Asm.( Movq, [Ind2 src; ~%x] ) ) + + | (Load (x, _, src), _)::rest -> + loop rest @@ + ( outstream + >@ emit_mov (co src) (Reg Rax) + >@ lift Asm.[ Movq, [Ind2 Rax; ~%Rax] + ; Movq, [~%Rax; co (Loc x)] ] ) + + | (Store (_,Loc (LReg src),Loc (LReg dst)), _)::rest -> + loop rest @@ + ( outstream + >:: I Asm.( Movq, [~%src; Ind2 dst] ) ) + + | (Store (_,src,dst), _)::rest -> + loop rest @@ + ( outstream + >@ emit_mov (co src) (Reg Rax) + >@ emit_mov (co dst) (Reg Rcx) + >:: I Asm.( Movq, [~%Rax; Ind2 Rcx] ) ) + + | (Gep (x, at,o,os), _)::rest -> + loop rest @@ + ( outstream + >@ compile_getelementptr tdecls at o os + >:: I Asm.( Movq, [~%Rax; co (Loc x)] ) ) + + | (Call (x, t,fo,os), live)::rest -> + (* Corner: fo is Loc (LReg r) and r is used in the calling conventions. + Then we use R15 to hold the function pointer, saving and restoring it, + since it is a callee-save register. *) + let fptr_op, init_fp, restore_fp = + begin match fo with + | Loc (LReg (Rdi | Rsi | Rdx | Rcx | R08 | R09)) -> + Loc (LReg R15), + [I Asm.(Pushq, [~%R15])] >@ (emit_mov (co fo) (Reg R15)), + [I Asm.(Popq, [~%R15])] + | _ -> fo, [], [] + end + in + let () = Platform.verb @@ Printf.sprintf "call: %s live = %s\n" + (str_operand fo) (str_locset live) + in + let save = LocSet.(elements @@ inter (remove x live) caller_save) in + loop rest @@ + ( outstream + >@ init_fp + >@ lift (List.rev_map (fun x -> Pushq, [co (Loc x)]) save) + >@ compile_call live fptr_op os + >@ lift (List.map (fun x -> Popq, [co (Loc x)]) save) + >@ restore_fp + >@ (if t = Ll.Void || x = LVoid then [] + else lift Asm.[ Movq, [~%Rax; co (Loc x)] ]) ) + + | (Ret (_,None), _)::rest -> + loop rest @@ + ( outstream + >@ lift Asm.[ Movq, [~%Rbp; ~%Rsp] + ; Popq, [~%Rbp] + ; Retq, [] ] ) + + | (Ret (_,Some o), _)::rest -> + loop rest @@ + ( outstream + >@ emit_mov (co o) (Reg Rax) + >@ lift Asm.[ Movq, [~%Rbp; ~%Rsp] + ; Popq, [~%Rbp] + ; Retq, [] ] ) + + | (Br (LLbl l), _)::rest -> + loop rest @@ + ( outstream + >:: I Asm.( Jmp, [~$$l] ) ) + + | (Cbr (Const i,(LLbl l1),(LLbl l2)), _)::rest -> + loop rest @@ + ( outstream + >:: (if i <> 0L + then I Asm.( Jmp, [~$$l1] ) + else I Asm.( Jmp, [~$$l2] ) ) ) + + | (Cbr (o,(LLbl l1),(LLbl l2)), _)::rest -> + loop rest @@ + ( outstream + >@ lift Asm.[ Cmpq, [~$0; co o] + ; J Neq, [~$$l1] + ; Jmp, [~$$l2] ] ) + + | _ -> failwith "codegen failed to find instruction" + in + loop af [] + + +(* compile_fdecl ------------------------------------------------------------ *) + +(* Processes a function declaration by processing each of the subcomponents + in turn: + - first fold over the function parameters + - then fold over the entry block + - then fold over the subsequent blocks in their listed order + To fold over a block: + - fold over the label + - then the instructions (in block order) + - then the terminator + + See the examples no_reg_layout and greedy_layout for how to use this function. +*) +let fold_fdecl (f_param : 'a -> uid * Ll.ty -> 'a) + (f_lbl : 'a -> lbl -> 'a) + (f_insn : 'a -> uid * Ll.insn -> 'a) + (f_term : 'a -> uid * Ll.terminator -> 'a) + (init:'a) (f:Ll.fdecl) : 'a = + let fold_params ps a = + List.fold_left f_param a ps in + let fold_block {insns; term} a = + f_term (List.fold_left f_insn a insns) term in + let fold_lbl_block (l,blk) a = + fold_block blk (f_lbl a l) in + let fold_lbl_blocks bs a = + List.fold_left (fun a b -> fold_lbl_block b a) a bs in + let entry,bs = f.f_cfg in + init + |> fold_params (List.combine f.f_param (fst f.f_ty)) + |> fold_block entry + |> fold_lbl_blocks bs + + +(* no layout ---------------------------------------------------------------- *) +(* This register allocation strategy puts all uids into stack + slots. It does not use liveness information. +*) +let insn_assigns : Ll.insn -> bool = function + | Ll.Call (Ll.Void, _, _) | Ll.Store _ -> false + | _ -> true + +let no_reg_layout (f:Ll.fdecl) (_:liveness) : layout = + let lo, n_stk = + fold_fdecl + (fun (lo, n) (x, _) -> (x, Alloc.LStk (- (n + 1)))::lo, n + 1) + (fun (lo, n) l -> (l, Alloc.LLbl (Platform.mangle l))::lo, n) + (fun (lo, n) (x, i) -> + if insn_assigns i + then (x, Alloc.LStk (- (n + 1)))::lo, n + 1 + else (x, Alloc.LVoid)::lo, n) + (fun a _ -> a) + ([], 0) f in + { uid_loc = (fun x -> List.assoc x lo) + ; spill_bytes = 8 * n_stk + } + +(* greedy layout ------------------------------------------------------------ *) +(* This example register allocation strategy puts the first few uids in + available registers and spills the rest. It uses liveness information to + recycle available registers when their current value becomes dead. + + There is a corner case where we might have to try to allocate a location + but there is a live variable who's location is unknown! (This can happen + in a loop... see gcd_euclidean.ll for an example.) In that case, we + should just spill to avoid conflicts. +*) + +let greedy_layout (f:Ll.fdecl) (live:liveness) : layout = + let n_arg = ref 0 in + let n_spill = ref 0 in + + let spill () = (incr n_spill; Alloc.LStk (- !n_spill)) in + + (* Allocates a destination location for an incoming function parameter. + Corner case: argument 3, in Rcx occupies a register used for other + purposes by the compiler. We therefore always spill it. + *) + let alloc_arg () = + let res = + match arg_loc !n_arg with + | Alloc.LReg Rcx -> spill () + | x -> x + in + incr n_arg; res + in + (* The available palette of registers. Excludes Rax and Rcx *) + let pal = LocSet.(caller_save + |> remove (Alloc.LReg Rax) + |> remove (Alloc.LReg Rcx) + ) + in + + (* Allocates a uid greedily based on liveness information *) + let allocate lo uid = + let loc = + try + let used_locs = + UidSet.fold (fun y -> LocSet.add (List.assoc y lo)) (live.live_in uid) LocSet.empty + in + let available_locs = LocSet.diff pal used_locs in + LocSet.choose available_locs + with + | Not_found -> spill () + in + Platform.verb @@ Printf.sprintf "allocated: %s <- %s\n" (Alloc.str_loc loc) uid; loc + in + + let lo = + fold_fdecl + (fun lo (x, _) -> (x, alloc_arg())::lo) + (fun lo l -> (l, Alloc.LLbl (Platform.mangle l))::lo) + (fun lo (x, i) -> + if insn_assigns i + then (x, allocate lo x)::lo + else (x, Alloc.LVoid)::lo) + (fun lo _ -> lo) + [] f in + { uid_loc = (fun x -> List.assoc x lo) + ; spill_bytes = 8 * !n_spill + } + + +(* better register allocation ----------------------------------------------- *) +(* TASK: Implement a (correct) register allocation strategy that + outperforms the greedy layout strategy given above, assuming that + the liveness information is calculated using the dataflow analysis + from liveness.ml. + + Your implementation does _not_ necessarily have to do full-blown + coalescing graph coloring as described in lecture. You may choose + a simpler strategy. In particular, a non-coalescing graph coloring + algorithm that uses some simple preference heuristics should be + able to beat the greedy algorithm. + + To measure the effectiveness of your strategy, our testing infrastructure + uses a simple heuristic to compare it with the 'greedy' strategy given above. + + QUALITY HEURISTIC: + The 'quality score' of a register assignment for an x86 program is based + on two things: + - the total number of memory accesses, which is the sum of: + - the number of Ind2 and Ind3 operands + - the number of Push and Pop instructions + + - size(p) the total number of instructions in the x86 program + + Your goal for register allocation should be to minimize the number of + memory operations and, secondarily, the overall size of the program. + + registers.ml provides some helper functions that you can use to + get the size and total number of memory operations in a program. It + also provides a function that computes a histogram of the register usage, + which can be helpful when testing your register allocator. + + To see whether your register assignment is better than the greedy one, + we check: + if #mem_ops(yours) < #mem_ops(greedy) then yours is better + otherwise if size(yours) < size(greedy) then yours is better + otherwise greedy wins. + + Hints: + - The Datastructures file provides a UidMap that can be used to + create your interference graph. + + - It may be useful to understand how this version of the compiler + deals with function calls (see compile_pmov) and what the + greedy allocator does. + + - The compiler uses Rax and Rcx in its code generation, so they + are _not_ generally available for your allocator to use. + + . other caller_save registers are freely available + + . if you want to use callee_save registers you might have to + adjust the code generated by compile_fdecl to save/restore them. +*) + +let better_layout (f:Ll.fdecl) (live:liveness) : layout = + failwith "Backend.better_layout not implemented" + + + +(* register allocation options ---------------------------------------------- *) +(* A trivial liveness analysis that conservatively says that every defined + uid is live across every edge. *) +let trivial_liveness (f:Ll.fdecl) : liveness = + let s = + fold_fdecl + (fun s (x, _) -> UidSet.add x s) + (fun s _ -> s) + (fun s (x, i) -> if insn_assigns i then UidSet.add x s else s) + (fun s _ -> s) + UidSet.empty f in + {live_in = (fun _ -> s); live_out = (fun _ -> s)} + +let liveness_fn : (Ll.fdecl -> liveness) ref = + ref trivial_liveness + +let layout_fn : (Ll.fdecl -> liveness -> layout) ref = + ref no_reg_layout + +(* Consistency check for layout, i.e., make sure that a layout does not use the + same location for variables that are live at the same time *) +let check_layout (lay:layout) (live:liveness) (f:Ll.fdecl) = + (* Check that uid is not allocated to the same location as any uid in s *) + let check_disjoint uid s = + let loc = lay.uid_loc uid in + if loc <> LVoid then + UidSet.iter + (fun v -> if v <> uid && loc = (lay.uid_loc v) then + failwith @@ + Printf.sprintf + "Invalid layout %s and %s both map to %s" + uid v (Alloc.str_loc loc)) + s + in + UidSet.iter + (fun x -> + let live_in = try (live.live_in x) with Not_found -> UidSet.empty in + UidSet.iter (fun y -> check_disjoint y live_in) live_in) + (fold_fdecl + (fun s (x, _) -> UidSet.add x s) + (fun s _ -> s) + (fun s (x, i) -> if insn_assigns i then UidSet.add x s else s) + (fun s _ -> s) + UidSet.empty f) + +let set_liveness name = + liveness_fn := match name with + | "trivial" -> trivial_liveness + | "dataflow" -> Liveness.get_liveness + | _ -> failwith "impossible arg" + +let set_regalloc name = + layout_fn := match name with + | "none" -> no_reg_layout + | "greedy" -> greedy_layout + | "better" -> better_layout + | _ -> failwith "impossible arg" + +(* Compile a function declaration using the chosen liveness analysis + and register allocation strategy. *) +let compile_fdecl tdecls (g:gid) (f:Ll.fdecl) : x86stream = + let liveness = !liveness_fn f in + let layout = !layout_fn f liveness in + (* + Help out students by checking that the layout is correct with + respect to liveness. + *) + let _ = check_layout layout liveness f in + let afdecl = alloc_fdecl layout liveness f in + [L (Platform.mangle g, true)] + >@ lift Asm.[ Pushq, [~%Rbp] + ; Movq, [~%Rsp; ~%Rbp] ] + >@ (if layout.spill_bytes <= 0 then [] else + lift Asm.[ Subq, [~$(layout.spill_bytes); ~%Rsp] ]) + >@ (compile_fbody tdecls afdecl) + +(* compile_gdecl ------------------------------------------------------------ *) + +let rec compile_ginit = function + | GNull -> [Quad (Lit 0L)] + | GGid gid -> [Quad (Lbl (Platform.mangle gid))] + | GInt c -> [Quad (Lit c)] + | GString s -> [Asciz s] + | GArray gs + | GStruct gs -> List.(flatten @@ map compile_gdecl gs) + | GBitcast (t1,g,t2) -> compile_ginit g + +and compile_gdecl (_, g) = compile_ginit g + +(* compile_prog ------------------------------------------------------------- *) + +let compile_prog {tdecls; gdecls; fdecls} : X86.prog = + let g = fun (lbl, gdecl) -> + Asm.data (Platform.mangle lbl) (compile_gdecl gdecl) + in + + let f = fun (name, fdecl) -> + prog_of_x86stream @@ compile_fdecl tdecls name fdecl + in + (List.map g gdecls) + @ List.(flatten @@ map f fdecls) diff --git a/hw6/cfg.ml b/hw6/cfg.ml new file mode 100644 index 0000000..21b0e32 --- /dev/null +++ b/hw6/cfg.ml @@ -0,0 +1,363 @@ +open Ll +open Llutil +open Datastructures + +(* control flow graphs ------------------------------------------------------ *) + +(* This representation of control-flow graphs is more suited for dataflow + analysis than the abstract syntax defined in Ll.fdecl + + - a cfg has: + blocks - a map of labels to Ll basic block, and + preds - a set of labels containing the blocks predecessors + ret_ty - the Ll return type of the function + args - a list of function parameters with their types + + Representing cfgs as maps makes it simpler to look up information + about the nodes in the graph. *) + +type cfg = { blocks : Ll.block LblM.t + ; preds : LblS.t LblM.t + ; ret_ty : Ll.ty + ; args : (Ll.uid * Ll.ty) list + } + +let entry_lbl = "_entry" + + +(* compute a block's successors --------------------------------------------- *) +let block_succs (b:block) : LblS.t = + match b.term with + | _, Ret _ -> LblS.empty + | _, Br l -> LblS.singleton l + | _, Cbr (_,k,l) -> LblS.of_list [k; l] + + +(* compute a map from block labels to predecessors -------------------------- *) +let cfg_preds (ast:(lbl * block) list): LblS.t LblM.t = + let set_add l = LblM.update_or LblS.empty (LblS.add l) in + List.fold_left (fun m (l, b) -> + m |> LblM.update_or LblS.empty (fun s -> s) l + |> LblS.fold (set_add l) (block_succs b)) LblM.empty ast + + +(* lookup operations -------------------------------------------------------- *) +let preds (g:cfg) (l:lbl) : LblS.t = LblM.find l g.preds +let succs (g:cfg) (l:lbl) : LblS.t = block_succs @@ LblM.find l g.blocks +let block (g:cfg) (l:lbl) : Ll.block = LblM.find l g.blocks +let nodes (g:cfg) : LblS.t = LblM.bindings g.blocks |> List.map fst |> LblS.of_list +let exits (g:cfg) : LblS.t = LblM.bindings g.blocks + |> List.filter + (fun (l, b) -> LblS.is_empty @@ block_succs b ) + |> List.map fst + |> LblS.of_list + +(* convert an Ll.fdecl to this representation ------------------------------- *) +let of_ast (fdecl:Ll.fdecl) : cfg = + let e,bs = fdecl.f_cfg in + let ast = (entry_lbl,e)::bs in + let preds = cfg_preds ast in + let blocks = List.fold_left + (fun g (l, block) -> LblM.add l block g) + LblM.empty ast + in + let paramtys, ret_ty = fdecl.f_ty in + let args = List.combine fdecl.f_param paramtys in + { preds; blocks; ret_ty; args} + +(* convert this representation back to Ll.cfg ------------------------------- *) +let to_ast (g:cfg) : Ll.fdecl = + let e = block g entry_lbl in + let f_cfg = e, g.blocks |> LblM.bindings |> List.remove_assoc entry_lbl in + let f_param, paramtys = List.split g.args in + {f_cfg; f_param; f_ty=paramtys,g.ret_ty; } + +let add_block (l:lbl) (block:block) (g:cfg) : cfg = + {g with blocks=LblM.add l block g.blocks } + + + +(* creating a flow graph from a control flow graph -------------------------- *) + +(* Conceptually, this is a view of a cfg annotated with dataflow information + that should be usable by the generic solver and subsequent optimizations. + + To create a flow graph module for a particular analysis, we need to supply + several parameters: *) +module type AS_GRAPH_PARAMS = + sig + (* The type of dataflow facts and the combine operator. This just implements + the FACT interface from cfg.ml *) + type t + val combine : t list -> t + val to_string : t -> string + + (* We also need to specify the direction of the analysis *) + val forwards : bool + + (* The flow functions defined on the CFG. *) + (* Flow functions across an instruction or terminator + for forward analysis: should map in[n] to out[n] + for backward analysis: should map out[n] to in[n] + *) + val insn_flow : (uid * insn) -> t -> t + val terminator_flow : terminator -> t -> t + end + +(* This Cfg.AsGraph can be used to create a flow graph for the solver from a + control flow graph with of_cfg *) +module AsGraph (D:AS_GRAPH_PARAMS) : + sig + (* Implement the DFA_GRAPH signature where facts are defined by the functor + argument type t and nodes are blocks of the cfg identified by labels *) + include Solver.DFA_GRAPH + with type fact := D.t + and module NodeS = LblS + + (* To use the resulting flow graph in optimizations, we need expose a few + more operations: *) + + (* Create a flow graph for this analysis an initial mapping of facts for + block labels, a constant flow-in value for the entry or exit labels depending + on the direction of the analysis, and a CFG *) + val of_cfg : (node -> D.t) -> D.t -> cfg -> t + + (* We need to be able to look up the resulting solved dataflow analysis facts + per block and per instruction. We also need to be able to inspect the + input and output information for each. + The way we compute this information depends on the direction of the + analysis. + uid_in and uid_out work for both instructions and terminators + the provided lbl is that of the containing block + *) + + val block_in : t -> lbl -> D.t + val block_out : t -> lbl -> D.t + val uid_in : t -> lbl -> uid -> D.t + val uid_out : t -> lbl -> uid -> D.t + + (* For testing purposes, we would like to be able to access the underlying + map of dataflow facts *) + val dfa : t -> D.t LblM.t + end = + struct + module NodeS = LblS + + type t = { cfg:cfg + ; dfa:D.t LblM.t } + + (* We use _blocks_ of the control flow graph as the nodes of the dataflow + graph. Each block is identified by its lbl. + + This choice means that we won't use the "exploded" control-flow graph, where + each instruction is considered a node. The reason for this decision is two-fold: + One: the edges of the cfg are defined in terms of block labesl. + Two: we can speed up the dataflow analysis by propagating information across and + entire block. + The cost of this decision is that we have to re-calculate the flow information + for individual instructions when we need it. + *) + type node = lbl + + (* The label of the logical "boundary" node. This boundary node represents + a logical predecessor of the entry block (for forward analysis) or the + logical successor of the exits blocks (for backward analysis). It provides + an "edge" on which to put the entry/exit flow information. *) + let bound_lbl = "__bound" + + (* The only way to create a flow graph is to provide an initial labeling *) + let of_cfg init flow_in cfg = + let dfa = cfg.blocks + |> LblM.mapi (fun l _ -> init l) + |> LblM.add bound_lbl flow_in + in + { cfg; dfa } + + (* Access to underlying cfg and facts map *) + let block g = block g.cfg + + let nodes g = nodes g.cfg |> NodeS.add bound_lbl + + let dfa g = LblM.remove bound_lbl g.dfa + + (* Create the dfa successors and predecessors based on the direction of the + data flow analysis. This also adds the boundary node to the succs/preds. + + This graph is build at the "block" level, so nodes are block labels. + *) + let extend k v f l = if LblS.mem l k then v else f l + let ns = NodeS.singleton + + let dfa_preds = + if D.forwards + then fun g -> (preds g.cfg) + |> extend (ns entry_lbl) (ns bound_lbl) + |> extend (ns bound_lbl) NodeS.empty + else fun g -> (succs g.cfg) + |> extend (exits g.cfg) (ns bound_lbl) + |> extend (ns bound_lbl) NodeS.empty + + let dfa_succs = + if D.forwards + then fun g -> extend (ns bound_lbl) (ns entry_lbl) (succs g.cfg) + else fun g -> extend (ns bound_lbl) (exits g.cfg) (preds g.cfg) + + let preds = dfa_preds + let succs = dfa_succs + + (* Block flow function *) + (* dataflow analysis helpers ------------------------------------------------ *) + + (* Propagate dataflow information forward through a whole block. + - fi is the flow function for instructions + - ft is the flow function for terminators + - d_in is the dataflow fact on the in edge + Returns the resulting out / in fact. *) + let block_flow_forwards ({insns; term}:block) (d_in:'d) : 'd = + let d_tmn = List.fold_left (fun d (u,i) -> D.insn_flow (u,i) d) d_in insns in + D.terminator_flow (snd term) d_tmn + + let block_flow_backwards ({insns; term}:block) (d_out:'d) : 'd = + let d_ins = D.terminator_flow (snd term) d_out in + List.fold_right (fun (u,i) d -> D.insn_flow (u,i) d) insns d_ins + + let flow_block g l d = + (if D.forwards then block_flow_forwards else block_flow_backwards) (block g l) d + + (* The supplied flow function, plus the boundary value. Used by the solver. *) + let flow g (l:lbl) = + if Lbl.compare l bound_lbl == 0 + then fun _ -> LblM.find l g.dfa + else flow_block g l + + (* Look up and modify facts when viewing the CFG as a dataflow graph, used by the solver. *) + let out g n = LblM.find n g.dfa + let add_fact n d g = { g with dfa=LblM.add n d g.dfa } + + (* Because the cfg instance of the dataflow graph uses _basic blocks_ as nodes, + we need a way to recover the dataflow facts at individual instructions + within the block. Depending on the direction of the analysis, this amounts to + propagating information either forward or backwards through the block. + + The following helper functions construct maps from each instruction or terminator + to the corresponding dataflow fact. *) + + (* Compute IN[n] for each instruction in a block, given IN of the first instruction *) + let in_forwards_map + ({insns; term}:block) (d_in:'d) : uid -> 'd = + let t_id, t = term in + let m, d_tmn = List.fold_left + (fun (m, d) (u,i) -> + let d' = D.insn_flow (u,i) d in + UidM.add u d m, d') + (UidM.empty, d_in) + insns + in + let m' = UidM.add t_id d_tmn m in + fun u -> UidM.find u m' + + (* Compute OUT[n] for each instruction in a block, given IN of the first instruction *) + let out_forwards_map + ({insns; term}:block) (d_in:'d) : uid -> 'd = + let t_id, t = term in + let m, d_tmn = List.fold_left + (fun (m, d_in) (u,i) -> + let d_out = D.insn_flow (u, i) d_in in + UidM.add u d_out m, d_out) + (UidM.empty, d_in) + insns + in + let d_out = D.terminator_flow t d_tmn in + let m' = UidM.add t_id d_out m in + fun u -> UidM.find u m' + + (* Compute IN[n] for each instruction in a block, given OUT of the terminator*) + let in_backwards_map + ({insns; term}:block) (d_out:'d) : uid -> 'd = + let t_id, t = term in + let d_ins = D.terminator_flow t d_out in + let m_init = UidM.add t_id d_ins UidM.empty in + let m, _ = List.fold_right (fun (u,i) (m, d_out) -> + let d_in = D.insn_flow (u,i) d_out in + UidM.add u d_in m, d_in) + insns (m_init, d_ins) in + fun u -> UidM.find u m + + (* Compute OUT[n] for each instruction in a block, given OUT of the terminator*) + let out_backwards_map + ({insns; term}:block) (d_out:'d) : uid -> 'd = + let t_id, t = term in + let m_init = UidM.add t_id d_out UidM.empty in + let d_ins = D.terminator_flow t d_out in + let m, _ = List.fold_right (fun (u,i) (m, d_out) -> + let d_in = D.insn_flow (u,i) d_out in + UidM.add u d_out m, d_in) + insns (m_init, d_ins) in + fun u -> UidM.find u m + + + (* Wrapper functions to account for directionality of the analysis *) + let block_in g n = + if D.forwards then + let preds = NodeS.elements @@ preds g n in + let d_outs = List.map (out g) preds in + D.combine d_outs + else + out g n + + let block_out g n = + if D.forwards then + out g n + else + let preds = NodeS.elements @@ preds g n in + let d_outs = List.map (out g) preds in + D.combine d_outs + + let uid_in g (l:lbl) = + if D.forwards then + in_forwards_map (block g l) (block_in g l) + else + in_backwards_map (block g l) (block_out g l) + + let uid_out g (l:lbl) = + if D.forwards then + out_forwards_map (block g l) (block_in g l) + else + out_backwards_map (block g l) (block_out g l) + + (* Printing functions *) + (* printing functions ------------------------------------------------------- *) + + let annot_insn g l (u,i:uid*insn) = + Printf.sprintf " IN : %s\n %s\n OUT: %s" + (D.to_string (uid_in g l u)) + (Llutil.string_of_named_insn (u,i)) + (D.to_string (uid_out g l u)) + + let annot_terminator g l (u,t:uid*terminator) = + Printf.sprintf " IN : %s\n %s\n OUT: %s" + (D.to_string (uid_in g l u)) + (Llutil.string_of_terminator t) + (D.to_string (uid_out g l u)) + + let to_string_annot (annot:lbl -> string) (g:t) : string = + LblM.to_string + (fun l block -> + Printf.sprintf "%s\n%s\n%s\n\n" + (annot l) + (Llutil.mapcat "\n" (annot_insn g l) (block.insns)) + (annot_terminator g l (block.term)) + ) (g.cfg.blocks) + + let printer_annot (annot:lbl -> string) (f:Format.formatter) (g:t) : unit = + Format.pp_print_string f (to_string_annot annot g) + + let to_string g = + to_string_annot (fun l -> D.to_string (out g l)) g + + let printer f g = + printer_annot (fun l -> D.to_string (out g l)) f g + end + +(* exported type *) +type t = cfg diff --git a/hw6/cinterop.c b/hw6/cinterop.c new file mode 100644 index 0000000..24f8786 --- /dev/null +++ b/hw6/cinterop.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +void ll_puts(int8_t *s) { + puts((char *)s); +} + +int8_t* ll_strcat(int8_t* s1, int8_t* s2) { + int l1 = strlen((char*)s1); + int l2 = strlen((char*)s2); + char* buf = (char*)calloc(l1 + l2 + 1, sizeof(char)); + strncpy(buf, (char*)s1, l1); + strncpy(buf + l1, (char*)s2, l2+1); + return (int8_t*) buf; +} + +int64_t ll_callback(int64_t (*fun)(int64_t, int64_t)) { + int64_t x = 19L; + return fun(x, x); +} + +int8_t* ll_ltoa(int64_t i) { + char* buf = (char*)calloc(20, sizeof(char)); + snprintf((char *)buf, 20, "%ld", (long)i); + return (int8_t *)buf; +} + +void *ll_malloc(int64_t n, int64_t size) { + return calloc(n, size); +} diff --git a/hw6/constprop.ml b/hw6/constprop.ml new file mode 100644 index 0000000..6cbf240 --- /dev/null +++ b/hw6/constprop.ml @@ -0,0 +1,102 @@ +open Ll +open Datastructures + +(* The lattice of symbolic constants ---------------------------------------- *) +module SymConst = + struct + type t = NonConst (* Uid may take on multiple values at runtime *) + | Const of int64 (* Uid will always evaluate to const i64 or i1 *) + | UndefConst (* Uid is not defined at the point *) + + let compare s t = + match (s, t) with + | (Const i, Const j) -> Int64.compare i j + | (NonConst, NonConst) | (UndefConst, UndefConst) -> 0 + | (NonConst, _) | (_, UndefConst) -> 1 + | (UndefConst, _) | (_, NonConst) -> -1 + + let to_string : t -> string = function + | NonConst -> "NonConst" + | Const i -> Printf.sprintf "Const (%LdL)" i + | UndefConst -> "UndefConst" + + + end + +(* The analysis computes, at each program point, which UIDs in scope will evaluate + to integer constants *) +type fact = SymConst.t UidM.t + + + +(* flow function across Ll instructions ------------------------------------- *) +(* - Uid of a binop or icmp with const arguments is constant-out + - Uid of a binop or icmp with an UndefConst argument is UndefConst-out + - Uid of a binop or icmp with an NonConst argument is NonConst-out + - Uid of stores and void calls are UndefConst-out + - Uid of all other instructions are NonConst-out + *) +let insn_flow (u,i:uid * insn) (d:fact) : fact = + failwith "Constprop.insn_flow unimplemented" + +(* The flow function across terminators is trivial: they never change const info *) +let terminator_flow (t:terminator) (d:fact) : fact = d + +(* module for instantiating the generic framework --------------------------- *) +module Fact = + struct + type t = fact + let forwards = true + + let insn_flow = insn_flow + let terminator_flow = terminator_flow + + let normalize : fact -> fact = + UidM.filter (fun _ v -> v != SymConst.UndefConst) + + let compare (d:fact) (e:fact) : int = + UidM.compare SymConst.compare (normalize d) (normalize e) + + let to_string : fact -> string = + UidM.to_string (fun _ v -> SymConst.to_string v) + + (* The constprop analysis should take the meet over predecessors to compute the + flow into a node. You may find the UidM.merge function useful *) + let combine (ds:fact list) : fact = + failwith "Constprop.Fact.combine unimplemented" + end + +(* instantiate the general framework ---------------------------------------- *) +module Graph = Cfg.AsGraph (Fact) +module Solver = Solver.Make (Fact) (Graph) + +(* expose a top-level analysis operation ------------------------------------ *) +let analyze (g:Cfg.t) : Graph.t = + (* the analysis starts with every node set to bottom (the map of every uid + in the function to UndefConst *) + let init l = UidM.empty in + + (* the flow into the entry node should indicate that any parameter to the + function is not a constant *) + let cp_in = List.fold_right + (fun (u,_) -> UidM.add u SymConst.NonConst) + g.Cfg.args UidM.empty + in + let fg = Graph.of_cfg init cp_in g in + Solver.solve fg + + +(* run constant propagation on a cfg given analysis results ----------------- *) +(* HINT: your cp_block implementation will probably rely on several helper + functions. *) +let run (cg:Graph.t) (cfg:Cfg.t) : Cfg.t = + let open SymConst in + + + let cp_block (l:Ll.lbl) (cfg:Cfg.t) : Cfg.t = + let b = Cfg.block cfg l in + let cb = Graph.uid_out cg l in + failwith "Constprop.cp_block unimplemented" + in + + LblS.fold cp_block (Cfg.nodes cfg) cfg diff --git a/hw6/datastructures.ml b/hw6/datastructures.ml new file mode 100644 index 0000000..26cfaba --- /dev/null +++ b/hw6/datastructures.ml @@ -0,0 +1,117 @@ +(** Data structures, signatures *) + +(** Comparable, printable type *) +module type OrdPrintT = + sig + type t + val compare : t -> t -> int + val to_string : t -> string + end + +(** Extended sets *) +module type SetS = + sig + include Set.S + val of_list : elt list -> t (* added to Set.S in OCaml 4.02 *) + val to_string : t -> string + val string_of_elt : elt -> string + val printer : Format.formatter -> t -> unit + end + +module MakeSet (Ord : OrdPrintT) : SetS with type elt = Ord.t = + struct + include Set.Make (Ord) + + let of_list = List.fold_left (fun s e -> add e s) empty + + let to_string t = + let s = elements t + |> List.map Ord.to_string + |> String.concat ", " + in + "{" ^ s ^ "}" + + let string_of_elt = Ord.to_string + + let printer f t = Format.pp_print_string f (to_string t) + + end + +(** Extended maps *) +module type MapS = + sig + include Map.S + val update : ('a -> 'a) -> key -> 'a t -> 'a t + val find_or : 'a -> 'a t -> key -> 'a + val update_or : 'a -> ('a -> 'a) -> key -> 'a t -> 'a t + val diff_keys : ('a -> 'a -> int) -> 'a t -> 'a t -> key list + val to_string : (key -> 'a -> string) -> 'a t -> string + val printer : (key -> 'a -> string) -> Format.formatter -> 'a t -> unit + end + +module MakeMap (Ord : OrdPrintT) : MapS with type key = Ord.t = + struct + include Map.Make (Ord) + + let update f k m = + add k (f @@ find k m) m + + let find_or d m k = + try find k m with Not_found -> d + + let diff_keys cmp_v m n = + let module S = MakeSet(Ord) in + let has_binding_or_add m k v l = + try if cmp_v v @@ find k m == 0 then l else S.add k l + with Not_found -> S.add k l + in + S.empty |> fold (has_binding_or_add n) m + |> fold (has_binding_or_add m) n + |> S.elements + + let update_or d f k m = + add k (f @@ find_or d m k) m + + let to_string val_str t = + let s = bindings t + |> List.map (fun (k,v) -> Ord.to_string k ^ "=" ^ val_str k v) + |> String.concat ", " + in + "{" ^ s ^ "}" + + let printer val_str f t = Format.pp_print_string f (to_string val_str t) + + end + +(** Useful instances *) + +module Lbl = + struct + type t = Ll.lbl + let compare = String.compare + let to_string l = l + end + +module LblM = MakeMap (Lbl) +module LblS = MakeSet (Lbl) + +module Uid = + struct + type t = Ll.uid + let compare = String.compare + let to_string u = "%" ^ u + end + +module UidS = MakeSet (Uid) +module UidM = MakeMap (Uid) + + +(** For testing *) +let uidm (b:(Ll.uid * 'a) list) : 'a UidM.t = + List.fold_left (fun m (k,v) -> UidM.add k v m) UidM.empty b + +let lblm (b:(Ll.lbl * 'a) list) : 'a LblM.t = + List.fold_left (fun m (k,v) -> LblM.add k v m) LblM.empty b + +let uids (l:Ll.uid list) : UidS.t = UidS.of_list l +let lbls (l:Ll.lbl list) : LblS.t = LblS.of_list l diff --git a/hw6/dce.ml b/hw6/dce.ml new file mode 100644 index 0000000..93704b1 --- /dev/null +++ b/hw6/dce.ml @@ -0,0 +1,44 @@ +(** Dead Code Elimination *) +open Ll +open Datastructures + + +(* expose a top-level analysis operation ------------------------------------ *) +(* TASK: This function should optimize a block by removing dead instructions + - lb: a function from uids to the live-OUT set at the + corresponding program point + - ab: the alias map flowing IN to each program point in the block + - b: the current ll block + + Note: + Call instructions are never considered to be dead (they might produce + side effects) + + Store instructions are not dead if the pointer written to is live _or_ + the pointer written to may be aliased. + + Other instructions are dead if the value they compute is not live. + + Hint: Consider using List.filter + *) +let dce_block (lb:uid -> Liveness.Fact.t) + (ab:uid -> Alias.fact) + (b:Ll.block) : Ll.block = + failwith "Dce.dce_block unimplemented" + +let run (lg:Liveness.Graph.t) (ag:Alias.Graph.t) (cfg:Cfg.t) : Cfg.t = + + LblS.fold (fun l cfg -> + let b = Cfg.block cfg l in + + (* compute liveness at each program point for the block *) + let lb = Liveness.Graph.uid_out lg l in + + (* compute aliases at each program point for the block *) + let ab = Alias.Graph.uid_in ag l in + + (* compute optimized block *) + let b' = dce_block lb ab b in + Cfg.add_block l b' cfg + ) (Cfg.nodes cfg) cfg + diff --git a/hw6/driver.ml b/hw6/driver.ml new file mode 100644 index 0000000..1f67d49 --- /dev/null +++ b/hw6/driver.ml @@ -0,0 +1,162 @@ +open Printf +open Platform + +(* configuration flags ------------------------------------------------------ *) +let print_ll_flag = ref false +let print_x86_flag = ref false +let print_ast_flag = ref false +let print_oat_flag = ref false +let clang = ref false +let assemble = ref true +let link = ref true +let executable_filename = ref "a.out" +let execute_x86 = ref false +let print_regs_flag = ref false + +let link_files = ref [] +let add_link_file path = + link_files := path :: (!link_files) +let files : string list ref = ref [] + +let print_banner s = + let rec dashes n = if n = 0 then "" else "-"^(dashes (n-1)) in + printf "%s %s\n%!" (dashes (79 - (String.length s))) s + +let print_ll file ll_ast = + print_banner (file ^ ".ll"); + print_endline (Llutil.string_of_prog ll_ast) + +let print_x86 file asm_str = + print_banner file; + print_endline asm_str + +let read_file (file:string) : string = + let channel = open_in file in + let lines = ref [] in + try while true; do + lines := input_line channel :: !lines + done; "" + with End_of_file -> + close_in channel; + String.concat "\n" (List.rev !lines) + +let write_file (file:string) (out:string) = + let channel = open_out file in + fprintf channel "%s" out; + close_out channel + +let parse_ll_file filename = + let program = read_file filename |> + Lexing.from_string |> + Llparser.prog Lllexer.token + in + program + +let parse_oat_file filename = + let lexbuf = read_file filename |> + Lexing.from_string + in + try + Parser.prog Lexer.token lexbuf + with + | Parser.Error -> failwith @@ Printf.sprintf "Parse error at: %s" + (Range.string_of_range (Range.lex_range lexbuf)) + + +let print_oat file ll_ast = + print_banner (file ^ ".oat"); + Astlib.print_prog ll_ast + +let print_ast p = Printf.printf "\n%s\n\n" (Astlib.ml_string_of_prog p) + +let run_executable args executable = + let cmd = sprintf "%s%s %s" dot_path executable args in + sh cmd (fun _ i -> i) + +let run_executable_to_tmpfile arg pr tmp = + let cmd = sprintf "%s%s %d > %s 2>&1" dot_path pr arg tmp in + sh cmd ignore_error + +let run_program (args:string) (executable:string) (tmp_out:string) : string = + let cmd = sprintf "%s%s %s > %s 2>&1" dot_path executable args tmp_out in + let result = sh cmd (fun _ i -> i) in + (read_file tmp_out) ^ (string_of_int result) + +let process_ll_ast path file ll_ast = + if !print_ll_flag then print_ll file ll_ast; + let dot_s_file = Platform.gen_name !Platform.output_path file ".s" in + let dot_o_file = Platform.gen_name !Platform.output_path file ".o" in + if !clang + then (Platform.verb "..compiling with clang\n"; + Platform.clang_compile path dot_s_file; + if !print_x86_flag + then (print_banner dot_s_file; + Platform.sh (Printf.sprintf "cat %s" dot_s_file) Platform.raise_error)) + else ( + Platform.verb "..compiling with backend\n"; + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + if !print_regs_flag then begin + let (h,size) = Registers.histogram_of_prog asm_ast in + Printf.printf "%s\n" (Registers.string_of_histogram h); + Printf.printf "Summary: %d\n" (Registers.summary h); + Printf.printf "#instructions = %d\n" size + end; + if !print_x86_flag then begin + print_x86 dot_s_file asm_str + end; + write_file dot_s_file asm_str); + if !assemble then Platform.assemble dot_s_file dot_o_file; + add_link_file dot_o_file + +let string_of_ll_ast path ll_ast = + let ll_str = Llutil.string_of_prog ll_ast in + let prog = Printf.sprintf "; generated from: %s\ntarget triple = \"%s\"\n%s\n" + path !Platform.target_triple ll_str in + prog + +let process_ll_file path file = + Platform.verb @@ Printf.sprintf "* processing file: %s\n" path; + let ll_ast = parse_ll_file path in + let ll_ast = Opt.optimize ll_ast in + process_ll_ast path file ll_ast + +let process_oat_ast path file oat_ast = + if !print_oat_flag then print_oat file oat_ast; + if !print_ast_flag then print_ast oat_ast; + Platform.verb @@ Printf.sprintf "..typechecking"; + Typechecker.typecheck_program oat_ast; + Platform.verb @@ Printf.sprintf "..frontend"; + let ll_ast = Frontend.cmp_prog oat_ast in + let ll_ast = Opt.optimize ll_ast in + let dot_ll_file = Platform.gen_name !Platform.output_path file ".ll" in + Platform.verb @@ Printf.sprintf "..writing file: %s\n" dot_ll_file; + let prog = string_of_ll_ast path ll_ast in + write_file dot_ll_file prog; + process_ll_ast dot_ll_file file ll_ast + +let process_oat_file path basename = + Platform.verb @@ Printf.sprintf "* processing file: %s\n" path; + let oat_ast = parse_oat_file path in + process_oat_ast path basename oat_ast + +let process_file path = + let basename, ext = Platform.path_to_basename_ext path in + begin match ext with + | "oat" -> process_oat_file path basename + | "ll" -> process_ll_file path basename + | "o" -> add_link_file path + | "c" -> add_link_file path + | _ -> failwith @@ Printf.sprintf "found unsupported file type: %s" path + end + +let process_files files = + if (List.length files) > 0 then begin + List.iter process_file files; + ( if !assemble && !link then + Platform.link (List.rev !link_files@["runtime.c"]) !executable_filename ); + ( if !assemble && !link && !execute_x86 then + let ret = run_executable "" !executable_filename in + print_banner @@ Printf.sprintf "Executing: %s" !executable_filename; + Printf.printf "* %s returned %d\n" !executable_filename ret ) + end diff --git a/hw6/dune b/hw6/dune new file mode 100644 index 0000000..6689e6e --- /dev/null +++ b/hw6/dune @@ -0,0 +1,32 @@ +(menhir + (modules ll/llparser) + (infer true) + (merge_into llparser)) + +(menhir + (modules parser) + (infer true) + (merge_into parser)) + +(rule + (target lllexer.ml) + (deps ll/lllexer.mll) + (action (run ocamllex -o %{target} %{deps}))) + +(rule + (target lexer.ml) + (deps lexer.mll) + (action (run ocamllex -o %{target} %{deps}))) + + + +(executable + (name main) + (modules (:standard \ ll-original frontend-break)) + (libraries unix str num)) + +(env +(dev +(flags (:standard -warn-error -A -no-strict-formats)))) + +(include_subdirs unqualified) diff --git a/hw6/dune-project b/hw6/dune-project new file mode 100644 index 0000000..8695e4a --- /dev/null +++ b/hw6/dune-project @@ -0,0 +1,2 @@ +(lang dune 2.9) +(using menhir 2.0) \ No newline at end of file diff --git a/hw6/frontend-break.ml b/hw6/frontend-break.ml new file mode 100644 index 0000000..8176d84 --- /dev/null +++ b/hw6/frontend-break.ml @@ -0,0 +1,688 @@ +open Ll +open Llutil +open Ast + +(* instruction streams ------------------------------------------------------ *) + +(* As in the last project, we'll be working with a flattened representation + of LLVMlite programs to make emitting code easier. This version + additionally makes it possible to emit elements will be gathered up and + "hoisted" to specific parts of the constructed CFG + - G of gid * Ll.gdecl: allows you to output global definitions in the middle + of the instruction stream. You will find this useful for compiling string + literals + - E of uid * insn: allows you to emit an instruction that will be moved up + to the entry block of the current function. This will be useful for + compiling local variable declarations +*) + +type elt = + | L of Ll.lbl (* block labels *) + | I of uid * Ll.insn (* instruction *) + | T of Ll.terminator (* block terminators *) + | G of gid * Ll.gdecl (* hoisted globals (usually strings) *) + | E of uid * Ll.insn (* hoisted entry block instructions *) + +type stream = elt list +let ( >@ ) x y = y @ x +let ( >:: ) x y = y :: x +let lift : (uid * insn) list -> stream = List.rev_map (fun (x,i) -> I (x,i)) + +(* Build a CFG and collection of global variable definitions from a stream *) +let cfg_of_stream (code:stream) : Ll.cfg * (Ll.gid * Ll.gdecl) list = + let gs, einsns, insns, term_opt, blks = List.fold_left + (fun (gs, einsns, insns, term_opt, blks) e -> + match e with + | L l -> + begin match term_opt with + | None -> + if (List.length insns) = 0 then (gs, einsns, [], None, blks) + else failwith @@ Printf.sprintf "build_cfg: block labeled %s has\ + no terminator" l + | Some term -> + (gs, einsns, [], None, (l, {insns; term})::blks) + end + | T t -> (gs, einsns, [], Some (Llutil.Parsing.gensym "tmn", t), blks) + | I (uid,insn) -> (gs, einsns, (uid,insn)::insns, term_opt, blks) + | G (gid,gdecl) -> ((gid,gdecl)::gs, einsns, insns, term_opt, blks) + | E (uid,i) -> (gs, (uid, i)::einsns, insns, term_opt, blks) + ) ([], [], [], None, []) code + in + match term_opt with + | None -> failwith "build_cfg: entry block has no terminator" + | Some term -> + let insns = einsns @ insns in + ({insns; term}, blks), gs + + +(* compilation contexts ----------------------------------------------------- *) + +(* To compile OAT variables, we maintain a mapping of source identifiers to the + corresponding LLVMlite operands. Bindings are added for global OAT variables + and local variables that are in scope. *) + +module Ctxt = struct + + type t = (Ast.id * (Ll.ty * Ll.operand)) list + let empty = [] + + (* Add a binding to the context *) + let add (c:t) (id:id) (bnd:Ll.ty * Ll.operand) : t = (id,bnd)::c + + (* Lookup a binding in the context *) + let lookup (id:Ast.id) (c:t) : Ll.ty * Ll.operand = + List.assoc id c + +end + +(* Mapping of identifiers representing struct definitions to + * the corresponding name-to-name-to-type map. + + Note: You will need to use these operations when compiling structures. +*) +module TypeCtxt = struct + type t = (Ast.id * Ast.field list) list + let empty = [] + + let add c id bnd = (id, bnd) :: c + let lookup id c = List.assoc id c + let lookup_field st_name f_name (c : t) = + let rec lookup_field_aux f_name l = + match l with + | [] -> failwith "TypeCtxt.lookup_field: Not_found" + | h :: t -> if h.fieldName = f_name then h.ftyp else lookup_field_aux f_name t in + lookup_field_aux f_name (List.assoc st_name c) + + let rec index_of f l i = + match l with + | [] -> None + | h :: t -> if h.fieldName = f then Some i else index_of f t (i + 1) + + (* Return the index of a field in the struct. *) + let index_of_field_opt st f (c : t) = + index_of f (List.assoc st c) 0 + + let index_of_field st f c = + match index_of_field_opt st f c with + | None -> failwith "index_of_field: Not found" + | Some x -> x + + (* Return a pair of base type and index into struct *) + let rec lookup_field_name f (c : t) = + match c with + | [] -> failwith "lookup_field_name: Not found" + | (id, field) :: t -> + match index_of f field 0 with + | None -> lookup_field_name f t + | Some x -> List.(nth field x).ftyp, Int64.of_int x +end + +(* compiling OAT types ------------------------------------------------------ *) + +(* The mapping of source types onto LLVMlite is straightforward. Booleans and ints + are represented as the the corresponding integer types. OAT strings are + pointers to bytes (I8). Arrays are the most interesting type: they are + represented as pointers to structs where the first component is the number + of elements in the following array. + + NOTE: structure types are named, so they compile to their named form +*) + +let rec cmp_ty (ct : TypeCtxt.t) : Ast.ty -> Ll.ty = function + | Ast.TBool -> I1 + | Ast.TInt -> I64 + | Ast.TRef r -> Ptr (cmp_rty ct r) + | Ast.TNullRef r -> Ptr (cmp_rty ct r) + + +and cmp_ret_ty ct : Ast.ret_ty -> Ll.ty = function + | Ast.RetVoid -> Void + | Ast.RetVal t -> cmp_ty ct t + +and cmp_fty ct (ts, r) : Ll.fty = + List.map (cmp_ty ct) ts, cmp_ret_ty ct r + +and cmp_rty ct : Ast.rty -> Ll.ty = function + | Ast.RString -> I8 + | Ast.RArray u -> Struct [I64; Array(0, cmp_ty ct u)] + | Ast.RStruct r -> Namedt r + | Ast.RFun (ts, t) -> + let args, ret = cmp_fty ct (ts, t) in + Fun (args, ret) + +let typ_of_binop : Ast.binop -> Ast.ty * Ast.ty * Ast.ty = function + | Add | Mul | Sub | Shl | Shr | Sar | IAnd | IOr -> (TInt, TInt, TInt) + | Eq | Neq | Lt | Lte | Gt | Gte -> (TInt, TInt, TBool) + | And | Or -> (TBool, TBool, TBool) + +let typ_of_unop : Ast.unop -> Ast.ty * Ast.ty = function + | Neg | Bitnot -> (TInt, TInt) + | Lognot -> (TBool, TBool) + + +(* Some useful helper functions *) + +(* Generate a fresh temporary identifier. Since OAT identifiers cannot begin + with an underscore, these should not clash with any source variables *) +let gensym : string -> string = + let c = ref 0 in + fun (s:string) -> incr c; Printf.sprintf "_%s%d" s (!c) + +(* Amount of space an Oat type takes when stored in the satck, in bytes. + Note that since structured values are manipulated by reference, all + Oat values take 8 bytes on the stack. +*) +let size_oat_ty (t : Ast.ty) = 8L + + +(* Amount of size that needs to be allocated to store a structure *) +let rec size_oat_struct (l : Ast.field list) = + match l with + | [] -> 0L + | f :: t -> Int64.(add (size_oat_struct t) (size_oat_ty f.ftyp)) + +(* Generate code to allocate an array of source type TRef (RArray t) of the + given size. Note "size" is an operand whose value can be computed at + runtime *) +let oat_alloc_array ct (t:Ast.ty) (size:Ll.operand) : Ll.ty * operand * stream = + let ans_id, arr_id = gensym "array", gensym "raw_array" in + let ans_ty = cmp_ty ct @@ TRef (RArray t) in + let arr_ty = Ptr I64 in + ans_ty, Id ans_id, lift + [ arr_id, Call(arr_ty, Gid "oat_alloc_array", [I64, size]) + ; ans_id, Bitcast(arr_ty, Id arr_id, ans_ty) ] + + +(* Allocates an oat structure on the + heap and returns a target operand with the appropriate reference. + + - generate a call to 'oat_malloc' and use bitcast to conver the + resulting pointer to the right type + + - make sure to calculate the correct amount of space to allocate! +*) +let oat_alloc_struct ct (id:Ast.id) : Ll.ty * operand * stream = + let ret_id, arr_id = gensym "struct", gensym "raw_struct" in + let ans_ty = cmp_ty ct (TRef (RStruct id)) in + let arr_ty = Ptr I64 in + ans_ty, Id ret_id, lift + [ arr_id, Call(arr_ty, Gid "oat_malloc", [I64, Const (size_oat_struct (TypeCtxt.lookup id ct))]) + ; ret_id, Bitcast(arr_ty, Id arr_id, ans_ty) ] + + +let str_arr_ty s = Array(1 + String.length s, I8) +let i1_op_of_bool b = Ll.Const (if b then 1L else 0L) +let i64_op_of_int i = Ll.Const (Int64.of_int i) + +let cmp_binop t (b : Ast.binop) : Ll.operand -> Ll.operand -> Ll.insn = + let ib b op1 op2 = Ll.Binop (b, t, op1, op2) in + let ic c op1 op2 = Ll.Icmp (c, t, op1, op2) in + match b with + | Ast.Add -> ib Ll.Add + | Ast.Mul -> ib Ll.Mul + | Ast.Sub -> ib Ll.Sub + | Ast.And -> ib Ll.And + | Ast.IAnd -> ib Ll.And + | Ast.IOr -> ib Ll.Or + | Ast.Or -> ib Ll.Or + | Ast.Shl -> ib Ll.Shl + | Ast.Shr -> ib Ll.Lshr + | Ast.Sar -> ib Ll.Ashr + + | Ast.Eq -> ic Ll.Eq + | Ast.Neq -> ic Ll.Ne + | Ast.Lt -> ic Ll.Slt + | Ast.Lte -> ic Ll.Sle + | Ast.Gt -> ic Ll.Sgt + | Ast.Gte -> ic Ll.Sge + +(* Compiles an expression exp in context c, outputting the Ll operand that will + recieve the value of the expression, and the stream of instructions + implementing the expression. +*) +let rec cmp_exp (tc : TypeCtxt.t) (c:Ctxt.t) (exp:Ast.exp node) : Ll.ty * Ll.operand * stream = + match exp.elt with + | Ast.CInt i -> I64, Const i, [] + | Ast.CNull r -> cmp_ty tc (TNullRef r), Null, [] + | Ast.CBool b -> I1, i1_op_of_bool b, [] + + | Ast.CStr s -> + let gid = gensym "str_arr" in + let str_typ = str_arr_ty s in + let uid = gensym "str" in + Ptr I8, Id uid, [] + >:: G(gid, (str_typ, GString s)) + >:: I(uid, Gep(Ptr str_typ, Gid gid, [Const 0L; Const 0L;])) + + | Ast.Bop (bop, e1, e2) -> + let t, _, ret_ty = typ_of_binop bop in + let ll_t = cmp_ty tc t in + let op1, code1 = cmp_exp_as tc c e1 ll_t in + let op2, code2 = cmp_exp_as tc c e2 ll_t in + let ans_id = gensym "bop" in + cmp_ty tc ret_ty, Id ans_id, code1 >@ code2 >:: I(ans_id, cmp_binop ll_t bop op1 op2) + + | Ast.Uop (uop, e) -> + let t, ret_ty = typ_of_unop uop in + let op, code = cmp_exp_as tc c e (cmp_ty tc t) in + let ans_id = gensym "unop" in + let cmp_uop op = function + | Ast.Neg -> Binop (Sub, I64, i64_op_of_int 0, op) + | Ast.Lognot -> Icmp (Eq, I1, op, i1_op_of_bool false) + | Ast.Bitnot -> Binop (Xor, I64, op, i64_op_of_int (-1)) in + cmp_ty tc ret_ty, Id ans_id, code >:: I (ans_id, cmp_uop op uop) + + | Ast.Id id -> + let t, op = Ctxt.lookup id c in + begin match t with + | Ptr (Fun _) -> t, op, [] + | Ptr t -> + let ans_id = gensym id in + t, Id ans_id, [I(ans_id, Load(Ptr t, op))] + | _ -> failwith "broken invariant: identifier not a pointer" + end + + (* compiles the length(e) expression. *) + | Ast.Length e -> + let arr_ty, arr_op, arr_code = cmp_exp tc c e in + let _ = match arr_ty with + | Ptr (Struct [_; Array (_,t)]) -> t + | _ -> failwith "Length: indexed into non pointer" in + let ptr_id, tmp_id = gensym "index_ptr", gensym "tmp" in + let ans_id = gensym "len" in + I64, (Id ans_id), + arr_code >@ lift + [ + ptr_id, Gep(arr_ty, arr_op, [i64_op_of_int 0; i64_op_of_int 0]) + ; ans_id, Load(Ptr I64, Id ptr_id)] + + + | Ast.Index (e, i) -> + let ans_ty, ptr_op, code = cmp_exp_lhs tc c exp in + let ans_id = gensym "index" in + ans_ty, Id ans_id, code >:: I(ans_id, Load(Ptr ans_ty, ptr_op)) + + | Ast.Call (f, es) -> + cmp_call tc c f es + + | Ast.CArr (elt_ty, cs) -> + let size_op = Ll.Const (Int64.of_int @@ List.length cs) in + let arr_ty, arr_op, alloc_code = oat_alloc_array tc elt_ty size_op in + let ll_elt_ty = cmp_ty tc elt_ty in + let add_elt s (i, elt) = + let elt_op, elt_code = cmp_exp_as tc c elt ll_elt_ty in + let ind = gensym "ind" in + s >@ elt_code >@ lift + [ ind, Gep(arr_ty, arr_op, [Const 0L; Const 1L; i64_op_of_int i ]) + ; gensym "store", Store (ll_elt_ty, elt_op, Id ind) ] + in + let ind_code = List.(fold_left add_elt [] @@ mapi (fun i e -> i, e) cs) in + arr_ty, arr_op, alloc_code >@ ind_code + + (* - the initializer is a loop that uses id as the index + - each iteration of the loop the code evaluates e2 and assigns it + to the index stored in id. + *) + | Ast.NewArr (elt_ty, e1, id, e2) -> + let ptr_id = gensym "ptr_" in + let bound_id = gensym "bnd_" in + let _, size_op, size_code = cmp_exp tc c e1 in + let arr_ty, arr_op, alloc_code = oat_alloc_array tc elt_ty size_op in + let for_loop = (no_loc @@ Ast.For ([(id, no_loc (CInt 0L))], + Some (no_loc @@ Bop (Lt, no_loc @@ Id id, no_loc @@ Id bound_id)), + Some (no_loc @@ Assn (no_loc @@ Id id, no_loc @@ Bop (Add, no_loc @@ Id id, no_loc @@ CInt 1L))), + [no_loc @@ Assn (no_loc @@ Index (no_loc @@ Id ptr_id, no_loc @@ Id id), e2)])) in + let new_context = Ctxt.add c ptr_id (Ptr arr_ty, Id ptr_id) in + let new_context = Ctxt.add new_context bound_id (Ptr I64, Id bound_id) in + let _, assign_code = cmp_stmt tc new_context arr_ty for_loop None None in + arr_ty, arr_op, + size_code >@ + alloc_code >@ + [I (bound_id, Alloca(I64))] >@ + [I (gensym "store", Store (I64, size_op, Id bound_id))] >@ + [I (ptr_id, Alloca(arr_ty))] >@ + [I (gensym "store", Store (arr_ty, arr_op, Id ptr_id))] >@ + assign_code + + (* For each field component of the struct + - use the TypeCtxt operations to compute getelementptr indices + - compile the initializer expression + - store the resulting value into the structure + *) + | Ast.CStruct (id, l) -> + let struct_ty, struct_op, alloc_code = oat_alloc_struct tc id in + let add_elt s (fid, fexp) = + let field_type = cmp_ty tc @@ TypeCtxt.lookup_field id fid tc in + let index = TypeCtxt.index_of_field id fid tc in + let elt_op, elt_code = cmp_exp_as tc c fexp field_type in + let ind = gensym "ind" in + s >@ elt_code >@ lift + [ ind, Gep(struct_ty, struct_op, [Const 0L; i64_op_of_int index]) + ; gensym "store", Store(field_type, elt_op, Id ind) ] + in + let ind_code = List.fold_left add_elt [] l in + struct_ty, struct_op, alloc_code >@ ind_code + + | Ast.Proj (e, id) -> + let ans_ty, ptr_op, code = cmp_exp_lhs tc c exp in + let ans_id = gensym "proj" in + ans_ty, Id ans_id, code >:: I(ans_id, Load(Ptr ans_ty, ptr_op)) + + +and cmp_exp_lhs (tc : TypeCtxt.t) (c:Ctxt.t) (e:exp node) : Ll.ty * Ll.operand * stream = + match e.elt with + | Ast.Id x -> + let t, op = Ctxt.lookup x c in + t, op, [] + + | Ast.Proj (e, i) -> + let src_ty, src_op, src_code = cmp_exp tc c e in + let ret_ty, ret_index = TypeCtxt.lookup_field_name i tc in + let gep_id = gensym "index" in + let ret_op = Gep(src_ty, src_op, [Const 0L; Const ret_index]) in + cmp_ty tc ret_ty, Id gep_id, src_code >:: I (gep_id, ret_op) + + + | Ast.Index (e, i) -> + let arr_ty, arr_op, arr_code = cmp_exp tc c e in + let _, ind_op, ind_code = cmp_exp tc c i in + let ans_ty = match arr_ty with + | Ptr (Struct [_; Array (_,t)]) -> t + | _ -> failwith "Index: indexed into non pointer" in + let ptr_id, tmp_id, call_id = gensym "index_ptr", gensym "tmp", gensym "call" in + ans_ty, (Id ptr_id), + arr_code >@ ind_code >@ lift + [tmp_id, Bitcast(arr_ty, arr_op, Ptr I64) + ;call_id, Call (Void, Gid "oat_assert_array_length", [Ptr I64, Id tmp_id; I64, ind_op ]) + ;ptr_id, Gep(arr_ty, arr_op, [i64_op_of_int 0; i64_op_of_int 1; ind_op]) ] + + + + | _ -> failwith "invalid lhs expression" + +and cmp_call (tc : TypeCtxt.t) (c:Ctxt.t) (exp:Ast.exp node) (es:Ast.exp node list) : Ll.ty * Ll.operand * stream = + let (t, op, s) = cmp_exp tc c exp in + let (ts, rt) = + match t with + | Ptr (Fun (l, r)) -> l, r + | _ -> failwith "nonfunction passed to cmp_call" in + let args, args_code = List.fold_right2 + (fun e t (args, code) -> + let arg_op, arg_code = cmp_exp_as tc c e t in + (t, arg_op)::args, arg_code @ code + ) es ts ([],[]) in + let res_id = gensym "result" in + rt, Id res_id, s >@ args_code >:: I(res_id, Call(rt, op, args)) + +and cmp_exp_as (tc : TypeCtxt.t) (c:Ctxt.t) (e:Ast.exp node) (t:Ll.ty) : Ll.operand * stream = + let from_t, op, code = cmp_exp tc c e in + if from_t = t then op, code + else let res_id = gensym "cast" in + Id res_id, code >:: I(res_id, Bitcast(from_t, op, t)) + +(* Compile a statement in context c with return typ rt. Return a new context, + possibly extended with new local bindings, and the instruction stream + implementing the statement. + + Left-hand-sides of assignment statements must either be OAT identifiers, + or an index into some arbitrary expression of array type. Otherwise, the + program is not well-formed and your compiler may throw an error. + *) +and cmp_stmt (tc : TypeCtxt.t) (c:Ctxt.t) (rt:Ll.ty) (stmt:Ast.stmt node) (lo : Ll.lbl option) (ls : Ll.lbl option) : Ctxt.t * stream = + + match stmt.elt with + | Ast.Decl (id, init) -> + let ll_ty, init_op, init_code = cmp_exp tc c init in + let res_id = gensym id in + let c' = Ctxt.add c id (Ptr ll_ty, Id res_id) in + c', init_code + >:: E(res_id, Alloca ll_ty) + >:: I(gensym "store", Store (ll_ty, init_op, Id res_id)) + + | Ast.Assn (path ,e) -> + let _, pop, path_code = cmp_exp_lhs tc c path in + let ll_ty, eop, exp_code = cmp_exp tc c e in + c, path_code >@ exp_code >:: I(gensym "store", (Store (ll_ty, eop, pop))) + + | Ast.If (guard, st1, st2) -> + let guard_ty, guard_op, guard_code = cmp_exp tc c guard in + let then_code = cmp_block tc c rt st1 lo ls in + let else_code = cmp_block tc c rt st2 lo ls in + let lt, le, lm = gensym "then", gensym "else", gensym "merge" in + c, guard_code + >:: T(Cbr (guard_op, lt, le)) + >:: L lt >@ then_code >:: T(Br lm) + >:: L le >@ else_code >:: T(Br lm) + >:: L lm + + (* the 'if?' checked null downcast statement. + - check whether the value computed by exp is null, if so jump to + the 'null' block, otherwise take the 'notnull' block + + - the identifier id is in scope in the 'nutnull' block and so + needs to be allocated (and added to the context) + + - as in the if-the-else construct, you should jump to the common + merge label after either block + *) + | Ast.Cast (typ, id, exp, notnull, null) -> + let translated_typ = cmp_ty tc (TRef typ) in + let guard_op, guard_code = cmp_exp_as tc c exp translated_typ in + let res_id = gensym id in + let c' = Ctxt.add c id (Ptr translated_typ, Id res_id) in + let null_code = cmp_block tc c rt null lo ls in + let notnull_code = cmp_block tc c' rt notnull lo ls in + let cast_id = gensym "cast" in + let ln, lnn, lm = gensym "null", gensym "notnull", gensym "merge" in + c, guard_code + >:: I(cast_id, Icmp(Eq, translated_typ, guard_op, Null)) + >:: T(Cbr (Id cast_id, ln, lnn)) + >:: L lnn + >:: E(res_id, Alloca translated_typ) + >:: I(gensym "store", Store (translated_typ, guard_op, Id res_id)) + >@ notnull_code >:: T(Br lm) + >:: L ln >@ null_code >:: T(Br lm) + >:: L lm + + | Ast.While (guard, body) -> + let guard_ty, guard_op, guard_code = cmp_exp tc c guard in + let lcond, lbody, lpost = gensym "cond", gensym "body", gensym "post" in + let body_code = cmp_block tc c rt body (Some lpost) (Some lcond) in + c, [] + >:: T (Br lcond) + >:: L lcond >@ guard_code >:: T (Cbr (guard_op, lbody, lpost)) + >:: L lbody >@ body_code >:: T (Br lcond) + >:: L lpost + + | Ast.For (inits, guard, after, body) -> + let guard = match guard with Some e -> e | None -> no_loc (CBool true) in + let after = match after with Some s -> [s] | None -> [] in + let body = body @ after in + let ds = List.map (fun d -> no_loc (Decl d)) inits in + let stream = cmp_block tc c rt (ds @ [no_loc @@ Ast.While (guard, body)]) None None in + c, stream + + | Ast.Ret None -> + c, [T (Ret(Void, None))] + + | Ast.Ret (Some e) -> + let op, code = cmp_exp_as tc c e rt in + c, code >:: T(Ret (rt, Some op)) + + | Ast.SCall (f, es) -> + let _, op, code = cmp_call tc c f es in + c, code + +(* Compile a series of statements *) +and cmp_block (tc : TypeCtxt.t) (c:Ctxt.t) (rt:Ll.ty) (stmts:Ast.block) (lo:Ll.lbl option) ls : stream = + snd @@ List.fold_left (fun (c, code) s -> + let c, stmt_code = cmp_stmt tc c rt s lo ls in + c, code >@ stmt_code + ) (c,[]) stmts + + + +(* Construct the structure context for compilation. We could reuse + the H component from the Typechecker rather than recomputing this + information here, but we do it this way to make the two parts of + the project less interdependent. *) +let get_struct_defns (p:Ast.prog) : TypeCtxt.t = + List.fold_right (fun d ts -> + match d with + | Ast.Gtdecl { elt=(id, fs) } -> + TypeCtxt.add ts id fs + | _ -> ts) p TypeCtxt.empty + + +(* Adds each function identifer to the context at an + appropriately translated type. + + NOTE: The Gid of a function is just its source name +*) +let cmp_function_ctxt (tc : TypeCtxt.t) (c:Ctxt.t) (p:Ast.prog) : Ctxt.t = + List.fold_left (fun c -> function + | Ast.Gfdecl { elt={ frtyp; fname; args } } -> + let ft = TRef (RFun (List.map fst args, frtyp)) in + Ctxt.add c fname (cmp_ty tc ft, Gid fname) + | _ -> c + ) c p + +(* Populate a context with bindings for global variables + mapping OAT identifiers to LLVMlite gids and their types. + + Only a small subset of OAT expressions can be used as global initializers + in well-formed programs. (The constructors starting with C and Id's + for global function values). +*) +let cmp_global_ctxt (tc : TypeCtxt.t) (c:Ctxt.t) (p:Ast.prog) : Ctxt.t = + let gexp_ty c = function + | Id id -> fst (Ctxt.lookup id c) + | CStruct (t, cs) -> Ptr (Namedt t) + | CNull r -> cmp_ty tc (TNullRef r) + | CBool b -> I1 + | CInt i -> I64 + | CStr s -> Ptr (str_arr_ty s) + | CArr (u, cs) -> Ptr (Struct [I64; Array(List.length cs, cmp_ty tc u)]) + | x -> failwith ( "bad global initializer: " ^ (Astlib.string_of_exp (no_loc x))) + in + List.fold_left (fun c -> function + | Ast.Gvdecl { elt={ name; init } } -> + Ctxt.add c name (Ptr (gexp_ty c init.elt), Gid name) + | _ -> c) c p + + +(* Compile a function declaration in global context c. Return the LLVMlite cfg + and a list of global declarations containing the string literals appearing + in the function. + *) +let cmp_fdecl (tc : TypeCtxt.t) (c:Ctxt.t) (f:Ast.fdecl node) : Ll.fdecl * (Ll.gid * Ll.gdecl) list = + let {frtyp; args; body} = f.elt in + let add_arg (s_typ, s_id) (c,code,args) = + let ll_id = gensym s_id in + let ll_ty = cmp_ty tc s_typ in + let alloca_id = gensym s_id in + let c = Ctxt.add c s_id (Ptr ll_ty, Ll.Id alloca_id)in + c, [] + >:: E(alloca_id, Alloca ll_ty) + >:: I(gensym "store", Store(ll_ty, Id ll_id, Id alloca_id)) + >@ code, + (ll_ty, ll_id)::args + in + let c, args_code, args = List.fold_right add_arg args (c,[],[]) in + let ll_rty = cmp_ret_ty tc frtyp in + let block_code = cmp_block tc c ll_rty body None None in + let argtys, f_param = List.split args in + let f_ty = (argtys, ll_rty) in + let f_cfg, globals = cfg_of_stream (args_code >@ block_code) in + {f_ty; f_param; f_cfg}, globals + + + +(* Compile a global initializer, returning the resulting LLVMlite global + declaration, and a list of additional global declarations. +*) +let rec cmp_gexp c (tc : TypeCtxt.t) (e:Ast.exp node) : Ll.gdecl * (Ll.gid * Ll.gdecl) list = + match e.elt with + | CNull r -> (cmp_ty tc (TNullRef r), GNull), [] + | CBool b -> (I1, (if b then GInt 1L else GInt 0L)), [] + | CInt i -> (I64, GInt i), [] + | Id id -> ((fst @@ Ctxt.lookup id c), GGid id), [] + + | CStr s -> + let gid = gensym "str" in + let ll_ty = str_arr_ty s in + (Ptr ll_ty, GGid gid), [gid, (ll_ty, GString s)] + + | CArr (u, cs) -> + let elts, gs = List.fold_right + (fun cst (elts, gs) -> + let gd, gs' = cmp_gexp c tc cst in + gd::elts, gs' @ gs) cs ([], []) + in + let len = List.length cs in + let ll_u = cmp_ty tc u in + let gid = gensym "global_arr" in + let arr_t = Struct [ I64; Array(len, ll_u) ] in + let arr_i = GStruct [ I64, GInt (Int64.of_int len); Array(len, ll_u), GArray elts ] in + (Ptr arr_t, GGid gid), (gid, (arr_t, arr_i))::gs + + | CStruct (id, cs) -> + let fields = TypeCtxt.lookup id tc in + let elts, gs = + List.fold_right + (fun fs (elts, gs) -> + let gd, gs' = cmp_gexp c tc (snd (List.find (fun (xid, xname) -> xid = fs.fieldName) cs)) in + (gd :: elts, gs' @ gs)) fields ([], []) in + let gid = gensym "global_struct" in + (Ptr (Namedt id), GGid gid), (gid, (Namedt id, GStruct elts)) :: gs + + | _ -> failwith "bad global initializer" + +(* Oat internals function context ------------------------------------------- *) +let internals = + [ "oat_malloc", Ll.Fun ([I64], Ptr I64) + ; "oat_alloc_array", Ll.Fun ([I64], Ptr I64) + ; "oat_assert_not_null", Ll.Fun ([Ptr I8], Void) + ; "oat_assert_array_length", Ll.Fun ([Ptr I64; I64], Void) + ] + +(* Oat builtin function context --------------------------------------------- *) +let builtins = List.map + (fun (fname, ftyp) -> + let args, ret = cmp_fty TypeCtxt.empty ftyp in + (fname, Ll.Fun (args, ret))) + Typechecker.builtins + + +let tctxt_to_tdecls c = + List.map (fun (i, l) -> i, Struct (List.map (fun f -> cmp_ty c f.ftyp) l)) c + +(* Compile a OAT program to LLVMlite *) +let cmp_prog (p:Ast.prog) : Ll.prog = + let tc = get_struct_defns p in + (* add built-in functions to context *) + let init_ctxt = + List.fold_left (fun c (i, t) -> Ctxt.add c i (Ll.Ptr t, Gid i)) + Ctxt.empty builtins + in + let fc = cmp_function_ctxt tc init_ctxt p in + + (* build global variable context *) + let c = cmp_global_ctxt tc fc p in + (* compile functions and global variables *) + let fdecls, gdecls = + List.fold_right (fun d (fs, gs) -> + match d with + | Ast.Gvdecl { elt=gd } -> + let ll_gd, gs' = cmp_gexp c tc gd.init in + (fs, (gd.name, ll_gd)::gs' @ gs) + | Ast.Gfdecl fd -> + let fdecl, gs' = cmp_fdecl tc c fd in + (fd.elt.fname,fdecl)::fs, gs' @ gs + | Ast.Gtdecl _ -> + fs, gs + ) p ([], []) + in + (* gather external declarations *) + let edecls = internals @ builtins in + { tdecls = tctxt_to_tdecls tc; gdecls; fdecls; edecls } diff --git a/hw6/frontend.ml b/hw6/frontend.ml new file mode 100644 index 0000000..fe03421 --- /dev/null +++ b/hw6/frontend.ml @@ -0,0 +1,723 @@ +open Ll +open Llutil +open Ast + +(* instruction streams ------------------------------------------------------ *) + +(* As in the last project, we'll be working with a flattened representation + of LLVMlite programs to make emitting code easier. This version + additionally makes it possible to emit elements will be gathered up and + "hoisted" to specific parts of the constructed CFG + - G of gid * Ll.gdecl: allows you to output global definitions in the middle + of the instruction stream. You will find this useful for compiling string + literals + - E of uid * insn: allows you to emit an instruction that will be moved up + to the entry block of the current function. This will be useful for + compiling local variable declarations +*) + +type elt = + | L of Ll.lbl (* block labels *) + | I of uid * Ll.insn (* instruction *) + | T of Ll.terminator (* block terminators *) + | G of gid * Ll.gdecl (* hoisted globals (usually strings) *) + | E of uid * Ll.insn (* hoisted entry block instructions *) + +type stream = elt list +let ( >@ ) x y = y @ x +let ( >:: ) x y = y :: x +let lift : (uid * insn) list -> stream = List.rev_map (fun (x,i) -> I (x,i)) + +(* Build a CFG and collection of global variable definitions from a stream *) +let cfg_of_stream (code:stream) : Ll.cfg * (Ll.gid * Ll.gdecl) list = + let gs, einsns, insns, term_opt, blks = List.fold_left + (fun (gs, einsns, insns, term_opt, blks) e -> + match e with + | L l -> + begin match term_opt with + | None -> + if (List.length insns) = 0 then (gs, einsns, [], None, blks) + else failwith @@ Printf.sprintf "build_cfg: block labeled %s has\ + no terminator" l + | Some term -> + (gs, einsns, [], None, (l, {insns; term})::blks) + end + | T t -> (gs, einsns, [], Some (Llutil.Parsing.gensym "tmn", t), blks) + | I (uid,insn) -> (gs, einsns, (uid,insn)::insns, term_opt, blks) + | G (gid,gdecl) -> ((gid,gdecl)::gs, einsns, insns, term_opt, blks) + | E (uid,i) -> (gs, (uid, i)::einsns, insns, term_opt, blks) + ) ([], [], [], None, []) code + in + match term_opt with + | None -> failwith "build_cfg: entry block has no terminator" + | Some term -> + let insns = einsns @ insns in + ({insns; term}, blks), gs + + +(* compilation contexts ----------------------------------------------------- *) + +(* To compile OAT variables, we maintain a mapping of source identifiers to the + corresponding LLVMlite operands. Bindings are added for global OAT variables + and local variables that are in scope. *) + +module Ctxt = struct + + type t = (Ast.id * (Ll.ty * Ll.operand)) list + let empty = [] + + (* Add a binding to the context *) + let add (c:t) (id:id) (bnd:Ll.ty * Ll.operand) : t = (id,bnd)::c + + (* Lookup a binding in the context *) + let lookup (id:Ast.id) (c:t) : Ll.ty * Ll.operand = + List.assoc id c + +end + +(* Mapping of identifiers representing struct definitions to + * the corresponding name-to-name-to-type map. + + Note: You will need to use these operations when compiling structures. +*) +module TypeCtxt = struct + type t = (Ast.id * Ast.field list) list + let empty = [] + + let add c id bnd = (id, bnd) :: c + let lookup id c = List.assoc id c + let lookup_field st_name f_name (c : t) = + let rec lookup_field_aux f_name l = + match l with + | [] -> failwith "TypeCtxt.lookup_field: Not_found" + | h :: t -> if h.fieldName = f_name then h.ftyp else lookup_field_aux f_name t in + lookup_field_aux f_name (List.assoc st_name c) + + let rec index_of f l i = + match l with + | [] -> None + | h :: t -> if h.fieldName = f then Some i else index_of f t (i + 1) + + (* Return the index of a field in the struct. *) + let index_of_field_opt (st:Ast.id) (f:Ast.id) (c : t) : (int option) = + index_of f (List.assoc st c) 0 + + let index_of_field (st:Ast.id) (f:Ast.id) (c:t) : int = + match index_of_field_opt st f c with + | None -> failwith "index_of_field: Not found" + | Some x -> x + + (* Return a pair of base type and index into struct *) + let rec lookup_field_name (st:Ast.id) (f:Ast.id) (c : t) : (Ast.ty * Int64.t) = + let fields = lookup st c in + match index_of f fields 0 with + | None -> failwith "no such field" + | Some x -> List.(nth fields x).ftyp, Int64.of_int x +end + +(* compiling OAT types ------------------------------------------------------ *) + +(* The mapping of source types onto LLVMlite is straightforward. Booleans and ints + are represented as the the corresponding integer types. OAT strings are + pointers to bytes (I8). Arrays are the most interesting type: they are + represented as pointers to structs where the first component is the number + of elements in the following array. + + NOTE: structure types are named, so they compile to their named form +*) + +let rec cmp_ty (ct : TypeCtxt.t) : Ast.ty -> Ll.ty = function + | Ast.TBool -> I1 + | Ast.TInt -> I64 + | Ast.TRef r -> Ptr (cmp_rty ct r) + | Ast.TNullRef r -> Ptr (cmp_rty ct r) + + +and cmp_ret_ty ct : Ast.ret_ty -> Ll.ty = function + | Ast.RetVoid -> Void + | Ast.RetVal t -> cmp_ty ct t + +and cmp_fty ct (ts, r) : Ll.fty = + List.map (cmp_ty ct) ts, cmp_ret_ty ct r + +and cmp_rty ct : Ast.rty -> Ll.ty = function + | Ast.RString -> I8 + | Ast.RArray u -> Struct [I64; Array(0, cmp_ty ct u)] + | Ast.RStruct r -> Namedt r + | Ast.RFun (ts, t) -> + let args, ret = cmp_fty ct (ts, t) in + Fun (args, ret) + +let typ_of_binop : Ast.binop -> Ast.ty * Ast.ty * Ast.ty = function + | Add | Mul | Sub | Shl | Shr | Sar | IAnd | IOr -> (TInt, TInt, TInt) + | Eq | Neq | Lt | Lte | Gt | Gte -> (TInt, TInt, TBool) + | And | Or -> (TBool, TBool, TBool) + +let typ_of_unop : Ast.unop -> Ast.ty * Ast.ty = function + | Neg | Bitnot -> (TInt, TInt) + | Lognot -> (TBool, TBool) + + +(* Some useful helper functions *) + +(* Generate a fresh temporary identifier. Since OAT identifiers cannot begin + with an underscore, these should not clash with any source variables *) +let gensym : string -> string = + let c = ref 0 in + fun (s:string) -> incr c; Printf.sprintf "_%s%d" s (!c) + +(* Amount of space an Oat type takes when stored in the stack, in bytes. + Note that since structured values are manipulated by reference, all + Oat values take 8 bytes on the stack. +*) +let size_oat_ty (t : Ast.ty) = 8L + + +(* Amount of size that needs to be allocated to store a structure *) +let rec size_oat_struct (l : Ast.field list) = + match l with + | [] -> 0L + | f :: t -> Int64.(add (size_oat_struct t) (size_oat_ty f.ftyp)) + +(* Generate code to allocate a zero-initialized array of source type TRef (RArray t) of the + given size. Note "size" is an operand whose value can be computed at + runtime *) +let oat_alloc_array ct (t:Ast.ty) (size:Ll.operand) : Ll.ty * operand * stream = + let ans_id, arr_id = gensym "array", gensym "raw_array" in + let ans_ty = cmp_ty ct @@ TRef (RArray t) in + let arr_ty = Ptr I64 in + ans_ty, Id ans_id, lift + [ arr_id, Call(arr_ty, Gid "oat_alloc_array", [I64, size]) + ; ans_id, Bitcast(arr_ty, Id arr_id, ans_ty) ] + + +(* Allocates an oat structure on the + heap and returns a target operand with the appropriate reference. + + - generate a call to 'oat_malloc' and use bitcast to conver the + resulting pointer to the right type + + - make sure to calculate the correct amount of space to allocate! +*) +let oat_alloc_struct ct (id:Ast.id) : Ll.ty * operand * stream = + let ret_id, arr_id = gensym "struct", gensym "raw_struct" in + let ans_ty = cmp_ty ct (TRef (RStruct id)) in + let arr_ty = Ptr I64 in + ans_ty, Id ret_id, lift + [ arr_id, Call(arr_ty, Gid "oat_malloc", [I64, Const (size_oat_struct (TypeCtxt.lookup id ct))]) + ; ret_id, Bitcast(arr_ty, Id arr_id, ans_ty) ] + + +let str_arr_ty s = Array(1 + String.length s, I8) +let i1_op_of_bool b = Ll.Const (if b then 1L else 0L) +let i64_op_of_int i = Ll.Const (Int64.of_int i) + +let cmp_binop t (b : Ast.binop) : Ll.operand -> Ll.operand -> Ll.insn = + let ib b op1 op2 = Ll.Binop (b, t, op1, op2) in + let ic c op1 op2 = Ll.Icmp (c, t, op1, op2) in + match b with + | Ast.Add -> ib Ll.Add + | Ast.Mul -> ib Ll.Mul + | Ast.Sub -> ib Ll.Sub + | Ast.And -> ib Ll.And + | Ast.IAnd -> ib Ll.And + | Ast.IOr -> ib Ll.Or + | Ast.Or -> ib Ll.Or + | Ast.Shl -> ib Ll.Shl + | Ast.Shr -> ib Ll.Lshr + | Ast.Sar -> ib Ll.Ashr + + | Ast.Eq -> ic Ll.Eq + | Ast.Neq -> ic Ll.Ne + | Ast.Lt -> ic Ll.Slt + | Ast.Lte -> ic Ll.Sle + | Ast.Gt -> ic Ll.Sgt + | Ast.Gte -> ic Ll.Sge + +(* Compiles an expression exp in context c, outputting the Ll operand that will + receive the value of the expression, and the stream of instructions + implementing the expression. +*) +let rec cmp_exp (tc : TypeCtxt.t) (c:Ctxt.t) (exp:Ast.exp node) : Ll.ty * Ll.operand * stream = + match exp.elt with + | Ast.CInt i -> I64, Const i, [] + | Ast.CNull r -> cmp_ty tc (TNullRef r), Null, [] + | Ast.CBool b -> I1, i1_op_of_bool b, [] + + | Ast.CStr s -> + let gid = gensym "str_arr" in + let str_typ = str_arr_ty s in + let uid = gensym "str" in + Ptr I8, Id uid, [] + >:: G(gid, (str_typ, GString s)) + >:: I(uid, Gep(Ptr str_typ, Gid gid, [Const 0L; Const 0L;])) + + | Ast.Bop (Ast.Eq as bop, e1, e2) + | Ast.Bop (Ast.Neq as bop, e1, e2) -> + (* Polymorphic equality operations *) + (* Allow any type for the first operand, and cast + the second operand to the type of the first. *) + let _, _, ret_ty = typ_of_binop bop in + let ll_t, op1, code1 = cmp_exp tc c e1 in + let op2, code2 = cmp_exp_as tc c e2 ll_t in + let ans_id = gensym "bop" in + cmp_ty tc ret_ty, Id ans_id, code1 >@ code2 >:: I(ans_id, cmp_binop ll_t bop op1 op2) + + | Ast.Bop (bop, e1, e2) -> + let t, _, ret_ty = typ_of_binop bop in + let ll_t = cmp_ty tc t in + let op1, code1 = cmp_exp_as tc c e1 ll_t in + let op2, code2 = cmp_exp_as tc c e2 ll_t in + let ans_id = gensym "bop" in + cmp_ty tc ret_ty, Id ans_id, code1 >@ code2 >:: I(ans_id, cmp_binop ll_t bop op1 op2) + + | Ast.Uop (uop, e) -> + let t, ret_ty = typ_of_unop uop in + let op, code = cmp_exp_as tc c e (cmp_ty tc t) in + let ans_id = gensym "unop" in + let cmp_uop op = function + | Ast.Neg -> Binop (Sub, I64, i64_op_of_int 0, op) + | Ast.Lognot -> Icmp (Eq, I1, op, i1_op_of_bool false) + | Ast.Bitnot -> Binop (Xor, I64, op, i64_op_of_int (-1)) in + cmp_ty tc ret_ty, Id ans_id, code >:: I (ans_id, cmp_uop op uop) + + | Ast.Id id -> + let t, op = Ctxt.lookup id c in + begin match t with + | Ptr (Fun _) -> t, op, [] + | Ptr t -> + let ans_id = gensym id in + t, Id ans_id, [I(ans_id, Load(Ptr t, op))] + | _ -> failwith "broken invariant: identifier not a pointer" + end + + (* compiles the length(e) expression. *) + | Ast.Length e -> + let arr_ty, arr_op, arr_code = cmp_exp tc c e in + let _ = match arr_ty with + | Ptr (Struct [_; Array (_,t)]) -> t + | _ -> failwith "Length: indexed into non pointer" in + let ptr_id, tmp_id = gensym "index_ptr", gensym "tmp" in + let ans_id = gensym "len" in + I64, (Id ans_id), + arr_code >@ lift + [ + ptr_id, Gep(arr_ty, arr_op, [i64_op_of_int 0; i64_op_of_int 0]) + ; ans_id, Load(Ptr I64, Id ptr_id)] + + + | Ast.Index (e, i) -> + let ans_ty, ptr_op, code = cmp_exp_lhs tc c exp in + let ans_id = gensym "index" in + ans_ty, Id ans_id, code >:: I(ans_id, Load(Ptr ans_ty, ptr_op)) + + | Ast.Call (f, es) -> + cmp_call tc c f es + + | Ast.CArr (elt_ty, cs) -> + let size_op = Ll.Const (Int64.of_int @@ List.length cs) in + let arr_ty, arr_op, alloc_code = oat_alloc_array tc elt_ty size_op in + let ll_elt_ty = cmp_ty tc elt_ty in + let add_elt s (i, elt) = + let elt_op, elt_code = cmp_exp_as tc c elt ll_elt_ty in + let ind = gensym "ind" in + s >@ elt_code >@ lift + [ ind, Gep(arr_ty, arr_op, [Const 0L; Const 1L; i64_op_of_int i ]) + ; gensym "store", Store(ll_elt_ty, elt_op, Id ind) ] + in + let ind_code = List.(fold_left add_elt [] @@ mapi (fun i e -> i, e) cs) in + arr_ty, arr_op, alloc_code >@ ind_code + + | Ast.NewArr (elt_ty, e) -> + let _, size_op, size_code = cmp_exp tc c e in + let arr_ty, arr_op, alloc_code = oat_alloc_array tc elt_ty size_op in + arr_ty, arr_op, size_code >@ alloc_code + + | Ast.NewArrInit (elt_ty, e1, id, e2) -> + let ptr_id = gensym "ptr_" in + let bound_id = gensym "bnd_" in + let _, size_op, size_code = cmp_exp tc c e1 in + let arr_ty, arr_op, alloc_code = oat_alloc_array tc elt_ty size_op in + let for_loop = (no_loc @@ Ast.For ([(id, no_loc (CInt 0L))], + Some (no_loc @@ Bop (Lt, no_loc @@ Id id, no_loc @@ Id bound_id)), + Some (no_loc @@ Assn (no_loc @@ Id id, no_loc @@ Bop (Add, no_loc @@ Id id, no_loc @@ CInt 1L))), + [no_loc @@ Assn (no_loc @@ Index (no_loc @@ Id ptr_id, no_loc @@ Id id), e2)])) in + let new_context = Ctxt.add c ptr_id (Ptr arr_ty, Id ptr_id) in + let new_context = Ctxt.add new_context bound_id (Ptr I64, Id bound_id) in + let _, assign_code = cmp_stmt tc new_context arr_ty for_loop in + arr_ty, arr_op, + size_code >@ + alloc_code >@ + [I (bound_id, Alloca(I64))] >@ + [I (gensym "store", Store (I64, size_op, Id bound_id))] >@ + [I (ptr_id, Alloca(arr_ty))] >@ + [I (gensym "store", Store (arr_ty, arr_op, Id ptr_id))] >@ + assign_code + + (* For each field component of the struct + - use the TypeCtxt operations to compute getelementptr indices + - compile the initializer expression + - store the resulting value into the structure + *) + | Ast.CStruct (id, l) -> + let struct_ty, struct_op, alloc_code = oat_alloc_struct tc id in + let add_elt s (fid, fexp) = + let field_type = cmp_ty tc @@ TypeCtxt.lookup_field id fid tc in + let index = TypeCtxt.index_of_field id fid tc in + let elt_op, elt_code = cmp_exp_as tc c fexp field_type in + let ind = gensym "ind" in + s >@ elt_code >@ lift + [ ind, Gep(struct_ty, struct_op, [Const 0L; i64_op_of_int index]) + ; gensym "store", Store(field_type, elt_op, Id ind) ] + in + let ind_code = List.fold_left add_elt [] l in + struct_ty, struct_op, alloc_code >@ ind_code + + | Ast.Proj (e, id) -> + let ans_ty, ptr_op, code = cmp_exp_lhs tc c exp in + let ans_id = gensym "proj" in + ans_ty, Id ans_id, code >:: I(ans_id, Load(Ptr ans_ty, ptr_op)) + + +and cmp_exp_lhs (tc : TypeCtxt.t) (c:Ctxt.t) (e:exp node) : Ll.ty * Ll.operand * stream = + match e.elt with + | Ast.Id x -> + let pt, op = Ctxt.lookup x c in + let t = match pt with + | Ptr t -> t + | _ -> failwith "Unexpected variable type" in + t, op, [] + + | Ast.Proj (e, i) -> + let src_ty, src_op, src_code = cmp_exp tc c e in + let struct_id = match src_ty with + | Ptr (Namedt id) -> id + | _ -> failwith "Project on non-struct type" + in + let ret_ty, ret_index = TypeCtxt.lookup_field_name struct_id i tc in + let gep_id = gensym "index" in + let ret_op = Gep(src_ty, src_op, [Const 0L; Const ret_index]) in + cmp_ty tc ret_ty, Id gep_id, src_code >:: I (gep_id, ret_op) + + | Ast.Index (e, i) -> + let arr_ty, arr_op, arr_code = cmp_exp tc c e in + let _, ind_op, ind_code = cmp_exp tc c i in + let ans_ty = match arr_ty with + | Ptr (Struct [_; Array (_,t)]) -> t + | _ -> failwith "Index: indexed into non pointer" in + let ptr_id, tmp_id, call_id = gensym "index_ptr", gensym "tmp", gensym "call" in + ans_ty, (Id ptr_id), + arr_code >@ ind_code >@ lift + [tmp_id, Bitcast(arr_ty, arr_op, Ptr I64) + ; call_id, Call (Void, Gid "oat_assert_array_length", [Ptr I64, Id tmp_id; I64, ind_op ]) + ; ptr_id, Gep(arr_ty, arr_op, [i64_op_of_int 0; i64_op_of_int 1; ind_op]) ] + + + + | _ -> failwith "invalid lhs expression" + +and cmp_call (tc : TypeCtxt.t) (c:Ctxt.t) (exp:Ast.exp node) (es:Ast.exp node list) : Ll.ty * Ll.operand * stream = + let (t, op, s) = cmp_exp tc c exp in + let (ts, rt) = + match t with + | Ptr (Fun (l, r)) -> l, r + | _ -> failwith "nonfunction passed to cmp_call" in + let args, args_code = List.fold_right2 + (fun e t (args, code) -> + let arg_op, arg_code = cmp_exp_as tc c e t in + (t, arg_op)::args, arg_code @ code + ) es ts ([],[]) in + let res_id = gensym "result" in + rt, Id res_id, s >@ args_code >:: I(res_id, Call(rt, op, args)) + +and cmp_exp_as (tc : TypeCtxt.t) (c:Ctxt.t) (e:Ast.exp node) (t:Ll.ty) : Ll.operand * stream = + let from_t, op, code = cmp_exp tc c e in + if from_t = t then op, code + else let res_id = gensym "cast" in + Id res_id, code >:: I(res_id, Bitcast(from_t, op, t)) + +(* Compile a statement in context c with return typ rt. Return a new context, + possibly extended with new local bindings, and the instruction stream + implementing the statement. + + Left-hand-sides of assignment statements must either be OAT identifiers, + or an index into some arbitrary expression of array type. Otherwise, the + program is not well-formed and your compiler may throw an error. + *) +and cmp_stmt (tc : TypeCtxt.t) (c:Ctxt.t) (rt:Ll.ty) (stmt:Ast.stmt node) : Ctxt.t * stream = + + match stmt.elt with + | Ast.Decl (id, init) -> + let ll_ty, init_op, init_code = cmp_exp tc c init in + let res_id = gensym id in + let c' = Ctxt.add c id (Ptr ll_ty, Id res_id) in + c', init_code + >:: E(res_id, Alloca ll_ty) + >:: I(gensym "store", Store (ll_ty, init_op, Id res_id)) + + | Ast.Assn (path ,e) -> + let ll_ty, pop, path_code = cmp_exp_lhs tc c path in + let eop, exp_code = cmp_exp_as tc c e ll_ty in + c, path_code >@ exp_code >:: I(gensym "store", (Store (ll_ty, eop, pop))) + + | Ast.If (guard, st1, st2) -> + let guard_ty, guard_op, guard_code = cmp_exp tc c guard in + let _, then_code = cmp_block tc c rt st1 in + let _, else_code = cmp_block tc c rt st2 in + let lt, le, lm = gensym "then", gensym "else", gensym "merge" in + c, guard_code + >:: T(Cbr (guard_op, lt, le)) + >:: L lt >@ then_code >:: T(Br lm) + >:: L le >@ else_code >:: T(Br lm) + >:: L lm + + (* the 'if?' checked null downcast statement. + - check whether the value computed by exp is null, if so jump to + the 'null' block, otherwise take the 'notnull' block + + - the identifier id is in scope in the 'nutnull' block and so + needs to be allocated (and added to the context) + + - as in the if-the-else construct, you should jump to the common + merge label after either block + *) + | Ast.Cast (typ, id, exp, notnull, null) -> + let translated_typ = cmp_ty tc (TRef typ) in + let guard_op, guard_code = cmp_exp_as tc c exp translated_typ in + let res_id = gensym id in + let c' = Ctxt.add c id (Ptr translated_typ, Id res_id) in + let _, null_code = cmp_block tc c rt null in + let _, notnull_code = cmp_block tc c' rt notnull in + let cast_id = gensym "cast" in + let ln, lnn, lm = gensym "null", gensym "notnull", gensym "merge" in + c, guard_code + >:: I(cast_id, Icmp(Eq, translated_typ, guard_op, Null)) + >:: T(Cbr (Id cast_id, ln, lnn)) + >:: L lnn + >:: E(res_id, Alloca translated_typ) + >:: I(gensym "store", Store (translated_typ, guard_op, Id res_id)) + >@ notnull_code >:: T(Br lm) + >:: L ln >@ null_code >:: T(Br lm) + >:: L lm + + | Ast.While (guard, body) -> + let guard_ty, guard_op, guard_code = cmp_exp tc c guard in + let lcond, lbody, lpost = gensym "cond", gensym "body", gensym "post" in + let _, body_code = cmp_block tc c rt body in + c, [] + >:: T (Br lcond) + >:: L lcond >@ guard_code >:: T (Cbr (guard_op, lbody, lpost)) + >:: L lbody >@ body_code >:: T (Br lcond) + >:: L lpost + + | Ast.For (inits, guard, after, body) -> + let ds = List.map (fun d -> no_loc (Decl d)) inits in + let ci, init = cmp_block tc c rt ds in + let guard = match guard with Some e -> e | None -> no_loc (CBool true) in + let guard_ty, guard_op, guard_code = cmp_exp tc ci guard in + let after = match after with Some s -> [s] | None -> [] in + let lcond, lbody, lpost = gensym "cond", gensym "body", gensym "post" in + let _,body_code = cmp_block tc ci rt body in + let _,after_code = cmp_block tc ci rt after in + c, init + >:: T (Br lcond) + >:: L lcond >@ guard_code >:: T (Cbr (guard_op, lbody, lpost)) + >:: L lbody >@ body_code >@ after_code >:: T (Br lcond) + >:: L lpost + + | Ast.Ret None -> + c, [T (Ret(Void, None))] + + | Ast.Ret (Some e) -> + let op, code = cmp_exp_as tc c e rt in + c, code >:: T(Ret (rt, Some op)) + + | Ast.SCall (f, es) -> + let _, op, code = cmp_call tc c f es in + c, code + +(* Compile a series of statements *) +and cmp_block (tc : TypeCtxt.t) (c:Ctxt.t) (rt:Ll.ty) (stmts:Ast.block) : Ctxt.t * stream = + List.fold_left (fun (c, code) s -> + let c, stmt_code = cmp_stmt tc c rt s in + c, code >@ stmt_code + ) (c,[]) stmts + + + +(* Construct the structure context for compilation. We could reuse + the H component from the Typechecker rather than recomputing this + information here, but we do it this way to make the two parts of + the project less interdependent. *) +let get_struct_defns (p:Ast.prog) : TypeCtxt.t = + List.fold_right (fun d ts -> + match d with + | Ast.Gtdecl { elt=(id, fs) } -> + TypeCtxt.add ts id fs + | _ -> ts) p TypeCtxt.empty + + +(* Adds each function identifier to the context at an + appropriately translated type. + + NOTE: The Gid of a function is just its source name +*) +let cmp_function_ctxt (tc : TypeCtxt.t) (c:Ctxt.t) (p:Ast.prog) : Ctxt.t = + List.fold_left (fun c -> function + | Ast.Gfdecl { elt={ frtyp; fname; args } } -> + let ft = TRef (RFun (List.map fst args, frtyp)) in + Ctxt.add c fname (cmp_ty tc ft, Gid fname) + | _ -> c + ) c p + +(* Populate a context with bindings for global variables + mapping OAT identifiers to LLVMlite gids and their types. + + Only a small subset of OAT expressions can be used as global initializers + in well-formed programs. (The constructors starting with C and Id's + for global function values). +*) +let cmp_global_ctxt (tc : TypeCtxt.t) (c:Ctxt.t) (p:Ast.prog) : Ctxt.t = + let gexp_ty c = function + | Id id -> fst (Ctxt.lookup id c) + | CStruct (t, cs) -> Ptr (Namedt t) + | CNull r -> cmp_ty tc (TNullRef r) + | CBool b -> I1 + | CInt i -> I64 + | CStr s -> Ptr I8 + | CArr (u, cs) -> Ptr (Struct [I64; Array(0, cmp_ty tc u)]) + | x -> failwith ( "bad global initializer: " ^ (Astlib.string_of_exp (no_loc x))) + in + List.fold_left (fun c -> function + | Ast.Gvdecl { elt={ name; init } } -> + Ctxt.add c name (Ptr (gexp_ty c init.elt), Gid name) + | _ -> c) c p + + +(* Compile a function declaration in global context c. Return the LLVMlite cfg + and a list of global declarations containing the string literals appearing + in the function. + *) +let cmp_fdecl (tc : TypeCtxt.t) (c:Ctxt.t) (f:Ast.fdecl node) : Ll.fdecl * (Ll.gid * Ll.gdecl) list = + let {frtyp; args; body} = f.elt in + let add_arg (s_typ, s_id) (c,code,args) = + let ll_id = gensym s_id in + let ll_ty = cmp_ty tc s_typ in + let alloca_id = gensym s_id in + let c = Ctxt.add c s_id (Ptr ll_ty, Ll.Id alloca_id)in + c, [] + >:: E(alloca_id, Alloca ll_ty) + >:: I(gensym "store", Store(ll_ty, Id ll_id, Id alloca_id)) + >@ code, + (ll_ty, ll_id)::args + in + let c, args_code, args = List.fold_right add_arg args (c,[],[]) in + let ll_rty = cmp_ret_ty tc frtyp in + let _, block_code = cmp_block tc c ll_rty body in + let argtys, f_param = List.split args in + let f_ty = (argtys, ll_rty) in + let return_code = + let return_val = + match frtyp with + | RetVoid -> None + | RetVal TBool | RetVal TInt -> Some (Const 0L) + | RetVal (TRef _ | TNullRef _) -> Some Null + in + [T (Ret (ll_rty, return_val))] + in + let f_cfg, globals = cfg_of_stream (args_code >@ block_code >@ return_code) in + {f_ty; f_param; f_cfg}, globals + + + +(* Compile a global initializer, returning the resulting LLVMlite global + declaration, and a list of additional global declarations. +*) +let rec cmp_gexp c (tc : TypeCtxt.t) (e:Ast.exp node) : Ll.gdecl * (Ll.gid * Ll.gdecl) list = + match e.elt with + | CNull r -> (cmp_ty tc (TNullRef r), GNull), [] + | CBool b -> (I1, (if b then GInt 1L else GInt 0L)), [] + | CInt i -> (I64, GInt i), [] + | Id id -> ((fst @@ Ctxt.lookup id c), GGid id), [] + + | CStr s -> + let gid = gensym "str" in + let ll_ty = str_arr_ty s in + let cast = GBitcast (Ptr ll_ty, GGid gid, Ptr I8) in + (Ptr I8, cast), [gid, (ll_ty, GString s)] + + | CArr (u, cs) -> + let elts, gs = List.fold_right + (fun cst (elts, gs) -> + let gd, gs' = cmp_gexp c tc cst in + gd::elts, gs' @ gs) cs ([], []) + in + let len = List.length cs in + let ll_u = cmp_ty tc u in + let gid = gensym "global_arr" in + let arr_t = Struct [ I64; Array(len, ll_u) ] in + let arr_i = GStruct [ I64, GInt (Int64.of_int len); Array(len, ll_u), GArray elts ] in + let final_t = Struct [ I64; Array(0, ll_u) ] in + let cast = GBitcast (Ptr arr_t, GGid gid, Ptr final_t) in + (Ptr final_t, cast), (gid, (arr_t, arr_i))::gs + + | CStruct (id, cs) -> + let fields = TypeCtxt.lookup id tc in + let elts, gs = + List.fold_right + (fun fs (elts, gs) -> + let gd, gs' = cmp_gexp c tc (snd (List.find (fun (xid, xname) -> xid = fs.fieldName) cs)) in + (gd :: elts, gs' @ gs)) fields ([], []) in + let gid = gensym "global_struct" in + (Ptr (Namedt id), GGid gid), (gid, (Namedt id, GStruct elts)) :: gs + + | _ -> failwith "bad global initializer" + +(* Oat internals function context ------------------------------------------- *) +let internals = + [ "oat_malloc", Ll.Fun ([I64], Ptr I64) + ; "oat_alloc_array", Ll.Fun ([I64], Ptr I64) + ; "oat_assert_not_null", Ll.Fun ([Ptr I8], Void) + ; "oat_assert_array_length", Ll.Fun ([Ptr I64; I64], Void) + ] + +(* Oat builtin function context --------------------------------------------- *) +let builtins = List.map + (fun (fname, ftyp) -> + let args, ret = cmp_fty TypeCtxt.empty ftyp in + (fname, Ll.Fun (args, ret))) + Typechecker.builtins + + +let tctxt_to_tdecls c = + List.map (fun (i, l) -> i, Struct (List.map (fun f -> cmp_ty c f.ftyp) l)) c + +(* Compile a OAT program to LLVMlite *) +let cmp_prog (p:Ast.prog) : Ll.prog = + let tc = get_struct_defns p in + (* add built-in functions to context *) + let init_ctxt = + List.fold_left (fun c (i, t) -> Ctxt.add c i (Ll.Ptr t, Gid i)) + Ctxt.empty builtins + in + let fc = cmp_function_ctxt tc init_ctxt p in + + (* build global variable context *) + let c = cmp_global_ctxt tc fc p in + (* compile functions and global variables *) + let fdecls, gdecls = + List.fold_right (fun d (fs, gs) -> + match d with + | Ast.Gvdecl { elt=gd } -> + let ll_gd, gs' = cmp_gexp c tc gd.init in + (fs, (gd.name, ll_gd)::gs' @ gs) + | Ast.Gfdecl fd -> + let fdecl, gs' = cmp_fdecl tc c fd in + (fd.elt.fname,fdecl)::fs, gs' @ gs + | Ast.Gtdecl _ -> + fs, gs + ) p ([], []) + in + (* gather external declarations *) + let edecls = internals @ builtins in + { tdecls = tctxt_to_tdecls tc; gdecls; fdecls; edecls } diff --git a/hw6/gradedtests.ml b/hw6/gradedtests.ml new file mode 100644 index 0000000..8b9b644 --- /dev/null +++ b/hw6/gradedtests.ml @@ -0,0 +1,542 @@ +open Assert +open X86 +open Driver +open Ll +open Backend +open Analysistests +open Datastructures + +(* Do NOT modify this file -- we will overwrite it with our *) +(* own version when we test your project. *) + +(* These tests will be used to grade your assignment *) + +let exec_ll_ast path ll_ast args extra_files = + let () = Platform.verb @@ Printf.sprintf "** exec_ll_ast: %s\n" path in + + let output_path = !Platform.output_path in + + (* First - optimize the ll ast *) + let _ = Opt.do_opt := true in + let ll_ast = Opt.optimize ll_ast in + + (* Write out the optimized ll file for debugging purposes *) + let ll_str = Driver.string_of_ll_ast path ll_ast in + let dot_ll_file = Platform.gen_name output_path "test" ".ll" in + let () = write_file dot_ll_file ll_str in + + (* Run the ll backend *) + let _ = Backend.set_liveness "dataflow" in + let _ = Backend.set_regalloc "better" in + let asm_ast = Backend.compile_prog ll_ast in + let asm_str = X86.string_of_prog asm_ast in + + (* Write out the resulting .s file for debugging purposes *) + let dot_s_file = Platform.gen_name output_path "test" ".s" in + let _ = Driver.write_file dot_s_file asm_str in + + (* Create the executable *) + let exec_file = Platform.gen_name output_path "exec" "" in + let _ = Platform.link (dot_s_file::extra_files) exec_file in + + (* Run it, piping the output to a temporary file *) + let tmp_file = Platform.gen_name output_path "tmp" ".txt" in + let result = Driver.run_program args exec_file tmp_file in + let () = Platform.sh (Printf.sprintf "rm -f %s %s %s" dot_ll_file exec_file tmp_file) Platform.ignore_error in + let () = Platform.verb @@ Printf.sprintf "** Executable output:\n%s\n" result in + result + +let exec_ll_file path args = + let ast = Driver.parse_ll_file path in + exec_ll_ast path ast args [] + +let oat_file_e2e_test path args = + let () = Platform.verb @@ Printf.sprintf "** oat_file_e2e_test: %s\n" path in + (* Run the Oat typechecker and frontend *) + let oat_ast = parse_oat_file path in + Typechecker.typecheck_program oat_ast; + let ll_ast = Frontend.cmp_prog oat_ast in + exec_ll_ast path ll_ast args ["runtime.c"] + +let pass_all = ref true +let pass_all_executed_ll_file tests = + List.map (fun (fn, ans) -> + fn, (fun () -> + try assert_eqf (fun () -> exec_ll_file fn "") ans () + with exn -> pass_all := false; raise exn)) + tests + +let pass_all_executed_oat_file tests = + List.map (fun (path, args, ans) -> + (path ^ " args: " ^ args), + (fun () -> + try assert_eqf (fun () -> oat_file_e2e_test path args) ans () + with exn -> pass_all := false; raise exn)) + tests + +let compile_with_config live regalloc ll_ast = + let open Registers in + let open Backend in + let _ = set_liveness live in + let _ = set_regalloc regalloc in + let asm_ast = compile_prog ll_ast in + let (histogram,size) = histogram_of_prog asm_ast in + histogram, size, asm_ast + +let assert_quality fn ll_ast = + if not !pass_all then failwith "Your register allocator failed a correctness test" else + let _ = Opt.do_opt := true in + let ll_ast = Opt.optimize ll_ast in + let h_greedy, size_greedy, x86_greedy = compile_with_config "dataflow" "greedy" ll_ast in + let h_better, size_better, x86_better = compile_with_config "dataflow" "better" ll_ast in + let mem_greedy = Registers.memop_of_prog x86_greedy in + let mem_better = Registers.memop_of_prog x86_better in + let _ = + if !Driver.print_regs_flag then begin + Printf.printf "greedy sz: %4d mem: %4d\t\tbetter sz: %4d mem: %4d \t diff_sz: %4d diff_mem: %4d - %s\n" + size_greedy mem_greedy size_better mem_better (size_greedy - size_better) (mem_greedy - mem_better) fn + end + in + if + mem_better < mem_greedy then () + else if + size_better < size_greedy then () + else failwith @@ Printf.sprintf "greedy is better" + +let assert_quality_oat fn () = + let oat_ast = parse_oat_file fn in + let ll_ast = Frontend.cmp_prog oat_ast in + assert_quality fn ll_ast + +let quality_oat tests = + List.map (fun (fn, _, _) -> fn, assert_quality_oat fn) tests + + + +let fdecl_of_path path = + Platform.verb @@ Printf.sprintf "* processing file: %s\n" path; + let ll_ast = parse_ll_file path in + match ll_ast.Ll.fdecls with + | [_, fdecl] -> fdecl + | _ -> failwith "test expected one fdecl" + +let ll_dfa_file_test path compare analyze expected = + let fdecl = fdecl_of_path path in + let dfa = analyze (Cfg.of_ast fdecl) in + compare dfa expected + +let throw_key_diff compare val_to_string a b = + let keys = LblM.diff_keys compare a b in + if List.length keys == 0 then () + else begin + let str_a = LblM.to_string val_to_string a in + let str_b = LblM.to_string val_to_string b in + failwith @@ Printf.sprintf "Output differs at labels: %s in maps\n%s\n%s\n" + (String.concat ", " keys) + str_a + str_b + end + +let ll_opt_file_test path optimize ans = + let fdecl = fdecl_of_path path in + let expected = (Cfg.of_ast @@ fdecl_of_path ans).Cfg.blocks in + let opt = optimize (Cfg.of_ast fdecl) in + let printer k b = Printf.sprintf "%s %s" (Lbl.to_string k) (Llutil.string_of_block b) in + throw_key_diff Llutil.compare_block printer opt expected + +let dfa_liveness_file (tests : (string * 'a Datastructures.LblM.t) list) = + let open Liveness in + let analyze f = Graph.dfa (analyze f) in + let printer k s = Printf.sprintf "%s %s" (Lbl.to_string k) (UidS.to_string s) in + List.map (fun (path, ans) -> + ("liveness: " ^ path, + fun () -> ll_dfa_file_test path (throw_key_diff Fact.compare printer) analyze ans)) tests + +let dfa_alias_file tests = + let open Alias in + let analyze f = Graph.dfa (analyze f) in + let printer k f = Printf.sprintf "%s %s" (Lbl.to_string k) (Alias.Fact.to_string f) in + List.map (fun (path, ans) -> + ("alias: " ^ path, + fun () -> ll_dfa_file_test path (throw_key_diff Fact.compare printer) analyze ans)) tests + +let dfa_constprop_file tests = + let open Constprop in + let analyze f = Graph.dfa (analyze f) in + let printer k f = Printf.sprintf "%s %s" (Lbl.to_string k) (Constprop.Fact.to_string f) in + List.map (fun (path, ans) -> + ("constprop: " ^ path, + fun () -> ll_dfa_file_test path (throw_key_diff Fact.compare printer) analyze ans)) tests + +let opt_dce_file tests = + let opt g = + let ag = Alias.analyze g in + let lg = Liveness.analyze g in + let g = Dce.run lg ag g in + g.Cfg.blocks + in + List.map (fun (path, ans) -> + (Printf.sprintf "dce opt: %s, %s" + (Filename.basename path) (Filename.basename ans), + fun () -> ll_opt_file_test path opt ans)) tests + +let opt_constfold_file tests = + let opt g = + let cg = Constprop.analyze g in + let g = Constprop.run cg g in + g.Cfg.blocks + in + List.map (fun (path, ans) -> + (Printf.sprintf "constprop opt: %s, %s" + (Filename.basename path) (Filename.basename ans), + fun () -> ll_opt_file_test path opt ans)) tests + +(* this test harness is used for part iv of the homework -------------------- *) +let executed_fullopt_file tests = + let opt n g = let g = Opt.pass n g in g.Cfg.blocks in + List.map (fun (n, path, ans) -> + (Printf.sprintf "fullopt %d iterations: %s" n path, + fun () -> ll_opt_file_test path (opt n) ans)) tests + + +let binop_tests = + [ "llprograms/add.ll", "14" + ; "llprograms/sub.ll", "1" + ; "llprograms/mul.ll", "45" + ; "llprograms/and.ll", "0" + ; "llprograms/or.ll", "1" + ; "llprograms/xor.ll", "0" + ; "llprograms/shl.ll", "168" + ; "llprograms/lshr.ll", "10" + ; "llprograms/ashr.ll", "5" ] + +let calling_convention_tests = + [ "llprograms/call.ll", "42" + ; "llprograms/call1.ll", "17" + ; "llprograms/call2.ll", "19" + ; "llprograms/call3.ll", "34" + ; "llprograms/call4.ll", "34" + ; "llprograms/call5.ll", "24" + ; "llprograms/call6.ll", "26" + ; "llprograms/call7.ll", "7" + ; "llprograms/call8.ll", "21" + ] + +let memory_tests = + [ "llprograms/alloca1.ll", "17" + ; "llprograms/alloca2.ll", "17" + ; "llprograms/global1.ll", "12" + ] + +let terminator_tests = + [ "llprograms/return.ll", "0" + ; "llprograms/return42.ll", "42" + ; "llprograms/br1.ll", "9" + ; "llprograms/br2.ll", "17" + ; "llprograms/cbr1.ll", "7" + ; "llprograms/cbr2.ll", "9" + ; "llprograms/cbr3.ll", "9" + ] + +let bitcast_tests = + [ "llprograms/bitcast1.ll", "3" + ] + +let gep_tests = + [ "llprograms/gep1.ll", "6" + ; "llprograms/gep2.ll", "4" + ; "llprograms/gep3.ll", "1" + ; "llprograms/gep4.ll", "2" + ; "llprograms/gep5.ll", "4" + ; "llprograms/gep6.ll", "7" + ; "llprograms/gep7.ll", "7" + ; "llprograms/gep8.ll", "2" + ; "llprograms/gep9.ll", "5" + ; "llprograms/gep10.ll", "3" + ] + + +let arithmetic_tests = + [ "llprograms/add_twice.ll", "29" + ; "llprograms/sub_neg.ll", "255" (* Why, oh why, does the termianl only report the last byte? *) + ; "llprograms/arith_combo.ll", "4" + ; "llprograms/return_intermediate.ll", "18" ] + +let sum_tree_tests = ["llprograms/sum_tree.ll", "116"] +let gcd_euclidian_tests = [ "llprograms/gcd_euclidian.ll", "2"] +let sieve_tests = [["cinterop.c"], "llprograms/sieve.ll", [], "1"] +let binary_search_tests = ["llprograms/binarysearch.ll", "8"] +let gep_5_deep_tests = ["llprograms/qtree.ll", "3"] +let binary_gcd_tests = ["llprograms/binary_gcd.ll", "3"] +let linear_search_tests = ["llprograms/linear_search.ll", "1"] +let lfsr_tests = ["llprograms/lfsr.ll", "108"] +let naive_factor_tests = + [ "llprograms/naive_factor_prime.ll", "1" + ; "llprograms/naive_factor_nonprime.ll", "0" + ] +let euclid_recursive_test = ["llprograms/euclid.ll", "2"] +let matmul_tests = ["llprograms/matmul.ll", "0"] + +let large_tests = [ "llprograms/list1.ll", "3" + ; "llprograms/cbr.ll", "42" + ; "llprograms/factorial.ll", "120" + ; "llprograms/factrect.ll", "120" + ] + +let ll_tests = + binop_tests + @ terminator_tests + @ memory_tests + @ calling_convention_tests + @ bitcast_tests + @ gep_tests + @ arithmetic_tests + @ sum_tree_tests + @ gcd_euclidian_tests + @ binary_search_tests + @ gep_5_deep_tests + @ binary_gcd_tests + @ linear_search_tests + @ lfsr_tests + @ naive_factor_tests + @ euclid_recursive_test + @ matmul_tests + @ large_tests + +(* Should not be used for quality tests *) +let greedy_is_good_tests = [ + ("oatprograms/easyrun1.oat", "", "17"); + ("oatprograms/easyrun2.oat", "", "35"); + ("oatprograms/easyrun5.oat", "", "212"); + ("oatprograms/easyrun6.oat", "", "9"); + ("oatprograms/easyrun7.oat", "", "23"); + ("oatprograms/easyrun8.oat", "", "160"); + ("oatprograms/path1.oat", "", "17"); + ("oatprograms/run26.oat", "", "0"); + ("oatprograms/run27.oat", "", "99"); + ("oatprograms/run29.oat", "", "1"); + ("oatprograms/run30.oat", "", "9"); + ("oatprograms/run31.oat", "", "9"); + ("oatprograms/run13.oat", "", "1"); + ("oatprograms/run38.oat", "", "31"); + ("oatprograms/run40.oat", "", "8"); + ("oatprograms/run60.oat", "", "85"); + ("oatprograms/heap.oat", "", "1"); + ("hw5programs/ifq2.oat", "", "5"); + ("hw5programs/length1.oat", "", "5"); + ("oatprograms/lcs.oat", "", "OAT0"); +] + + +let hw4_easiest_tests = [ + ("oatprograms/easyrun3.oat", "", "73"); + ("oatprograms/easyrun4.oat", "", "6"); + ("oatprograms/easyrun9.oat", "", "236"); +] + +(* Should not be used for quality tests *) +let hw4_globals_tests = [ + ("oatprograms/globals1.oat", "", "42"); + ("oatprograms/globals2.oat", "", "17"); + ("oatprograms/globals3.oat", "", "17"); + ("oatprograms/globals4.oat", "", "5"); + ("oatprograms/globals5.oat", "", "17"); + ("oatprograms/globals6.oat", "", "15"); +] + +let hw4_path_tests = [ + ("oatprograms/path2.oat", "", "35"); + ("oatprograms/path3.oat", "", "3"); + ("oatprograms/arrayargs1.oat", "", "17"); + ("oatprograms/arrayargs2.oat", "", "17"); + ("oatprograms/arrayargs4.oat", "", "0"); +] + +let hw4_easy_tests = [ + ("oatprograms/run28.oat", "", "18"); + ("oatprograms/run32.oat", "", "33"); + ("oatprograms/run21.oat", "", "99"); + ("oatprograms/run33.oat", "", "1"); + ("oatprograms/run34.oat", "", "66"); + ("oatprograms/run39.oat", "a", "2"); + ("oatprograms/run42.oat", "", "2"); + ("oatprograms/run49.oat", "", "abc0"); + ("oatprograms/run50.oat", "", "abcde0"); + ("oatprograms/run61.oat", "", "3410"); +] + +let hw4_medium_tests = [ + ("oatprograms/fact.oat", "", "1200"); + ("oatprograms/run1.oat", "", "153"); + ("oatprograms/run2.oat", "", "6"); + ("oatprograms/run8.oat", "", "2"); + ("oatprograms/run9.oat", "", "4"); + ("oatprograms/run10.oat", "", "5"); + ("oatprograms/run11.oat", "", "7"); + ("oatprograms/run14.oat", "", "16"); + ("oatprograms/run15.oat", "", "19"); + ("oatprograms/run16.oat", "", "13"); + ("oatprograms/run22.oat", "", "abc0"); + ("oatprograms/run23.oat", "", "1230"); + ("oatprograms/run25.oat", "", "nnn0"); + ("oatprograms/run46.oat", "", "420"); + ("oatprograms/run47.oat", "", "3"); + ("oatprograms/run48.oat", "", "11"); + ("oatprograms/lib4.oat", "", "53220"); + ("oatprograms/lib5.oat", "", "20"); + ("oatprograms/lib6.oat", "", "56553"); + ("oatprograms/lib7.oat", "", "53"); + ("oatprograms/lib8.oat", "", "Hello world!0"); + ("oatprograms/lib9.oat", "a b c d", "abcd5"); + ("oatprograms/lib11.oat", "", "45"); + ("oatprograms/lib14.oat", "", "~}|{zyxwvu0"); + ("oatprograms/lib15.oat", "123456789", "456780"); + ("oatprograms/regalloctest.oat", "", "0"); + ("oatprograms/regalloctest2.oat", "", "137999986200000000") +] + +let hw4_hard_tests = [ +("oatprograms/fac.oat", "", "120"); +("oatprograms/bsort.oat", "", "y}xotnuw notuwxy}255"); +("oatprograms/msort.oat", "", "~}|{zyxwvu uvwxyz{|}~ 0"); +("oatprograms/msort2.oat", "", "~}|{zyxwvu uvwxyz{|}~ 0"); +("oatprograms/selectionsort.oat", "", "01253065992000"); +("oatprograms/matrixmult.oat", "", "19 16 13 23 \t5 6 7 6 \t19 16 13 23 \t5 6 7 6 \t0"); +] + +let hw4_old_student_tests = [ + ("oatprograms/binary_search.oat", "", "Correct!0") + ; ("oatprograms/xor_shift.oat", "", "838867572\n22817190600") + ; ("oatprograms/sieve.oat", "", "25") + ; ("oatprograms/determinant_size2.oat", "", "94") + ; ("oatprograms/fibo.oat", "", "0") + ; ("oatprograms/bubble_sort.oat", "", "1") + ; ("oatprograms/binary_gcd.oat", "", "3") + ; ("oatprograms/lfsr.oat", "", "TFTF FFTT0") + ; ("oatprograms/gnomesort.oat", "", "01253065992000") + ; ("oatprograms/josh_joyce_test.oat", "", "0") + ; ("oatprograms/conquest.oat", "", "My name is Jeff...\nCharizard is the BEST Pokemon ever!!!11") + ; ("oatprograms/gcd.oat", "", "16") + ; ("oatprograms/insertion_sort.oat", "", "42") + ; ("oatprograms/maxsubsequence.oat", "", "107") +] + +let struct_tests = [ +("hw5programs/compile_assign_struct.oat", "", "16"); +("hw5programs/compile_basic_struct.oat", "", "7"); +("hw5programs/compile_global_struct.oat", "", "254"); +("hw5programs/compile_nested_struct.oat", "", "10"); +("hw5programs/compile_return_struct.oat", "", "0"); +("hw5programs/compile_struct_array.oat", "", "15"); +("hw5programs/compile_struct_fptr.oat", "", "7"); +("hw5programs/compile_various_fields.oat", "", "hello253"); +] + +let fptr_tests = [ + ("hw5programs/compile_array_fptr.oat", "", "2"); + ("hw5programs/compile_func_argument.oat", "", "4"); + ("hw5programs/compile_global_fptr.oat", "", "7"); + ("hw5programs/compile_global_fptr_unordered.oat", "", "2"); + ("hw5programs/compile_scall_fptr.oat", "", "4"); + ("hw5programs/compile_var_fptr.oat", "", "1"); + ("hw5programs/compile_local_fptr.oat", "", "5"); + ("hw5programs/compile_function_shadow.oat", "", "12"); + ("hw5programs/compile_global_struct_fptr.oat", "", "20"); + ("hw5programs/compile_builtin_argument.oat", "", "abab0"); +] + +let regalloc_challenge_tests = [ + ("oatprograms/arrayargs3.oat", "", "34"); + ("oatprograms/run41.oat", "", "3"); + ("oatprograms/run51.oat", "", "341"); + ("oatprograms/run52.oat", "", "15"); + ("oatprograms/run54.oat", "", "10"); + ("oatprograms/run55.oat", "", "6"); + ("oatprograms/qsort.oat", "", "kpyf{shomfhkmopsy{255"); + ("oatprograms/count_sort.oat", "", "AFHZAAEYC\nAAACEFHYZ0"); +] + +let new_tests = [ + ("hw5programs/ifq1.oat", "", "4"); + ("hw5programs/length2.oat", "", "3"); + ("hw5programs/initarr1.oat", "", "1"); + ("hw5programs/initarr2.oat", "", "2"); +] + +let oat_regalloc_quality_tests = + hw4_easiest_tests + @ hw4_path_tests + @ hw4_easy_tests + @ hw4_medium_tests + @ hw4_hard_tests + @ hw4_old_student_tests + @ struct_tests + @ fptr_tests + @ new_tests + @ regalloc_challenge_tests + + +let oat_correctness_tests = + oat_regalloc_quality_tests + @ hw4_globals_tests + @ greedy_is_good_tests + +let dce_opt_tests = + [ "llprograms/analysis1_cf_opt.ll", "llprograms/analysis1_dce_opt.ll" + ; "llprograms/analysis2_cf_opt.ll", "llprograms/analysis2_dce_opt.ll" + ; "llprograms/analysis3_cf_opt.ll", "llprograms/analysis3_dce_opt.ll" + ; "llprograms/analysis4_cf_opt.ll", "llprograms/analysis4_dce_opt.ll" + ; "llprograms/analysis5_cf_opt.ll", "llprograms/analysis5_dce_opt.ll" + ; "llprograms/analysis6_cf_opt.ll", "llprograms/analysis6_dce_opt.ll" + ; "llprograms/analysis7_cf_opt.ll", "llprograms/analysis7_dce_opt.ll" + ; "llprograms/analysis8_cf_opt.ll", "llprograms/analysis8_dce_opt.ll" + ; "llprograms/analysis9_cf_opt.ll", "llprograms/analysis9_dce_opt.ll" + ; "llprograms/analysis10_cf_opt.ll", "llprograms/analysis10_dce_opt.ll" + ; "llprograms/analysis11_cf_opt.ll", "llprograms/analysis11_dce_opt.ll" + ; "llprograms/analysis12_cf_opt.ll", "llprograms/analysis12_dce_opt.ll" + ; "llprograms/analysis13_cf_opt.ll", "llprograms/analysis13_dce_opt.ll" + ; "llprograms/analysis14_cf_opt.ll", "llprograms/analysis14_dce_opt.ll" + ; "llprograms/analysis15_cf_opt.ll", "llprograms/analysis15_dce_opt.ll" + ; "llprograms/analysis16_cf_opt.ll", "llprograms/analysis16_dce_opt.ll" + ; "llprograms/analysis17_cf_opt.ll", "llprograms/analysis17_dce_opt.ll" + ; "llprograms/analysis18_cf_opt.ll", "llprograms/analysis18_dce_opt.ll" + ; "llprograms/analysis19_cf_opt.ll", "llprograms/analysis19_dce_opt.ll" + ] + +let constprop_opt_tests = + [ "llprograms/analysis1.ll", "llprograms/analysis1_cf_opt.ll" + ; "llprograms/analysis2.ll", "llprograms/analysis2_cf_opt.ll" + ; "llprograms/analysis3.ll", "llprograms/analysis3_cf_opt.ll" + ; "llprograms/analysis4.ll", "llprograms/analysis4_cf_opt.ll" + ; "llprograms/analysis5.ll", "llprograms/analysis5_cf_opt.ll" + ; "llprograms/analysis6.ll", "llprograms/analysis6_cf_opt.ll" + ; "llprograms/analysis7.ll", "llprograms/analysis7_cf_opt.ll" + ; "llprograms/analysis8.ll", "llprograms/analysis8_cf_opt.ll" + ; "llprograms/analysis9.ll", "llprograms/analysis9_cf_opt.ll" + ; "llprograms/analysis10.ll", "llprograms/analysis10_cf_opt.ll" + ; "llprograms/analysis11.ll", "llprograms/analysis11_cf_opt.ll" + ; "llprograms/analysis12.ll", "llprograms/analysis12_cf_opt.ll" + ; "llprograms/analysis13.ll", "llprograms/analysis13_cf_opt.ll" + ; "llprograms/analysis14.ll", "llprograms/analysis14_cf_opt.ll" + ; "llprograms/analysis15.ll", "llprograms/analysis15_cf_opt.ll" + ; "llprograms/analysis16.ll", "llprograms/analysis16_cf_opt.ll" + ; "llprograms/analysis17.ll", "llprograms/analysis17_cf_opt.ll" + ; "llprograms/analysis18.ll", "llprograms/analysis18_cf_opt.ll" + ; "llprograms/analysis19.ll", "llprograms/analysis19_cf_opt.ll" + ] + + +let tests : suite = + [ + GradedTest("solver / liveness analysis tests", 10, dfa_liveness_file liveness_analysis_tests); + GradedTest("alias analysis tests", 15, dfa_alias_file alias_analysis_tests); + GradedTest("dce optimization tests", 15, opt_dce_file dce_opt_tests); + GradedTest("constprop analysis tests", 15, dfa_constprop_file constprop_analysis_tests); + GradedTest("constprop optimization tests", 10, opt_constfold_file constprop_opt_tests); + Test("ll regalloc correctness tests", pass_all_executed_ll_file ll_tests); + Test("oat regalloc correctness tests", pass_all_executed_oat_file (oat_correctness_tests @ regalloc_challenge_tests)); + GradedTest("oat regalloc quality tests", 35, quality_oat oat_regalloc_quality_tests); +] + +let graded_tests : suite = + tests diff --git a/hw6/hw5programs/apoth_composition.oat b/hw6/hw5programs/apoth_composition.oat new file mode 100644 index 0000000..4bccba5 --- /dev/null +++ b/hw6/hw5programs/apoth_composition.oat @@ -0,0 +1,60 @@ +struct Dog { + string name; + int food +} + +struct TrainableDog { + Dog dog; + int intelligence; + (TrainableDog, int) -> int train +} + +struct Person { + string name; + bool[][] areaMap; + ((Person, int, int) -> void) visit +} + +struct DogOwner { + Person person; + int numDogs; + Dog[] dogs; + (DogOwner, int) -> void feedDogs +} + +int train(TrainableDog tdog, int food) { + tdog.intelligence = tdog.intelligence + 1; + tdog.dog.food = tdog.dog.food + food; + return tdog.dog.food; +} + +void visit(Person p, int x, int y) { p.areaMap[x][y] = true; return; } + +void feedDogs(DogOwner do, int numDogs) { + for (var i = 0; i < numDogs; i = i + 1;) { + do.dogs[i].food = do.dogs[i].food + 1; + } + return; +} + +int program(int argc, string[] argv) { + var dog = new Dog { name = "Holmes"; food = 10 }; + var tdog = new TrainableDog { dog = dog; intelligence = 0; train = train }; + var areaMap = new bool[][] { new bool[] {false, false}, new bool[] {false, true} }; + var p = new Person { name = "Guy"; areaMap = areaMap; visit = visit }; + var do = new DogOwner { feedDogs = feedDogs; numDogs = 1; person = p; dogs = new Dog[] { dog } }; + + var newFood = tdog.train(tdog, 5); + p.visit(p, 0, 0); + do.feedDogs(do, 1); + + var numVisited = 0; + for (var i = 0; i < 2; i = i + 1;) { + for (var j = 0; j < 2; j = j + 1;) { + if (p.areaMap[i][j]) { + numVisited = numVisited + 1; + } + } + } + return dog.food + numVisited; +} \ No newline at end of file diff --git a/hw6/hw5programs/burowski_bfs.oat b/hw6/hw5programs/burowski_bfs.oat new file mode 100644 index 0000000..05ac27f --- /dev/null +++ b/hw6/hw5programs/burowski_bfs.oat @@ -0,0 +1,174 @@ +global debug = false; + +struct Node { + string val; + bool visited; + Queue neighbors; + bool hasNext +} + +struct QNode { + Node node; + QNode next; + bool qhasNext +} + +struct Queue { + QNode head; + QNode tail; + int size +} + +Node getIthInQueue(int i, Queue q) { + var tmp = q.head; + if (i + 1 == q.size) { + return q.tail.node; + } + while (tmp.qhasNext) { + if (i == 0) { + return tmp.node; + } + tmp = tmp.next; + i = i - 1; + } + return newNode("ERROR"); +} + +Node newNode(string v) { + return new Node {val=v; hasNext=false; visited=false; neighbors=newEmptyQueue()}; +} + +QNode newQNode(Node n) { + return new QNode {node=n; next=QNode null; qhasNext=false}; +} + +void printNode(Node n) { + print_string(n.val); + return; +} + +Queue newEmptyQueue() { + return new Queue {head=QNode null; tail=QNode null; size=0}; +} + + +bool isEmpty(Queue q) { + return q.size == 0; +} + +void printNeighbors(Node n) { + printNeighborsDebug(n, debug); + return; +} + +void printNeighborsDebug(Node n, bool d) { + if (!d) { + return; + } + var s = n.neighbors.size; + for (var i = 0; i < s; i = i + 1;) { + var x = getIthInQueue(i, n.neighbors); + printNode(x); + } + print_string("\n"); + return; +} + +void enqueue(Queue q, Node n) { + var node = newQNode(n); + if (q.size == 0) { + q.head = node; + } else { + q.tail.qhasNext = true; + q.tail.next = node; + } + q.size = q.size + 1; + node.qhasNext = false; + q.tail = node; + return; +} + +Node dequeue(Queue q) { + if (isEmpty(q)) { + return newNode(""); + } + var tmp = q.head; + q.head = tmp.next; + q.size = q.size - 1; + return tmp.node; +} + +void addNeighbor(Node tgt, Node toAdd) { + enqueue(tgt.neighbors, toAdd); + return; +} + +void bfs(Node start) { + var q = newEmptyQueue(); + start.visited = true; + enqueue(q, start); + while (!isEmpty(q)) { + var curr = dequeue(q); + printNode(curr); + var s = curr.neighbors.size; + for (var i = 0; i < s; i = i + 1;) { + var n = getIthInQueue(i, curr.neighbors); + if (!(n.visited)) { + n.visited = true; + enqueue(q, n); + } + } + } + return; +} + + +void print_debug(string msg) { + if (!debug) { + return; + } + print_string(msg); + return; +} + +int program (int argc, string[] argv) { + + var there = newNode("there "); + var should = newNode("should "); + var be = newNode("be "); + var better = newNode("better "); + var food = newNode("food "); + var options = newNode("options "); + var on = newNode("on "); + var campus = newNode("campus"); + + addNeighbor(there, should); + addNeighbor(there, be); + addNeighbor(there, better); + + addNeighbor(should, there); + addNeighbor(should, food); + + addNeighbor(be, there); + addNeighbor(be, better); + + + addNeighbor(better, there); + addNeighbor(better, be); + addNeighbor(better, options); + + addNeighbor(food, should); + addNeighbor(food, options); + + addNeighbor(options, food); + addNeighbor(options, better); + addNeighbor(options, on); + addNeighbor(options, campus); + + addNeighbor(on, options); + + addNeighbor(campus, options); + + bfs(there); + return 0; +} \ No newline at end of file diff --git a/hw6/hw5programs/chmartin_heapsort.oat b/hw6/hw5programs/chmartin_heapsort.oat new file mode 100644 index 0000000..d1770b8 --- /dev/null +++ b/hw6/hw5programs/chmartin_heapsort.oat @@ -0,0 +1,77 @@ +struct Heap { + int[] values; + int arr_length; + int size; + (Heap, int) -> void insert; + (Heap) -> int extract_min; + (Heap) -> int peek +} + +void swim (Heap heap, int index) { + while (index > 1 & (heap.values[index >> 1] > heap.values[index])) { + var parent = heap.values[index >> 1]; + heap.values[index >> 1] = heap.values[index]; + heap.values[index] = parent; + index = index >> 1; + } + return; +} + +void sink (Heap heap, int index) { + while (2 * index <= heap.size) { + var j = 2 * index; + if (j < heap.size & (heap.values[j] > heap.values[j + 1])) { + j = j + 1; + } + if (heap.values[index] <= heap.values[j]) { + index = heap.size; + } else { + var parent = heap.values[index]; + heap.values[index] = heap.values[j]; + heap.values[j] = parent; + index = j; + } + } + return; +} + +void insert (Heap heap, int n) { + heap.size = heap.size + 1; + heap.values[heap.size] = n; + swim(heap, heap.size); + return; +} + +int peek (Heap heap) { + return heap.values[1]; +} + +int extract_min (Heap heap) { + var min = heap.values[1]; + heap.values[1] = heap.values[heap.size]; + heap.values[heap.size] = min; + heap.size = heap.size - 1; + sink(heap, 1); + return min; +} + +int[] heapsort (int[] arr, int arr_len) { + var heap = new Heap {values = new int[arr_len + 1]; arr_length = arr_len + 1; size = 0; insert = insert; extract_min = extract_min; peek = peek}; + for (var i = 0; i < arr_len; i = i + 1;) { + heap.insert(heap, arr[i]); + } + for (var i = 0; i < arr_len; i = i + 1;) { + arr[i] = heap.extract_min(heap); + } + return arr; +} + +int program (int argc, string[] argv) { + var arr1 = new int[]{11, -5, 0, 2, 7, 7, 3, -11}; + var sorted_arr = heapsort(arr1, 8); + for (var i = 0; i < 8; i = i + 1;) { + print_int(sorted_arr[i]); + print_string(", "); + } + return 0; +} diff --git a/hw6/hw5programs/compile_array_fptr.oat b/hw6/hw5programs/compile_array_fptr.oat new file mode 100644 index 0000000..3fae796 --- /dev/null +++ b/hw6/hw5programs/compile_array_fptr.oat @@ -0,0 +1,7 @@ +int add(int x, int y) { return x + y; } +int sub(int x, int y) { return x - y; } + +int program(int argc, string[] argv) { + var ops = new ((int, int) -> int) [] { add, sub }; + return ops[0](1, 1); +} diff --git a/hw6/hw5programs/compile_assign_struct.oat b/hw6/hw5programs/compile_assign_struct.oat new file mode 100644 index 0000000..f9e705d --- /dev/null +++ b/hw6/hw5programs/compile_assign_struct.oat @@ -0,0 +1,12 @@ +struct Point { + int x; + int y +} + +int program(int argc, string[] argv) { + var p = new Point {x = 3; y = 4 }; + p.x = 5; + p.y = p.x + p.y + 3; + p.x = p.y + 4; + return p.x; +} diff --git a/hw6/hw5programs/compile_basic_struct.oat b/hw6/hw5programs/compile_basic_struct.oat new file mode 100644 index 0000000..403e60f --- /dev/null +++ b/hw6/hw5programs/compile_basic_struct.oat @@ -0,0 +1,10 @@ +struct Color { + int red; + int green; + int blue +} + +int program (int argc, string[] argv) { + var garr = new Color { red = 3; green = 4; blue = 5 }; + return garr.red + garr.green; +} diff --git a/hw6/hw5programs/compile_builtin_argument.oat b/hw6/hw5programs/compile_builtin_argument.oat new file mode 100644 index 0000000..07440b8 --- /dev/null +++ b/hw6/hw5programs/compile_builtin_argument.oat @@ -0,0 +1,10 @@ +void run2((string) -> void f, string arg) { + f(arg); + f(arg); + return; +} + +int program(int argc, string[] argv) { + run2(print_string, "ab"); + return 0; +} diff --git a/hw6/hw5programs/compile_func_argument.oat b/hw6/hw5programs/compile_func_argument.oat new file mode 100644 index 0000000..ab8e821 --- /dev/null +++ b/hw6/hw5programs/compile_func_argument.oat @@ -0,0 +1,9 @@ +int call((int) -> int f, int arg) { + return f(arg); +} + +int inc(int x) { return x + 1; } + +int program(int argc, string[] argv) { + return call(inc, 3); +} diff --git a/hw6/hw5programs/compile_function_shadow.oat b/hw6/hw5programs/compile_function_shadow.oat new file mode 100644 index 0000000..1fc85e2 --- /dev/null +++ b/hw6/hw5programs/compile_function_shadow.oat @@ -0,0 +1,12 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int mul(int arg1, int arg2) { + return arg1 * arg2; +} + +int program(int argc, string[] argv) { + var add = mul; + return add(3, 4); +} diff --git a/hw6/hw5programs/compile_global_array.oat b/hw6/hw5programs/compile_global_array.oat new file mode 100644 index 0000000..21f4c7a --- /dev/null +++ b/hw6/hw5programs/compile_global_array.oat @@ -0,0 +1,15 @@ +struct Point { + int x; + int y; + int z +} + +global x = Point[] {Point {x = 3; y = 4; z = 5}, Point {x = 1; y = 2; z = 3}}; + +int program(int argc, string[] argv) { + var i = 0; + for (var j = 0; j < 2; j = j + 1;) { + i = i + x[j].y; + } + return i; +} diff --git a/hw6/hw5programs/compile_global_fptr.oat b/hw6/hw5programs/compile_global_fptr.oat new file mode 100644 index 0000000..d76cc3f --- /dev/null +++ b/hw6/hw5programs/compile_global_fptr.oat @@ -0,0 +1,9 @@ +int add(int x, int y) { + return x + y; +} + +global x = add; + +int program(int argc, string[] argv) { + return x(3, 4); +} diff --git a/hw6/hw5programs/compile_global_fptr_unordered.oat b/hw6/hw5programs/compile_global_fptr_unordered.oat new file mode 100644 index 0000000..77be0ce --- /dev/null +++ b/hw6/hw5programs/compile_global_fptr_unordered.oat @@ -0,0 +1,9 @@ +global plus = add; + +int add(int x, int y) { + return x + y; +} + +int program(int argc, string[] argv) { + return plus(1, 1); +} diff --git a/hw6/hw5programs/compile_global_struct.oat b/hw6/hw5programs/compile_global_struct.oat new file mode 100644 index 0000000..058619f --- /dev/null +++ b/hw6/hw5programs/compile_global_struct.oat @@ -0,0 +1,12 @@ +struct Color { + int red; + int green; + int blue +} + +global white = new Color { red = 255; green = 254; blue = 253 }; + +int program (int argc, string[] argv) { + var garr = new Color { red = 3; green = 5; blue = 7 }; + return white.blue + 1; +} diff --git a/hw6/hw5programs/compile_global_struct_fptr.oat b/hw6/hw5programs/compile_global_struct_fptr.oat new file mode 100644 index 0000000..3024063 --- /dev/null +++ b/hw6/hw5programs/compile_global_struct_fptr.oat @@ -0,0 +1,17 @@ +struct Color { + int red; + int green; + int blue; + (Color) -> Color f +} + +Color rot(Color c1) { + var c2 = new Color{ red = c1.green; green = c1.blue; blue = c1.red; f = c1.f }; + return c2; +} + +global c = new Color { red = 10; green = 20; blue = 30 ; f = rot}; + +int program (int argc, string[] argv) { + return c.f(c).red; +} diff --git a/hw6/hw5programs/compile_local_fptr.oat b/hw6/hw5programs/compile_local_fptr.oat new file mode 100644 index 0000000..c331478 --- /dev/null +++ b/hw6/hw5programs/compile_local_fptr.oat @@ -0,0 +1,9 @@ +int add(int x, int y) { + return x + y; +} + +int program(int argc, string[] argv) { + var plus = add; + var loc_add = plus; + return loc_add(2, 3); +} diff --git a/hw6/hw5programs/compile_nested_struct.oat b/hw6/hw5programs/compile_nested_struct.oat new file mode 100644 index 0000000..6e84a67 --- /dev/null +++ b/hw6/hw5programs/compile_nested_struct.oat @@ -0,0 +1,25 @@ +struct RGB { + int red; + int green; + int blue +} + +struct Point { + RGB x; + RGB y; + RGB z +} + +global red = new RGB {red = 255; blue = 0; green = 0 }; +global green = new RGB {red = 0; blue = 0; green = 255 }; +global blue = new RGB {blue = 255; red = 0; green = 0 }; +global points = new Point[] {new Point {x=new RGB {red=255; blue=0; green=0}; + y=new RGB {green=255; blue=0; red=0}; + z=new RGB {blue=255; green=0; red=0}}}; + +int program(int argc, string[] argv) { + points[0].x.red = 3; + points[0].x.green = 2; + points[0].x.blue = 4; + return points[0].x.red * points[0].x.green + points[0].x.blue; +} diff --git a/hw6/hw5programs/compile_object_like.oat b/hw6/hw5programs/compile_object_like.oat new file mode 100644 index 0000000..1877def --- /dev/null +++ b/hw6/hw5programs/compile_object_like.oat @@ -0,0 +1,15 @@ +struct Point { + int x; + int y; + ((Point) -> int) f +} + +int sum(Point p) { + return p.x + p.y; +} + +global p = Point {x=3; y=4; f=sum}; + +int program (int argc, string[] argv) { + return p.f(p); +} diff --git a/hw6/hw5programs/compile_return_struct.oat b/hw6/hw5programs/compile_return_struct.oat new file mode 100644 index 0000000..0931c23 --- /dev/null +++ b/hw6/hw5programs/compile_return_struct.oat @@ -0,0 +1,17 @@ +struct Pair { + bool x; + bool y +} + +Pair create_pair(bool a, bool b) { + return new Pair {x = a; y = b}; +} + +int program(int argc, string[] argv) { + var p = create_pair(true, false); + if (p.x & p.y) { + return 1; + } else { + return 0; + } +} diff --git a/hw6/hw5programs/compile_scall_fptr.oat b/hw6/hw5programs/compile_scall_fptr.oat new file mode 100644 index 0000000..20162a0 --- /dev/null +++ b/hw6/hw5programs/compile_scall_fptr.oat @@ -0,0 +1,10 @@ +void inc_first(int[] x) { + x[0] = x[0] + 1; + return; +} + +int program(int argc, string[] argv) { + var x = new int[] {3, 4, 5}; + inc_first(x); + return x[0]; +} diff --git a/hw6/hw5programs/compile_struct_array.oat b/hw6/hw5programs/compile_struct_array.oat new file mode 100644 index 0000000..4c63bab --- /dev/null +++ b/hw6/hw5programs/compile_struct_array.oat @@ -0,0 +1,13 @@ +struct Test { + int[] xs; + int y; + int[] zs +} + +global arr_x = new int[] {3,4,5}; +global arr_z = new int[] {4,5,6}; + +int program(int argc, string[] argv) { + var t = new Test {xs=arr_x; y=3; zs=arr_z}; + return t.xs[0] * t.zs[1]; +} diff --git a/hw6/hw5programs/compile_struct_fptr.oat b/hw6/hw5programs/compile_struct_fptr.oat new file mode 100644 index 0000000..4319004 --- /dev/null +++ b/hw6/hw5programs/compile_struct_fptr.oat @@ -0,0 +1,12 @@ +struct S { + int s; + int t; + (int, int) -> int f +} + +int add(int x, int y) { return x + y; } + +int program(int argc, string[] argv) { + var x = new S { s = 3; t = 4; f = add }; + return x.f(x.s, x.t); +} diff --git a/hw6/hw5programs/compile_struct_lhs.oat b/hw6/hw5programs/compile_struct_lhs.oat new file mode 100644 index 0000000..ee5a7dd --- /dev/null +++ b/hw6/hw5programs/compile_struct_lhs.oat @@ -0,0 +1,11 @@ +struct Color { + int red; + int green; + int blue +} + +int program (int argc, string[] argv) { + var garr = new Color { red = 3; green = 4; blue = 5 }; + garr.red = 17; + return garr.red + garr.green; +} diff --git a/hw6/hw5programs/compile_struct_reordered.oat b/hw6/hw5programs/compile_struct_reordered.oat new file mode 100644 index 0000000..3315194 --- /dev/null +++ b/hw6/hw5programs/compile_struct_reordered.oat @@ -0,0 +1,8 @@ +struct Pair { + int x; + int y +} + +int program(int argc, string[] argv) { + return (new Pair {y = 3; x = 4}).y; +} diff --git a/hw6/hw5programs/compile_var_fptr.oat b/hw6/hw5programs/compile_var_fptr.oat new file mode 100644 index 0000000..d020345 --- /dev/null +++ b/hw6/hw5programs/compile_var_fptr.oat @@ -0,0 +1,6 @@ +int id(int x) { return x; } + +int program(int argc, string[] argv) { + var id_local = id; + return id_local(1); +} diff --git a/hw6/hw5programs/compile_various_fields.oat b/hw6/hw5programs/compile_various_fields.oat new file mode 100644 index 0000000..3e2e8be --- /dev/null +++ b/hw6/hw5programs/compile_various_fields.oat @@ -0,0 +1,20 @@ +struct Test { + int i; + bool b; + string s; + int[] arr; + Test? t; + (int) -> int f +} + +int neg(int x) { return -x; } + +int program(int argc, string[] argv) { + var n = new Test {i=3; b=true; s="hello"; arr=new int[3]{j->0}; t=Test null; f=neg}; + print_string(n.s); + if(n.b) { + return n.f(n.i); + } else { + return n.i; + } +} diff --git a/hw6/hw5programs/davidcao_treefunctions.oat b/hw6/hw5programs/davidcao_treefunctions.oat new file mode 100644 index 0000000..3f19d31 --- /dev/null +++ b/hw6/hw5programs/davidcao_treefunctions.oat @@ -0,0 +1,119 @@ +struct Node { + int val; + bool hasleft; + bool hasright; + Node left; + Node right +} + +void treemap(Node t, (int) -> int f) { + t.val = f(t.val); + if (t.hasleft) { + treemap(t.left, f); + } + if (t.hasright) { + treemap(t.right, f); + } + return; +} + +bool for_all(Node t, (int) -> bool pred) { + var result = pred(t.val); + if(t.hasleft & t.hasright) { + return result & for_all(t.left, pred) & for_all(t.right, pred); + } else if (t.hasleft) { + return result & for_all(t.left, pred); + } else if (t.hasright) { + return result & for_all(t.right, pred); + } + + return result; +} + +bool xor(bool b1, bool b2) { + return (b1 | b2) & !(b1 & b2); +} + +bool tree_eq (Node t1, Node t2) { + if (t1.val != t2.val) { + return false; + } else { + var flag = true; + if (t1.hasleft & t2.hasleft) { + flag = flag & tree_eq(t1.left, t2.left); + } + if (t1.hasright & t2.hasright) { + flag = flag & tree_eq(t1.right, t2.right); + } + if (xor(t1.hasleft, t2.hasleft)) { + return false; + } + if (xor(t1.hasright, t2.hasright)) { + return false; + } + return flag; + } +} + +int double(int i) { + return i*2; +} + +bool pred_lt_6 (int i) { + return i < 6; +} + +int program(int argc, string[] argv) { + var a1 = new Node{val = 1; hasleft = false; hasright = false; left = Node null; right = Node null }; + var a2 = new Node{val = 2; hasleft = true; hasright = false; left = a1; right = Node null }; + var a3 = new Node{val = 3; hasleft = false; hasright = false; left = Node null; right = Node null }; + var a4 = new Node{val = 4; hasleft = true; hasright = true; left = a2; right = a3 }; + var a5 = new Node{val = 5; hasleft = false; hasright = false; left = Node null; right = Node null }; + var root = new Node{val = 0; hasleft = true; hasright = true; left = a5; right = a4 }; + + var b1 = new Node{val = 1; hasleft = false; hasright = false; left = Node null; right = Node null }; + var b6 = new Node{val = 6; hasleft = false; hasright = false; left = Node null; right = Node null }; + var b2 = new Node{val = 2; hasleft = true; hasright = true; left = b1; right = b6 }; + var b3 = new Node{val = 3; hasleft = false; hasright = false; left = Node null; right = Node null }; + var b4 = new Node{val = 4; hasleft = true; hasright = true; left = b2; right = b3 }; + var b5 = new Node{val = 5; hasleft = false; hasright = false; left = Node null; right = Node null }; + var root2 = new Node{val = 0; hasleft = true; hasright = true; left = b5; right = b4 }; + + var c1 = new Node{val = 2; hasleft = false; hasright = false; left = Node null; right = Node null }; + var c2 = new Node{val = 4; hasleft = true; hasright = false; left = c1; right = Node null }; + var c3 = new Node{val = 6; hasleft = false; hasright = false; left = Node null; right = Node null }; + var c4 = new Node{val = 8; hasleft = true; hasright = true; left = c2; right = c3 }; + var c5 = new Node{val = 10; hasleft = false; hasright = false; left = Node null; right = Node null }; + var root3 = new Node{val = 0; hasleft = true; hasright = true; left = c5; right = c4 }; + + if (tree_eq(root,root)) { + print_string("1"); + } + + if (tree_eq(root2,root2)) { + print_string("2"); + } + + if (!tree_eq(root,root2)) { + print_string("3"); + } + + if (!tree_eq(root2,root)) { + print_string("4"); + } + + if (for_all(root, pred_lt_6)) { + print_string("5"); + } + + treemap(root,double); + if (tree_eq(root, root3)) { + print_string("6"); + } + + if (!for_all(root, pred_lt_6)) { + print_string("7"); + } + + return 0; +} diff --git a/hw6/hw5programs/hand_rgb_to_gray.oat b/hw6/hw5programs/hand_rgb_to_gray.oat new file mode 100644 index 0000000..f86dc11 --- /dev/null +++ b/hw6/hw5programs/hand_rgb_to_gray.oat @@ -0,0 +1,77 @@ +struct RGB { + int red; + int green; + int blue +} + +struct GrayScale { + int lightness; + int average; + int luminosity +} + +int div (int a, int b) { + var count = 0; + var cur_num = a; + while (cur_num - b >= 0) { + cur_num = cur_num - b; + count = count + 1; + } + return count; +} + +int max (int a, int b, int c) { + var m = 0; + if (a > b) { + m = a; + } else { + m = b; + } + + if (c > m) { + m = c; + } + + return m; +} + +int min (int a, int b, int c) { + var m = 300; + if (a < b) { + m = a; + } else { + m = b; + } + + if (c < m) { + m = c; + } + + return m; +} + +GrayScale rgbtogray (RGB rgb) { + var maxNum = max(rgb.red, rgb.green, rgb.blue); + var minNum = min(rgb.red, rgb.green, rgb.blue); + + var maxmin = maxNum + minNum; + var light = div(maxmin, 2); + + var averageSum = rgb.red + rgb.green + rgb.blue; + var ave = div(averageSum, 3); + + var luminositySum = (rgb.red * 21) + (rgb.green * 72) + (rgb.blue * 7); + var lum = luminositySum; + + var gray = new GrayScale { lightness = light; average = ave; luminosity = lum }; + return gray; +} + +global rgb = RGB { red = 200; green = 150; blue = 100 }; + +global gray = GrayScale { lightness = 150; average = 150; luminosity = 150 }; + +int program (int argc, string[] argv) { + var convert = rgbtogray(rgb); + return (convert.average - gray.average) + (convert.lightness - gray.lightness); +} diff --git a/hw6/hw5programs/hta_map_reduce.oat b/hw6/hw5programs/hta_map_reduce.oat new file mode 100644 index 0000000..2b488cd --- /dev/null +++ b/hw6/hw5programs/hta_map_reduce.oat @@ -0,0 +1,98 @@ +/* Simulates nodes which perform a map job */ +int[] map ((int) -> int f, int[] src, int len) { + var tgt = new int[len]; + for (var i = 0; i < len; i = i + 1;) { tgt[i] = f(src[i]); } + return tgt; +} + +struct MapJob { + (int) -> int f; + int[] arr; + int arrlen +} + +int[] mapNode(MapJob j) { return map(j.f, j.arr, j.arrlen); } + +/* Simulates nodes which perform a reduce job */ + +int reduce((int, int) -> int f, int[] arr, int len, int base) { + var acc = base; + for (var i = 0; i < len; i = i + 1;) { acc = f(acc, arr[i]); } + return acc; +} + +struct ReduceJob { + int[] arr; + int arrlen; + (int, int) -> int f; + int base +} + +int reduceNode(ReduceJob j) { return reduce(j.f, j.arr, j.arrlen, j.base); } + +/* Generates an array of data, partitions it into map jobs and assigns + them to virtual map nodes. When all data is mapped, reduces it into + an answer and returns it */ + +int square(int elt) { return elt * elt; } + +int sum(int acc, int elt) { return acc + elt; } + +int sumOfSquares(int[] arr, int arrlen, int numPartitions, int partitionLen) { + /* Partition array into almost equal subarrays */ + var src = new int[][numPartitions]; + for (var i = 0; i < numPartitions; i = i + 1;) { + src[i] = new int[partitionLen]; + } + var j = 0; + var k = 0; + for (var i = 0; i < arrlen; i = i + 1;) { + src[j][k] = arr[i]; + if (j == numPartitions - 1) { + j = 0; + k = k + 1; + } else { j = j + 1; } + } + /* Build map-jobs */ + var mapJobs = new MapJob[numPartitions]; + for (var i = 0; i < numPartitions; i = i + 1;) { + mapJobs[i] = new MapJob { + f = square; + arr = src[i]; + arrlen = partitionLen + }; + } + /* Map! */ + var tgt = new int[][numPartitions]; + for (var i = 0; i < numPartitions; i = i + 1;) { + tgt[i] = mapNode(mapJobs[i]); + } + + /* Build reduce-jobs */ + var reduceJobs = new ReduceJob[numPartitions]; + for (var i = 0; i < numPartitions; i = i + 1;) { + reduceJobs[i] = new ReduceJob { + f = sum; + arr = tgt[i]; + arrlen = partitionLen; + base = 0 + }; + } + /* Reduce! */ + var acc = 0; + for (var i = 0; i < numPartitions; i = i + 1;) { + acc = acc + reduceNode(reduceJobs[i]); + } + return acc; +} + +int program(int argc, string[] argv) { + /* Initialize array with first n positive ints */ + var n = 30; + var arr = new int[n]; + for (var i = 0; i < n; i = i + 1;) { arr[i] = i + 1; } + /* Need partitionLen * numPartitions >= arr.length */ + var numPartitions = 5; + var partitionLen = 6; + return sumOfSquares(arr, n, numPartitions, partitionLen); +} diff --git a/hw6/hw5programs/ifq1.oat b/hw6/hw5programs/ifq1.oat new file mode 100644 index 0000000..5d2c351 --- /dev/null +++ b/hw6/hw5programs/ifq1.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var x = int[] null; + x = new int[3]{i -> 0}; + var z = 0; + if? (int[] y = x) { + z = 4; + } else { + z = 5; + } + return z; +} diff --git a/hw6/hw5programs/ifq2.oat b/hw6/hw5programs/ifq2.oat new file mode 100644 index 0000000..9c809e4 --- /dev/null +++ b/hw6/hw5programs/ifq2.oat @@ -0,0 +1,10 @@ +int program (int argc, string[] argv) { + var x = int[] null; + var z = 0; + if? (int[] y = x) { + z = 4; + } else { + z = 5; + } + return z; +} diff --git a/hw6/hw5programs/ifq3.oat b/hw6/hw5programs/ifq3.oat new file mode 100644 index 0000000..783a464 --- /dev/null +++ b/hw6/hw5programs/ifq3.oat @@ -0,0 +1,16 @@ +int sum(int[]? arr) { + var z = 0; + if?(int[] a = arr) { + for(var i = 0; i i + 1}; + return x[0]; +} diff --git a/hw6/hw5programs/initarr2.oat b/hw6/hw5programs/initarr2.oat new file mode 100644 index 0000000..08d1c9c --- /dev/null +++ b/hw6/hw5programs/initarr2.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[3] {i -> 2}; + return x[0]; +} diff --git a/hw6/hw5programs/jacbrad_kruskal.oat b/hw6/hw5programs/jacbrad_kruskal.oat new file mode 100644 index 0000000..2dbfb1d --- /dev/null +++ b/hw6/hw5programs/jacbrad_kruskal.oat @@ -0,0 +1,120 @@ +struct Edge { + int u; + int v; + int weight +} + +int compare(Edge e1, Edge e2) { + return e1.weight - e2.weight; +} + +void sort((Edge, Edge) -> int cmp, int len, Edge[] list) { + + for(var i = 1; i < len; i = i + 1;){ + var j = i - 1; + var toswap = list[i]; + while(j >= 0) { + if(cmp(list[j], toswap) > 0) { + var temp = list[j]; + list[j] = list[j+1]; + list[j+1] = temp; + j = j - 1; + } + else { + j = -1; + } + } + } + return; +} + + +int[] create_ufind(int len) +{ + var arr = new int[len]; + for(var i = 0; i < len; i = i + 1;) + { + arr[i] = i; + } + return arr; + +} + +void union(int[] comps, int u, int v) +{ + var cU = find(comps, u); + var cV = find(comps, v); + + if(cU == cV) + { + return; + } + + comps[cU] = cV; + return; +} + +int find(int[] comps, int u) +{ + var root = u; + while(root != comps[root]) + { + root = comps[root]; + } + + while(u != root) + { + var parent = find(comps, comps[u]); + comps[u] = root; + u = parent; + + } + + return root; + +} + +Edge[] findMST(Edge[] edges, int m, int n) { + sort(compare, m, edges); + var uf = create_ufind(n); + var result = new Edge[n-1]; + var size = 0; + var count = 0; + + while(size < n - 1){ + + if(find(uf, edges[count].u) != find(uf, edges[count].v)){ + result[size] = edges[count]; + union(uf, edges[count].u, edges[count].v); + size = size + 1; + } + + count = count + 1; + } + return result; +} + + +int program (int argc, string[] argv) { + var e1 = new Edge {u = 1; v = 2; weight = 3}; + var e2 = new Edge {u = 0; v = 1; weight = 20}; + var e3 = new Edge {u = 1; v = 4; weight = 1}; + var e4 = new Edge {u = 2; v = 4; weight = 5}; + var e5 = new Edge {u = 3; v = 4; weight = 6}; + var e6 = new Edge {u = 2; v = 3; weight = 4}; + + var edges = new Edge[]{e1, e2, e3, e4, e5, e6}; + var mst = findMST(edges, 6, 5); + + for(var i = 0; i < 4; i = i + 1;){ + print_string("("); + print_int(mst[i].u); + print_string(","); + print_int(mst[i].v); + print_string(","); + print_int(mst[i].weight); + print_string(") "); + } + print_string("="); + return 0; +} diff --git a/hw6/hw5programs/johnhew_pagerank.oat b/hw6/hw5programs/johnhew_pagerank.oat new file mode 100644 index 0000000..ef50c1a --- /dev/null +++ b/hw6/hw5programs/johnhew_pagerank.oat @@ -0,0 +1,81 @@ +struct Node { + int value; + int new_value; + bool[] incoming_edges; + int outgoing_count +} + +struct PageRank { + int iterations; + (int, int) -> int division_fun; + (Node[], int) -> void iteration_fun; + (Node[], int, int) -> void run_fun +} + +int divide(int dividend, int divisor) { + var quotient = 0; + while (dividend > divisor) { + quotient = quotient + 1; + dividend = dividend - divisor; + } + /*print_int(quotient); + print_string("quotient\n");*/ + return quotient; +} + +void inter(Node[] nodes, int node_count) { + for (var i = 0; i < node_count; i = i+1; ) { + for (var j = 0; j < node_count; j = j+1; ) { + if (nodes[i].incoming_edges[j]) { + nodes[i].new_value = nodes[i].new_value + divide(nodes[j].value, nodes[j].outgoing_count); /* TODO: implement divide by number of outgoing edges. */ + } + } + } + for(var i = 0; i < node_count; i = i+1;) { + var half = nodes[i].new_value >> 1; + var quarter = nodes[i].new_value >> 2; + nodes[i].value = divide(250000,node_count) + half + quarter; /* This is 250000 (rather than 0.25) because of the lack of floating point support. */ + nodes[i].new_value = 0; + } + return; +} + +void run(Node[] nodes, int node_count, int iterations) { + for (var i = 0; i < 100; i = i + 1;) { + inter(nodes, node_count); + } + return; +} + +int program (int argc, string[] argv) { + var node_count = 3; + var nodes = new Node[node_count]; + var node_1_arr = new bool[] {false, false, true}; + var node_2_arr = new bool[] {false, false, false}; + var node_3_arr = new bool[] {true, true, false}; + nodes[0] = new Node {value = 333333; new_value = 0; incoming_edges = node_1_arr; outgoing_count = 1}; + nodes[1] = new Node {value = 333333; new_value = 0; incoming_edges = node_2_arr; outgoing_count = 1}; + nodes[2] = new Node {value = 333333; new_value = 0; incoming_edges = node_3_arr; outgoing_count = 1}; + + var pr = new PageRank {iterations = 100; division_fun = divide; iteration_fun = inter; run_fun = run}; + pr.run_fun(nodes, 3, 100); + + /*for (var i = 0; i < 100; i = i + 1;) { + inter(nodes, node_count); + }*/ + /*print_string("Results\n"); + print_string("Node 0: "); + print_int(nodes[0].value); + print_string("\n"); + print_string("Node 1: "); + print_int(nodes[1].value); + print_string("\n"); + print_string("Node 2: "); + print_int(nodes[2].value); + print_string("\n"); + print_string("Sum: "); + print_int(nodes[0].value + nodes[1].value + nodes[2].value); + print_string("\n");*/ + print_int(nodes[2].value); + return 0; +} diff --git a/hw6/hw5programs/kyim_test.oat b/hw6/hw5programs/kyim_test.oat new file mode 100644 index 0000000..d68a336 --- /dev/null +++ b/hw6/hw5programs/kyim_test.oat @@ -0,0 +1,53 @@ +global path1 = int[]{0, 0, 1}; +global path2 = int[]{1, 1, 0}; + +struct Node { + int val; + Node left; + Node right; + (int, int) -> int fun +} + +int sum_plus_one(int x, int y) { + return x+y+1; +} + +int two_x_plus_y(int x, int y) { + return 2*x+y; +} + +void make_children(Node root, int depth) { + if (depth != 0) { + var left_node = new Node{val=root.fun(root.val, 0); left=Node null; right=Node null; fun=root.fun}; + make_children(left_node, depth-1); + var right_node = new Node{val=root.fun(root.val, 1); left=Node null; right=Node null; fun=root.fun}; + make_children(right_node, depth-1); + root.left = left_node; + root.right = right_node; + } + return; +} + +int retrieve(Node root, int depth, int[] path) { + var next = root.right; + if (path[depth] == 0) { + next = root.left; + } + if (depth == 0) { + return next.val; + } else { + return retrieve(next, depth-1, path); + } +} + +int program(int argc, string[] argv) { + var root1 = new Node{val=1; left=Node null; right=Node null; fun=sum_plus_one}; + var root2 = new Node{val=2; left=Node null; right=Node null; fun=two_x_plus_y}; + make_children(root1, 3); + make_children(root2, 3); + if (retrieve(root1, 2, path1) == 5 & retrieve(root2, 2, path2) == 19) { + return 1; + } else { + return 0; + } +} diff --git a/hw6/hw5programs/length1.oat b/hw6/hw5programs/length1.oat new file mode 100644 index 0000000..eb365bf --- /dev/null +++ b/hw6/hw5programs/length1.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[] {3,4,5,6,7}; + return length(x); +} diff --git a/hw6/hw5programs/length2.oat b/hw6/hw5programs/length2.oat new file mode 100644 index 0000000..752811c --- /dev/null +++ b/hw6/hw5programs/length2.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[3]{i -> 0}; + return length(x); +} diff --git a/hw6/hw5programs/leqiliu_traversal.oat b/hw6/hw5programs/leqiliu_traversal.oat new file mode 100644 index 0000000..795591a --- /dev/null +++ b/hw6/hw5programs/leqiliu_traversal.oat @@ -0,0 +1,61 @@ +struct Tree { + int val; + Tree left; + Tree right; + (int) -> void f +} + +void print(int val) { + print_string(string_cat("->", string_of_int(val))); + return; +} + +void in_order_traverse(Tree tree) { + tree.f(tree.val); + if(tree.left.val != 0) { + in_order_traverse(tree.left); + } + + if(tree.right.val != 0) { + in_order_traverse(tree.right); + } + return; +} + +void pre_order_traverse(Tree tree) { + if(tree.left.val != 0) { + pre_order_traverse(tree.left); + } + + tree.f(tree.val); + + if(tree.right.val != 0) { + pre_order_traverse(tree.right); + } + return; +} + +void post_order_traverse(Tree tree) { + if(tree.left.val != 0) { + post_order_traverse(tree.left); + } + + if(tree.right.val != 0) { + post_order_traverse(tree.right); + } + + tree.f(tree.val); + return; +} + +int program(int argc, string[] argv) { + var nullchild = new Tree { val = 0; left = Tree null; right = Tree null; f = print}; + var rightchild = new Tree { val = 1; left = nullchild; right = nullchild; f = print }; + var leftchild = new Tree { val = 1; left = nullchild; right = nullchild; f = print }; + var tree = new Tree { val = 2; left = leftchild; right = rightchild; f = print }; + + pre_order_traverse(tree); + in_order_traverse(tree); + post_order_traverse(tree); + return 0; +} \ No newline at end of file diff --git a/hw6/hw5programs/maale_odd_even.oat b/hw6/hw5programs/maale_odd_even.oat new file mode 100644 index 0000000..ef58e55 --- /dev/null +++ b/hw6/hw5programs/maale_odd_even.oat @@ -0,0 +1,35 @@ +int[] oddevensort (int[] input, int len) { + var sorted = false; + while(!sorted) { + sorted = true; + for(var i = 1; i < len - 1; i = i + 2;) { + if(input[i] > input[i + 1]) { + var temp = input[i]; + input[i] = input[i + 1]; + input[i + 1] = temp; + sorted = false; + } + } + + for(var j = 0; j < len - 1; j = j + 2;) { + if(input[j] > input[j+1]) { + var temp = input[j]; + input[j] = input[j + 1]; + input[j + 1] = temp; + sorted = false; + } + } + } + return input; +} + +int program (int argc, string[] argv) { + var arr = new int[]{ 5, 200, 1, 65, 30, 99, 2, 0 }; + var len = 8; + var sorted = oddevensort(arr, len); + for(var i=0; i 0) { + var d = s * s; + if (d > n) { + n = -1; + } else { + s = s + 1; + } + } + return s - 1; +} + +int side_squared(Point p1, Point p2) { + var m1 = (p1.x - p2.x) * (p1.x - p2.x); + var m2 = (p1.y - p2.y) * (p1.y - p2.y); + if (m1 > m2) { + return m1 - m2; + } else { + return m2 - m1; + } +} + +int pythagorean(Triangle t) { + var s1 = side_squared(t.p1, t.p2); + var s2 = side_squared(t.p2, t.p3); + return sqrt(s1 + s2); +} + +struct Triangle { + Point p1; + Point p2; + Point p3 +} + +struct Point { + int x; + int y +} + +global points = Point[] {Point { x = 0; y = 0 }, Point { x = 4; y = 0 }, Point { x = 4; y = 3 }}; + +int program(int argc, string[] argv) { + var t = new Triangle { p1 = points[0]; p2 = points[1]; p3 = points[2] }; + return pythagorean(t); +} \ No newline at end of file diff --git a/hw6/hw5programs/negative_array_index.oat b/hw6/hw5programs/negative_array_index.oat new file mode 100644 index 0000000..530989e --- /dev/null +++ b/hw6/hw5programs/negative_array_index.oat @@ -0,0 +1,5 @@ +int program(string[] args) { + var arr = new int[]{1, 2, 3}; + var x = arr[-1]; + return x; +} \ No newline at end of file diff --git a/hw6/hw5programs/olekg_fold_struct.oat b/hw6/hw5programs/olekg_fold_struct.oat new file mode 100644 index 0000000..839dc74 --- /dev/null +++ b/hw6/hw5programs/olekg_fold_struct.oat @@ -0,0 +1,32 @@ +struct Node { + int i; + Node next; + bool hasNext +} + +int minus(int x, int y) { return x - y; } + +int plus(int x, int y) { return x + y; } + +int fold_str_int(Node n, (int, int) -> int f, int base) { + if(n.hasNext) { + var newBase = f(base, n.i); + return fold_str_int(n.next, f, newBase); + } else { + return f(base, n.i); + } +} + + +int program(int argc, string[] argv) { + var n9 = new Node {i=9; next=Node null; hasNext=false}; + var n8 = new Node {i=8; next=n9; hasNext=true}; + var n7 = new Node {i=7; next=n8; hasNext=true}; + var n6 = new Node {i=6; next=n7; hasNext=true}; + var n5 = new Node {i=5; next=n6; hasNext=true}; + var n4 = new Node {i=4; next=n5; hasNext=true}; + var n3 = new Node {i=3; next=n4; hasNext=true}; + var n2 = new Node {i=2; next=n3; hasNext=true}; + var n1 = new Node {i=1; next=n2; hasNext=true}; + return fold_str_int(n1, plus, 0) - fold_str_int(n1, minus, 2); +} \ No newline at end of file diff --git a/hw6/hw5programs/run44fixed.oat b/hw6/hw5programs/run44fixed.oat new file mode 100644 index 0000000..1c35c25 --- /dev/null +++ b/hw6/hw5programs/run44fixed.oat @@ -0,0 +1,20 @@ +global str = string[][][][][][][][][][] null; + +int program (int argc, string[] argv) { + str = new string[][][][][][][][][][1]{i1 -> + new string[][][][][][][][][1]{i2 -> + new string[][][][][][][][1]{i3 -> + new string[][][][][][][1]{i4 -> + new string[][][][][][1]{i5 -> + new string[][][][][1]{i6 -> + new string[][][][1]{i7 -> + new string[][][1]{i8 -> + new string[][1]{i9 -> + new string[1]{i10 -> "hello"}}}}}}}}}}; + + if?(string[][][][][][][][][][] x = str) { + print_string (x[0][0][0][0][0][0][0][0][0][0]); + } + return 0; +} + diff --git a/hw6/hw5programs/ssumit_balancedparens.oat b/hw6/hw5programs/ssumit_balancedparens.oat new file mode 100644 index 0000000..37a8971 --- /dev/null +++ b/hw6/hw5programs/ssumit_balancedparens.oat @@ -0,0 +1,104 @@ +struct Node { + int p; + Node next +} + +struct Stack { + int size; + Node head; + (Stack, int) -> Stack push; + (Stack) -> Stack pop; + (Stack) -> int peek +} + +Stack push(Stack stack, int paren) { + var n = new Node {p = paren; next = stack.head}; + return new Stack {size = stack.size + 1; head = n; push = stack.push; pop = stack.pop; peek = stack.peek}; +} + +Stack pop(Stack stack) { + if (stack.size == 0) { + return Stack null; + } + return new Stack{size = stack.size - 1; head = stack.head.next; push = stack.push; pop = stack.pop; peek = stack.peek}; +} + +int peek(Stack stack) { + if (stack.size == 0) { + return -1; + } + return stack.head.p; +} + +global leftParen = 40; +global leftBracket = 91; +global leftBrace = 123; +global rightParen = 41; +global rightBracket = 93; +global rightBrace = 125; + + +bool isStringBalanced(string input) { + var stack = new Stack {size = 0; head = Node null; push = push; pop = pop; peek = peek}; + var length = length_of_string(input); + var char_arr = array_of_string(input); + var result = new int[2*length]; + var ptr = 0; + for (var i = 0; i < length; i = i + 1;) { + var char = char_arr[i]; + if (char == leftParen | char == leftBracket | char == leftBrace) { + stack = stack.push(stack, char); + } else if (char == rightParen) { + var head = stack.peek(stack); + stack = stack.pop(stack); + if (head != leftParen) { + print_string("mismatch"); + return false; + } + result[ptr] = leftParen; + ptr = ptr + 1; + result[ptr] = rightParen; + ptr = ptr + 1; + } else if (char == rightBracket) { + var head = stack.peek(stack); + stack = stack.pop(stack); + if (head != leftBracket) { + print_string("mismatch"); + return false; + } + result[ptr] = leftBracket; + ptr = ptr + 1; + result[ptr] = rightBracket; + ptr = ptr + 1; + } else if (char == rightBrace) { + var head = stack.peek(stack); + stack = stack.pop(stack); + if (head != leftBrace) { + print_string("mismatch"); + return false; + } + result[ptr] = leftBrace; + ptr = ptr + 1; + result[ptr] = rightBrace; + ptr = ptr + 1; + } + } + if (stack.size != 0) { + print_string("mismatch"); + return false; + } + var finalString = new int[ptr]; + for (var i = 0; i < ptr; i = i + 1;) { + finalString[i] = result[i]; + } + print_string(string_of_array(finalString)); + return true; +} + +int program(int argc, string[] argv) { + var result = isStringBalanced(argv[1]); + if (result) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_array_err.oat b/hw6/hw5programs/tc_array_err.oat new file mode 100644 index 0000000..0b42c76 --- /dev/null +++ b/hw6/hw5programs/tc_array_err.oat @@ -0,0 +1,14 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +int f() { + var x = A[] null; + x = B[] null; + return 2; +} diff --git a/hw6/hw5programs/tc_arrow.oat b/hw6/hw5programs/tc_arrow.oat new file mode 100644 index 0000000..52183f9 --- /dev/null +++ b/hw6/hw5programs/tc_arrow.oat @@ -0,0 +1,15 @@ +int f((int) -> int g) { + return s(3); +} + +int s(int x) { + return x; +} + +int l(((int) -> int) -> int x) { + return 0; +} + +int main() { + return l(f); +} diff --git a/hw6/hw5programs/tc_arrow_null.oat b/hw6/hw5programs/tc_arrow_null.oat new file mode 100644 index 0000000..964b21e --- /dev/null +++ b/hw6/hw5programs/tc_arrow_null.oat @@ -0,0 +1,13 @@ +struct Point { + int x; + int y +} + +Point? f() { + return Point null; +} + +int g(() -> Point? x) { + return 0; +} + diff --git a/hw6/hw5programs/tc_arrow_null_rec.oat b/hw6/hw5programs/tc_arrow_null_rec.oat new file mode 100644 index 0000000..e566ef7 --- /dev/null +++ b/hw6/hw5programs/tc_arrow_null_rec.oat @@ -0,0 +1,17 @@ +struct Point { + int x; + int y +} + +Point? f() { + return Point null; +} + +Point? g(() -> Point? x) { + return x(); +} + +Point? h((() -> Point?) -> Point? x) { + return x(f); +} + diff --git a/hw6/hw5programs/tc_assn_err.oat b/hw6/hw5programs/tc_assn_err.oat new file mode 100644 index 0000000..3b8822a --- /dev/null +++ b/hw6/hw5programs/tc_assn_err.oat @@ -0,0 +1,9 @@ +int f() { + return 3; +} + +int bad() { + f() = 4; + return 0; +} + diff --git a/hw6/hw5programs/tc_correct_array.oat b/hw6/hw5programs/tc_correct_array.oat new file mode 100644 index 0000000..a57b14c --- /dev/null +++ b/hw6/hw5programs/tc_correct_array.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + var int_arr = new int[] {3, 4}; + var arr = new int[int_arr[2]]{i -> 0}; + return int_arr[0]; +} diff --git a/hw6/hw5programs/tc_correct_call.oat b/hw6/hw5programs/tc_correct_call.oat new file mode 100644 index 0000000..07f7399 --- /dev/null +++ b/hw6/hw5programs/tc_correct_call.oat @@ -0,0 +1,7 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int program(int argc, string[] argv) { + return add(3, 4); +} diff --git a/hw6/hw5programs/tc_correct_for.oat b/hw6/hw5programs/tc_correct_for.oat new file mode 100644 index 0000000..9ff1a4a --- /dev/null +++ b/hw6/hw5programs/tc_correct_for.oat @@ -0,0 +1,6 @@ +int program(int argc, string[] argv) { + for (var i = 0; i < 5; i = i + 1; ) { + return 0; + } + return 0; +} diff --git a/hw6/hw5programs/tc_correct_fptr.oat b/hw6/hw5programs/tc_correct_fptr.oat new file mode 100644 index 0000000..07f7399 --- /dev/null +++ b/hw6/hw5programs/tc_correct_fptr.oat @@ -0,0 +1,7 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int program(int argc, string[] argv) { + return add(3, 4); +} diff --git a/hw6/hw5programs/tc_correct_fptr_array.oat b/hw6/hw5programs/tc_correct_fptr_array.oat new file mode 100644 index 0000000..a846b82 --- /dev/null +++ b/hw6/hw5programs/tc_correct_fptr_array.oat @@ -0,0 +1,7 @@ +int add(int x, int y) { return x + y; } +int sub(int x, int y) { return x - y; } + +int program(int argc, string[] argv) { + var x = new ((int, int) -> int) [] { add, sub }; + return 0; +} diff --git a/hw6/hw5programs/tc_correct_function_shadow.oat b/hw6/hw5programs/tc_correct_function_shadow.oat new file mode 100644 index 0000000..1fc85e2 --- /dev/null +++ b/hw6/hw5programs/tc_correct_function_shadow.oat @@ -0,0 +1,12 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int mul(int arg1, int arg2) { + return arg1 * arg2; +} + +int program(int argc, string[] argv) { + var add = mul; + return add(3, 4); +} diff --git a/hw6/hw5programs/tc_correct_global.oat b/hw6/hw5programs/tc_correct_global.oat new file mode 100644 index 0000000..a405023 --- /dev/null +++ b/hw6/hw5programs/tc_correct_global.oat @@ -0,0 +1,11 @@ +int program(int argc, string[] argv) { + var x = array_of_string(""); + var y = string_of_array(x); + var z = length_of_string(y); + var a = string_of_int(3); + var b = string_cat("hello", "world"); + print_string(b); + print_int(3); + print_bool(true); + return z; +} diff --git a/hw6/hw5programs/tc_correct_if.oat b/hw6/hw5programs/tc_correct_if.oat new file mode 100644 index 0000000..502ab3d --- /dev/null +++ b/hw6/hw5programs/tc_correct_if.oat @@ -0,0 +1,7 @@ +int program(int argc, string[] argv) { + if (true) { + return 0; + } else { + return 1; + } +} diff --git a/hw6/hw5programs/tc_correct_local_redeclaration.oat b/hw6/hw5programs/tc_correct_local_redeclaration.oat new file mode 100644 index 0000000..97d977f --- /dev/null +++ b/hw6/hw5programs/tc_correct_local_redeclaration.oat @@ -0,0 +1,6 @@ +global x = 2; + +int program(int argc, string[] argv) { + var x = 2; + return x; +} diff --git a/hw6/hw5programs/tc_correct_null.oat b/hw6/hw5programs/tc_correct_null.oat new file mode 100644 index 0000000..65d9053 --- /dev/null +++ b/hw6/hw5programs/tc_correct_null.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] argv) { + var x = new (int[])[] { int[] null }; + return x[0][1]; +} diff --git a/hw6/hw5programs/tc_correct_struct.oat b/hw6/hw5programs/tc_correct_struct.oat new file mode 100644 index 0000000..6d3cba9 --- /dev/null +++ b/hw6/hw5programs/tc_correct_struct.oat @@ -0,0 +1,9 @@ +struct T { + int f1; + int f2 +} + +int program(int argc, string[] argv) { + var x = new T { f1 = 3; f2 = 4 }; + return x.f1; +} diff --git a/hw6/hw5programs/tc_correct_struct_fptr.oat b/hw6/hw5programs/tc_correct_struct_fptr.oat new file mode 100644 index 0000000..4319004 --- /dev/null +++ b/hw6/hw5programs/tc_correct_struct_fptr.oat @@ -0,0 +1,12 @@ +struct S { + int s; + int t; + (int, int) -> int f +} + +int add(int x, int y) { return x + y; } + +int program(int argc, string[] argv) { + var x = new S { s = 3; t = 4; f = add }; + return x.f(x.s, x.t); +} diff --git a/hw6/hw5programs/tc_correct_void.oat b/hw6/hw5programs/tc_correct_void.oat new file mode 100644 index 0000000..8b5139b --- /dev/null +++ b/hw6/hw5programs/tc_correct_void.oat @@ -0,0 +1,7 @@ +void f() { + return; +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw6/hw5programs/tc_correct_while.oat b/hw6/hw5programs/tc_correct_while.oat new file mode 100644 index 0000000..e370aef --- /dev/null +++ b/hw6/hw5programs/tc_correct_while.oat @@ -0,0 +1,6 @@ +int program(int argc, string[] argv) { + while (1 > 0) { + return 3; + } + return 0; +} diff --git a/hw6/hw5programs/tc_eq1.oat b/hw6/hw5programs/tc_eq1.oat new file mode 100644 index 0000000..8845b64 --- /dev/null +++ b/hw6/hw5programs/tc_eq1.oat @@ -0,0 +1,14 @@ +struct S {} +struct T {} + +int program(string[] args) { + var z = 0; + var s = new S{}; + var t = new T{}; + if (s == t) { + z = 17; + } else { + z = 3; + } + return z; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_eq2.oat b/hw6/hw5programs/tc_eq2.oat new file mode 100644 index 0000000..185ecfb --- /dev/null +++ b/hw6/hw5programs/tc_eq2.oat @@ -0,0 +1,14 @@ +struct S {int x; bool y} +struct T {int x; bool y} + +int program(string[] args) { + var z = 0; + var s = new S{x=3;y=true}; + var t = new T{x=3;y=true}; + if (s == t) { + z = 17; + } else { + z = 3; + } + return z; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_error_array1.oat b/hw6/hw5programs/tc_error_array1.oat new file mode 100644 index 0000000..3834bd2 --- /dev/null +++ b/hw6/hw5programs/tc_error_array1.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + var arr = new int[] {4, 5}; + arr[1] = true; + return arr[0]; +} diff --git a/hw6/hw5programs/tc_error_array2.oat b/hw6/hw5programs/tc_error_array2.oat new file mode 100644 index 0000000..22c2698 --- /dev/null +++ b/hw6/hw5programs/tc_error_array2.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + var arr2 = new bool[] { true, false }; + var arr = new int[arr2[0]]{i -> 0}; + return arr[0]; +} diff --git a/hw6/hw5programs/tc_error_assign_void.oat b/hw6/hw5programs/tc_error_assign_void.oat new file mode 100644 index 0000000..b838be0 --- /dev/null +++ b/hw6/hw5programs/tc_error_assign_void.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] argv) { + var x = print_int(3); + return 0; +} diff --git a/hw6/hw5programs/tc_error_binop1.oat b/hw6/hw5programs/tc_error_binop1.oat new file mode 100644 index 0000000..3ef0178 --- /dev/null +++ b/hw6/hw5programs/tc_error_binop1.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return 1 + true; +} diff --git a/hw6/hw5programs/tc_error_binop2.oat b/hw6/hw5programs/tc_error_binop2.oat new file mode 100644 index 0000000..f557307 --- /dev/null +++ b/hw6/hw5programs/tc_error_binop2.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return true | 3; +} diff --git a/hw6/hw5programs/tc_error_binop3.oat b/hw6/hw5programs/tc_error_binop3.oat new file mode 100644 index 0000000..47d57c5 --- /dev/null +++ b/hw6/hw5programs/tc_error_binop3.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return 1 [|] true; +} diff --git a/hw6/hw5programs/tc_error_call1.oat b/hw6/hw5programs/tc_error_call1.oat new file mode 100644 index 0000000..af3ce19 --- /dev/null +++ b/hw6/hw5programs/tc_error_call1.oat @@ -0,0 +1,7 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int program(int argc, string[] argv) { + return add(3, 4, 5); +} diff --git a/hw6/hw5programs/tc_error_call2.oat b/hw6/hw5programs/tc_error_call2.oat new file mode 100644 index 0000000..631b0cf --- /dev/null +++ b/hw6/hw5programs/tc_error_call2.oat @@ -0,0 +1,7 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +int program(int argc, string[] argv) { + return add(3, false); +} diff --git a/hw6/hw5programs/tc_error_dupstruct.oat b/hw6/hw5programs/tc_error_dupstruct.oat new file mode 100644 index 0000000..be05de2 --- /dev/null +++ b/hw6/hw5programs/tc_error_dupstruct.oat @@ -0,0 +1,11 @@ +struct L { + bool b +} + +struct L { + int c +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw6/hw5programs/tc_error_early_return.oat b/hw6/hw5programs/tc_error_early_return.oat new file mode 100644 index 0000000..7f5252e --- /dev/null +++ b/hw6/hw5programs/tc_error_early_return.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + return 3; + var x = 5; + return 4; +} diff --git a/hw6/hw5programs/tc_error_early_return_void.oat b/hw6/hw5programs/tc_error_early_return_void.oat new file mode 100644 index 0000000..c378553 --- /dev/null +++ b/hw6/hw5programs/tc_error_early_return_void.oat @@ -0,0 +1,9 @@ +void f() { + return; + var x = 5; + return; +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw6/hw5programs/tc_error_for.oat b/hw6/hw5programs/tc_error_for.oat new file mode 100644 index 0000000..0a05986 --- /dev/null +++ b/hw6/hw5programs/tc_error_for.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + for (var i = 0; i < 5; i = i + 1; ) { + return 0; + } +} diff --git a/hw6/hw5programs/tc_error_func_assign.oat b/hw6/hw5programs/tc_error_func_assign.oat new file mode 100644 index 0000000..904384f --- /dev/null +++ b/hw6/hw5programs/tc_error_func_assign.oat @@ -0,0 +1,12 @@ +int f() { + return 0; +} + +int g() { + return 1; +} + +int program(string[] args) { + f = g; + return 0; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_error_func_redeclaration.oat b/hw6/hw5programs/tc_error_func_redeclaration.oat new file mode 100644 index 0000000..610cedc --- /dev/null +++ b/hw6/hw5programs/tc_error_func_redeclaration.oat @@ -0,0 +1,11 @@ +int id(int x) { + return x; +} + +bool id (bool b) { + return b; +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw6/hw5programs/tc_error_function_no_shadow.oat b/hw6/hw5programs/tc_error_function_no_shadow.oat new file mode 100644 index 0000000..b6b00a3 --- /dev/null +++ b/hw6/hw5programs/tc_error_function_no_shadow.oat @@ -0,0 +1,12 @@ +int add(int arg1, int arg2) { + return arg1 + arg2; +} + +bool foo(int arg2) { + return true; +} + +int program(int argc, string[] argv) { + var add = foo; + return add(3, 4); +} diff --git a/hw6/hw5programs/tc_error_global.oat b/hw6/hw5programs/tc_error_global.oat new file mode 100644 index 0000000..fef5639 --- /dev/null +++ b/hw6/hw5programs/tc_error_global.oat @@ -0,0 +1,7 @@ +global x = 3; + +int program(int argc, string[] argv) { + var y = new bool[] { true }; + y[0] = x; + return y; +} diff --git a/hw6/hw5programs/tc_error_global_dup.oat b/hw6/hw5programs/tc_error_global_dup.oat new file mode 100644 index 0000000..bd3218a --- /dev/null +++ b/hw6/hw5programs/tc_error_global_dup.oat @@ -0,0 +1,6 @@ +global x = 3; +global x = 4; + +int program(int argc, string[] argv) { + return x; +} diff --git a/hw6/hw5programs/tc_error_global_fptr_scope.oat b/hw6/hw5programs/tc_error_global_fptr_scope.oat new file mode 100644 index 0000000..d17d869 --- /dev/null +++ b/hw6/hw5programs/tc_error_global_fptr_scope.oat @@ -0,0 +1,10 @@ +int f(int x, int y) { + return x + y; +} + +global x = f; +global y = x; + +int program(int argc, string[] argv) { + return y(3,4); +} diff --git a/hw6/hw5programs/tc_error_if.oat b/hw6/hw5programs/tc_error_if.oat new file mode 100644 index 0000000..f18348a --- /dev/null +++ b/hw6/hw5programs/tc_error_if.oat @@ -0,0 +1,7 @@ +int program(int argc, string[] argv) { + if (true) { + return 0; + } else { + var x = 3; + } +} diff --git a/hw6/hw5programs/tc_error_if_nonbool.oat b/hw6/hw5programs/tc_error_if_nonbool.oat new file mode 100644 index 0000000..3ef1347 --- /dev/null +++ b/hw6/hw5programs/tc_error_if_nonbool.oat @@ -0,0 +1,6 @@ +int program(int argc, string[] argv) { + if (3) { + } else { + } + return 0; +} diff --git a/hw6/hw5programs/tc_error_null.oat b/hw6/hw5programs/tc_error_null.oat new file mode 100644 index 0000000..1ebb883 --- /dev/null +++ b/hw6/hw5programs/tc_error_null.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] argv) { + var x = new (int[])[] { string[] null }; + return x[0][1]; +} diff --git a/hw6/hw5programs/tc_error_overwrite.oat b/hw6/hw5programs/tc_error_overwrite.oat new file mode 100644 index 0000000..bafb6aa --- /dev/null +++ b/hw6/hw5programs/tc_error_overwrite.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + var x = true; + var x = 3; + return x; +} diff --git a/hw6/hw5programs/tc_error_return_wrong.oat b/hw6/hw5programs/tc_error_return_wrong.oat new file mode 100644 index 0000000..572fd92 --- /dev/null +++ b/hw6/hw5programs/tc_error_return_wrong.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return true; +} diff --git a/hw6/hw5programs/tc_error_scall_nonvoid.oat b/hw6/hw5programs/tc_error_scall_nonvoid.oat new file mode 100644 index 0000000..27aa76a --- /dev/null +++ b/hw6/hw5programs/tc_error_scall_nonvoid.oat @@ -0,0 +1,9 @@ +int print(int x) { + print_int(x); + return x; +} + +int program(int argc, string[] argv) { + print(argc); + return 0; +} diff --git a/hw6/hw5programs/tc_error_struct.oat b/hw6/hw5programs/tc_error_struct.oat new file mode 100644 index 0000000..739d792 --- /dev/null +++ b/hw6/hw5programs/tc_error_struct.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int[] program(int argc, string[] argv) { + var x = new S { f1 = true; f2 = 3 }; + return x.f1; +} diff --git a/hw6/hw5programs/tc_error_struct1.oat b/hw6/hw5programs/tc_error_struct1.oat new file mode 100644 index 0000000..739d792 --- /dev/null +++ b/hw6/hw5programs/tc_error_struct1.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int[] program(int argc, string[] argv) { + var x = new S { f1 = true; f2 = 3 }; + return x.f1; +} diff --git a/hw6/hw5programs/tc_error_struct2.oat b/hw6/hw5programs/tc_error_struct2.oat new file mode 100644 index 0000000..5439677 --- /dev/null +++ b/hw6/hw5programs/tc_error_struct2.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int program(int argc, string[] argv) { + var x = new S { f1 = 4; f2 = 3; f3 = 4 }; + return x.f1; +} diff --git a/hw6/hw5programs/tc_error_struct3.oat b/hw6/hw5programs/tc_error_struct3.oat new file mode 100644 index 0000000..0bb9230 --- /dev/null +++ b/hw6/hw5programs/tc_error_struct3.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int program(int argc, string[] argv) { + var x = new S { f1 = 4; f2 = 3; f1 = 4 }; + return x.f1; +} diff --git a/hw6/hw5programs/tc_error_struct4.oat b/hw6/hw5programs/tc_error_struct4.oat new file mode 100644 index 0000000..f9d38c3 --- /dev/null +++ b/hw6/hw5programs/tc_error_struct4.oat @@ -0,0 +1,9 @@ +struct S { + int f1; + int f2 +} + +int program(int argc, string[] argv) { + var x = new S { f1 = 4 }; + return x.f1; +} diff --git a/hw6/hw5programs/tc_error_struct_dup.oat b/hw6/hw5programs/tc_error_struct_dup.oat new file mode 100644 index 0000000..ebd5a8f --- /dev/null +++ b/hw6/hw5programs/tc_error_struct_dup.oat @@ -0,0 +1,8 @@ +struct X { + int y; + int y +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw6/hw5programs/tc_error_struct_proj.oat b/hw6/hw5programs/tc_error_struct_proj.oat new file mode 100644 index 0000000..f1fe1d9 --- /dev/null +++ b/hw6/hw5programs/tc_error_struct_proj.oat @@ -0,0 +1,12 @@ +struct T { + int f +} + +struct G { + int g +} + +int program(int argc, string[] argv) { + var x = new T { f = 3 }; + return x.g; +} diff --git a/hw6/hw5programs/tc_error_struct_unbound.oat b/hw6/hw5programs/tc_error_struct_unbound.oat new file mode 100644 index 0000000..4d545f3 --- /dev/null +++ b/hw6/hw5programs/tc_error_struct_unbound.oat @@ -0,0 +1,8 @@ +struct T { + S name; + int x +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw6/hw5programs/tc_error_unop1.oat b/hw6/hw5programs/tc_error_unop1.oat new file mode 100644 index 0000000..47846cb --- /dev/null +++ b/hw6/hw5programs/tc_error_unop1.oat @@ -0,0 +1,3 @@ +int program(int argc, string[] argv) { + return !3; +} diff --git a/hw6/hw5programs/tc_error_void.oat b/hw6/hw5programs/tc_error_void.oat new file mode 100644 index 0000000..fac8c61 --- /dev/null +++ b/hw6/hw5programs/tc_error_void.oat @@ -0,0 +1,7 @@ +void f() { + return 3; +} + +int program(int argc, string[] argv) { + return 0; +} diff --git a/hw6/hw5programs/tc_error_while.oat b/hw6/hw5programs/tc_error_while.oat new file mode 100644 index 0000000..0e20ddd --- /dev/null +++ b/hw6/hw5programs/tc_error_while.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + while (1 > 0) { + return 3; + } +} diff --git a/hw6/hw5programs/tc_error_while_nonbool.oat b/hw6/hw5programs/tc_error_while_nonbool.oat new file mode 100644 index 0000000..310063b --- /dev/null +++ b/hw6/hw5programs/tc_error_while_nonbool.oat @@ -0,0 +1,5 @@ +int program(int argc, string[] argv) { + while (3) { + } + return 0; +} diff --git a/hw6/hw5programs/tc_func_arg_err.oat b/hw6/hw5programs/tc_func_arg_err.oat new file mode 100644 index 0000000..ac00f9a --- /dev/null +++ b/hw6/hw5programs/tc_func_arg_err.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +int f(A x) { + return 3; +} + +int g(B x) { + return 3; +} + +int l() { + var x = f; + x = g; + return 3; +} + diff --git a/hw6/hw5programs/tc_func_arg_ok.oat b/hw6/hw5programs/tc_func_arg_ok.oat new file mode 100644 index 0000000..7dbf401 --- /dev/null +++ b/hw6/hw5programs/tc_func_arg_ok.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +int f(A x) { + return 3; +} + +int g(B x) { + return 3; +} + +int l() { + var x = g; + x = f; + return 3; +} + diff --git a/hw6/hw5programs/tc_func_ret_err.oat b/hw6/hw5programs/tc_func_ret_err.oat new file mode 100644 index 0000000..700fb30 --- /dev/null +++ b/hw6/hw5programs/tc_func_ret_err.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +A f() { + return new A {x = 3}; +} + +B g() { + return new B {x = 3; y = 4}; +} + +int l() { + var x = g; + x = f; + return 3; +} + diff --git a/hw6/hw5programs/tc_func_ret_ok.oat b/hw6/hw5programs/tc_func_ret_ok.oat new file mode 100644 index 0000000..daac258 --- /dev/null +++ b/hw6/hw5programs/tc_func_ret_ok.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +A f() { + return new A {x = 3}; +} + +B g() { + return new B {x = 3; y = 4}; +} + +int l() { + var x = f; + x = g; + return 3; +} + diff --git a/hw6/hw5programs/tc_ifq1.oat b/hw6/hw5programs/tc_ifq1.oat new file mode 100644 index 0000000..d242770 --- /dev/null +++ b/hw6/hw5programs/tc_ifq1.oat @@ -0,0 +1,17 @@ +int sum(int[]? arr) { + var acc = 0; + if? (int[] a = arr) { + for(var i = 0; i < length(a); i = i+1;) { + acc = acc + a[i]; + } + } + return acc; +} + + +int program (int argc, string[] argv) { + var a1 = new int[]{1, 2, 3, 4}; + var a2 = int[] null; + var x = sum(a1) + sum(a2); + return x; +} diff --git a/hw6/hw5programs/tc_ifq_err1.oat b/hw6/hw5programs/tc_ifq_err1.oat new file mode 100644 index 0000000..5ce5716 --- /dev/null +++ b/hw6/hw5programs/tc_ifq_err1.oat @@ -0,0 +1,17 @@ +struct T { int x } +struct S { int x; int y } + +int sum(T? t) { + if?(S s = t) { + return s.y; + } else { + return 0; + } +} + +int program (int argc, string[] argv) { + var x = 0; + x = x + sum(S null); + x = x + sum(new S{x=4; y=5}); + return x; +} diff --git a/hw6/hw5programs/tc_null_array_err.oat b/hw6/hw5programs/tc_null_array_err.oat new file mode 100644 index 0000000..7318c5c --- /dev/null +++ b/hw6/hw5programs/tc_null_array_err.oat @@ -0,0 +1,5 @@ +int f() { + var x = int[] null; + x = new int[] {3,4}; + return x[0]; +} diff --git a/hw6/hw5programs/tc_recursive_struct_err.oat b/hw6/hw5programs/tc_recursive_struct_err.oat new file mode 100644 index 0000000..a0f0b3a --- /dev/null +++ b/hw6/hw5programs/tc_recursive_struct_err.oat @@ -0,0 +1,12 @@ +struct A{ + B x +} + +struct B { + A x +} + +void f() { + var x = A null; + x = B null; +} diff --git a/hw6/hw5programs/tc_struct_bad.oat b/hw6/hw5programs/tc_struct_bad.oat new file mode 100644 index 0000000..67e4170 --- /dev/null +++ b/hw6/hw5programs/tc_struct_bad.oat @@ -0,0 +1,4 @@ +void foo() { + var x = new S[]{S null}; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_struct_err.oat b/hw6/hw5programs/tc_struct_err.oat new file mode 100644 index 0000000..ffd69ac --- /dev/null +++ b/hw6/hw5programs/tc_struct_err.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +A f() { + return new A {x = 3}; +} + +B g() { + return new B {x = 3; y = 4}; +} + +int l() { + var x = g(); + x = f(); + return 3; +} + diff --git a/hw6/hw5programs/tc_struct_field_err.oat b/hw6/hw5programs/tc_struct_field_err.oat new file mode 100644 index 0000000..bd97c45 --- /dev/null +++ b/hw6/hw5programs/tc_struct_field_err.oat @@ -0,0 +1,22 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +struct C { + A x +} + +struct D { + B x +} + +int f() { + var x = C null; + x = D null; + return 2; +} diff --git a/hw6/hw5programs/tc_struct_ok.oat b/hw6/hw5programs/tc_struct_ok.oat new file mode 100644 index 0000000..b0e155f --- /dev/null +++ b/hw6/hw5programs/tc_struct_ok.oat @@ -0,0 +1,23 @@ +struct A { + int x +} + +struct B { + int x; + int y +} + +A f() { + return new A {x = 3}; +} + +B g() { + return new B {x = 3; y = 4}; +} + +int l() { + var x = f(); + x = g(); + return 3; +} + diff --git a/hw6/hw5programs/tc_subtyping1.oat b/hw6/hw5programs/tc_subtyping1.oat new file mode 100644 index 0000000..d09a965 --- /dev/null +++ b/hw6/hw5programs/tc_subtyping1.oat @@ -0,0 +1,4 @@ +void f(int[] x, int[]? y) { + y = x; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping2.oat b/hw6/hw5programs/tc_subtyping2.oat new file mode 100644 index 0000000..7187dc1 --- /dev/null +++ b/hw6/hw5programs/tc_subtyping2.oat @@ -0,0 +1,7 @@ +struct A {} +struct B { int x } + +void foo(A a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping3.oat b/hw6/hw5programs/tc_subtyping3.oat new file mode 100644 index 0000000..e2b3c7a --- /dev/null +++ b/hw6/hw5programs/tc_subtyping3.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int x ; int y } + +void foo(A a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping4.oat b/hw6/hw5programs/tc_subtyping4.oat new file mode 100644 index 0000000..59dcd7e --- /dev/null +++ b/hw6/hw5programs/tc_subtyping4.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int x ; int y } + +void foo(A? a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping5.oat b/hw6/hw5programs/tc_subtyping5.oat new file mode 100644 index 0000000..cd0d57e --- /dev/null +++ b/hw6/hw5programs/tc_subtyping5.oat @@ -0,0 +1,11 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y } + +void foo(A a, B b, C c) { + a = b; + a = c; + b = c; + c = b; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping6.oat b/hw6/hw5programs/tc_subtyping6.oat new file mode 100644 index 0000000..aca5f5b --- /dev/null +++ b/hw6/hw5programs/tc_subtyping6.oat @@ -0,0 +1,6 @@ +struct A { int x } +struct B { int x ; int y } + +A f(B b) { + return b; +} diff --git a/hw6/hw5programs/tc_subtyping7.oat b/hw6/hw5programs/tc_subtyping7.oat new file mode 100644 index 0000000..596821b --- /dev/null +++ b/hw6/hw5programs/tc_subtyping7.oat @@ -0,0 +1,20 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y ; int z } + +/* C <: B B <: B */ +/* ---------------------- */ +/* (B) -> B <: (C) -> B */ +B f(B b) { + return b; +} + +B g((C) -> B f) { + var c = new C {x = 1; y = 2; z = 3}; + return f(c); +} + +int program(string[] args) { + var b = g(f); + return b.y; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping8.oat b/hw6/hw5programs/tc_subtyping8.oat new file mode 100644 index 0000000..8813494 --- /dev/null +++ b/hw6/hw5programs/tc_subtyping8.oat @@ -0,0 +1,19 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y ; int z } + +/* C <: B B <: B */ +/* ---------------------- */ +/* (B) -> B <: (C) -> B */ +B f(B b) { + return b; +} + +void g((C) -> B f) { + return; +} + +int program(string[] args) { + g(f); + return 0; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping9.oat b/hw6/hw5programs/tc_subtyping9.oat new file mode 100644 index 0000000..2091e53 --- /dev/null +++ b/hw6/hw5programs/tc_subtyping9.oat @@ -0,0 +1,19 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y ; int z } + +/* C <: B B <: B */ +/* ---------------------- */ +/* (B) -> B <: (C) -> B */ +B? f(B b) { + return b; +} + +void g((C) -> B? f) { + return; +} + +int program(string[] args) { + g(f); + return 0; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping_err1.oat b/hw6/hw5programs/tc_subtyping_err1.oat new file mode 100644 index 0000000..1f61ddd --- /dev/null +++ b/hw6/hw5programs/tc_subtyping_err1.oat @@ -0,0 +1,4 @@ +void f(int[] x, int[]? y) { + x = y; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping_err2.oat b/hw6/hw5programs/tc_subtyping_err2.oat new file mode 100644 index 0000000..c6f0f62 --- /dev/null +++ b/hw6/hw5programs/tc_subtyping_err2.oat @@ -0,0 +1,7 @@ +struct A {} +struct B { int x } + +void foo(A a, B b) { + b = a; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping_err3.oat b/hw6/hw5programs/tc_subtyping_err3.oat new file mode 100644 index 0000000..b090f8d --- /dev/null +++ b/hw6/hw5programs/tc_subtyping_err3.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int x ; int y } + +void foo(A a, B b) { + b = a; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping_err4.oat b/hw6/hw5programs/tc_subtyping_err4.oat new file mode 100644 index 0000000..d77b766 --- /dev/null +++ b/hw6/hw5programs/tc_subtyping_err4.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int x ; int y } + +void foo(A? a, B b) { + b = a; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping_err5.oat b/hw6/hw5programs/tc_subtyping_err5.oat new file mode 100644 index 0000000..582b3c2 --- /dev/null +++ b/hw6/hw5programs/tc_subtyping_err5.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { bool x ; int y } + +void foo(A a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping_err6.oat b/hw6/hw5programs/tc_subtyping_err6.oat new file mode 100644 index 0000000..3dc023d --- /dev/null +++ b/hw6/hw5programs/tc_subtyping_err6.oat @@ -0,0 +1,7 @@ +struct A { int x } +struct B { int y } + +void foo(A a, B b) { + a = b; + return; +} \ No newline at end of file diff --git a/hw6/hw5programs/tc_subtyping_err7.oat b/hw6/hw5programs/tc_subtyping_err7.oat new file mode 100644 index 0000000..afb5731 --- /dev/null +++ b/hw6/hw5programs/tc_subtyping_err7.oat @@ -0,0 +1,6 @@ +struct A { int x } +struct B { int x ; int y } + +B f(A a) { + return a; +} diff --git a/hw6/hw5programs/tc_subtyping_err8.oat b/hw6/hw5programs/tc_subtyping_err8.oat new file mode 100644 index 0000000..7b16b9c --- /dev/null +++ b/hw6/hw5programs/tc_subtyping_err8.oat @@ -0,0 +1,19 @@ +struct A { int x } +struct B { int x ; int y } +struct C { int x ; int y ; int z } + +/* C <: B B <: B */ +/* ---------------------- */ +/* (B) -> B <: (C) -> B */ +B? f(B b) { + return b; +} + +void g((C) -> B f) { + return; +} + +int program(string[] args) { + g(f); + return 0; +} \ No newline at end of file diff --git a/hw6/hw5programs/whartonv_calculator.oat b/hw6/hw5programs/whartonv_calculator.oat new file mode 100644 index 0000000..8ceba15 --- /dev/null +++ b/hw6/hw5programs/whartonv_calculator.oat @@ -0,0 +1,149 @@ +struct Node { + int val; + Node next +} + +struct Stack { + Node head; + int size +} + +struct Calculator { + (Stack) -> void add; + (Stack) -> void sub; + (Stack) -> void mul +} + +/* Stack operations */ +Stack new_stack() { + return new Stack { head = Node null; size = 0 }; +} + +int peek_stack(Stack s) { + if (s.size == 0) { + return -1; + } + return s.head.val; +} + +int pop_stack(Stack s) { + if (s.size == 0) { + return -1; + } + var top = s.head.val; + s.head = s.head.next; + s.size = s.size - 1; + return top; +} + +void push_stack(Stack s, int v) { + var node = new Node { val = v; next = s.head }; + s.head = node; + s.size = s.size - 1; + return; +} + +int get_val(int i) { + /* turns a char_code i into a value v */ + return i - 48; +} + +/* Calculator operations */ +void calc_binop(Stack s, (int, int) -> int op) { + var x1 = pop_stack(s); + var x2 = pop_stack(s); + var val = op(x1, x2); + push_stack(s, val); + return; +} + +int add_op(int v1, int v2) { + return v1 + v2; +} + +int sub_op(int v1, int v2) { + return v1 - v2; +} + +int mul_op(int v1, int v2) { + return v1 * v2; +} + +void calc_add(Stack s) { + calc_binop(s, add_op); + return; +} + +void calc_sub(Stack s) { + calc_binop(s, sub_op); + return; +} + +void calc_mul(Stack s) { + calc_binop(s, mul_op); + return; +} + +Calculator new_calculator() { + return new Calculator { add = calc_add; sub = calc_sub; mul = calc_mul }; +} + +/* String manipulation */ +int int_of_string(string s) { + var arr = array_of_string(s); + var len = length_of_string(s); + + var sum = 0; + for(var i = 0; i < len; i = i + 1;) { + sum = sum * 10; + var val = get_val(arr[i]); + sum = sum + val; + } + + return sum; +} + +/* Main program */ +int program (int argc, string[] argv) { + /* A stack-based reverse Polish notation calculator. Feed in input numbers */ + /* and operands + (addition), - (subtraction), and x (multiplication) to */ + /* calculate result. */ + + var str = "\n"; + + var stack = new_stack(); + var calculator = new_calculator(); + + for(var i = 1; i < argc; i = i + 1;) { + var current_item = argv[i]; + + var did_op = false; + + var len = length_of_string(current_item); + if (len == 1) { + var arr = array_of_string(current_item); + did_op = true; + if (arr[0] == 43) { + /* plus op */ + calculator.add(stack); + } else if (arr[0] == 45) { + /* minus op */ + calculator.sub(stack); + } else if (arr[0] == 120) { + /* times op */ + calculator.mul(stack); + } else { + did_op = false; + } + } + + if (!did_op) { + /* didn't do op! we have a number maybe */ + var v = int_of_string(current_item); + push_stack(stack, v); + } + } + + print_int(peek_stack(stack)); + return peek_stack(stack); +} diff --git a/hw6/hw5programs/yingjiao_floydwarshall.oat b/hw6/hw5programs/yingjiao_floydwarshall.oat new file mode 100644 index 0000000..dd78806 --- /dev/null +++ b/hw6/hw5programs/yingjiao_floydwarshall.oat @@ -0,0 +1,102 @@ +struct Edge { + int weight; + int source; + int target; + Edge next; + bool hasNext +} + +int min(int x, int y) { + if (x < y) { + return x; + } else { + return y; + } +} + +int maximum(int x, int y) { + if (x < y | x == 5000) { + return y; + } else { + return x; + } +} + +int program(int argc, string[] argv) { + var n = 10; + var arr = new int[][10]; + + for (var i = 0; i < 10; i = i + 1;) { + arr[i] = new int[10]; + for (var j = 0; j < 10; j = j + 1;) { + if (i == j) { + arr[i][j] = 0; + } else { + arr[i][j] = 5000; + } + } + } + + var e0 = new Edge {weight = 4; source = 1; target = 2; next = Edge null; hasNext = false}; + var e1 = new Edge {weight = 3; source = 2; target = 0; next = e0; hasNext = true}; + var e2 = new Edge {weight = 4; source = 8; target = 5; next = e1; hasNext = true}; + var e3 = new Edge {weight = 1; source = 5; target = 7; next = e2; hasNext = true}; + var e4 = new Edge {weight = 2; source = 3; target = 1; next = e3; hasNext = true}; + var e5 = new Edge {weight = 3; source = 5; target = 4; next = e4; hasNext = true}; + var e6 = new Edge {weight = 7; source = 2; target = 1; next = e5; hasNext = true}; + var e7 = new Edge {weight = 5; source = 3; target = 8; next = e6; hasNext = true}; + var e8 = new Edge {weight = 8; source = 9; target = 4; next = e7; hasNext = true}; + var e9 = new Edge {weight = 3; source = 2; target = 7; next = e8; hasNext = true}; + var e10 = new Edge {weight = 3; source = 0; target = 2; next = e9; hasNext = true}; + var e11 = new Edge {weight = 0; source = 0; target = 3; next = e10; hasNext = true}; + var e12 = new Edge {weight = 4; source = 3; target = 2; next = e11; hasNext = true}; + var e13 = new Edge {weight = 2; source = 1; target = 8; next = e12; hasNext = true}; + var e14 = new Edge {weight = 7; source = 5; target = 1; next = e13; hasNext = true}; + + + var e = e14; + while(e.hasNext) { + arr[e.source][e.target] = e.weight; + e = e.next; + } + arr[e.source][e.target] = e.weight; + + /* + arr[1][2] = 4; + arr[2][0] = 3; + arr[8][5] = 4; + arr[5][7] = 1; + arr[3][1] = 2; + arr[5][4] = 3; + arr[2][1] = 7; + arr[3][8] = 5; + arr[9][4] = 8; + arr[2][7] = 3; + arr[0][2] = 3; + arr[0][3] = 0; + arr[3][2] = 4; + arr[1][8] = 2; + arr[5][1] = 7; + */ + + + for (var k = 0; k < n; k = k + 1;) { + for (var i = 0; i < n; i = i + 1;) { + for (var j = 0; j < n; j = j + 1;) { + arr[i][j] = min(arr[i][k] + arr[k][j], arr[i][j]); + } + } + } + + + var max = 0; + for (var i = 0; i < 10; i = i + 1;) { + for (var j = 0; j < 10; j = j + 1;) { + max = maximum(arr[i][j], max); + } + } + + return max; +} + + diff --git a/hw6/lexer.mll b/hw6/lexer.mll new file mode 100644 index 0000000..252617e --- /dev/null +++ b/hw6/lexer.mll @@ -0,0 +1,227 @@ +{ + open Lexing + open Parser + open Range + + exception Lexer_error of Range.t * string + + let reset_lexbuf (filename:string) (lnum:int) lexbuf : unit = + lexbuf.lex_curr_p <- { + pos_fname = filename; + pos_cnum = 0; + pos_bol = 0; + pos_lnum = lnum; + } + + let newline lexbuf = + lexbuf.lex_curr_p <- { (lexeme_end_p lexbuf) with + pos_lnum = (lexeme_end_p lexbuf).pos_lnum + 1; + pos_bol = (lexeme_end lexbuf) } + + (* Boilerplate to define exceptional cases in the lexer. *) + let unexpected_char lexbuf (c:char) : 'a = + raise (Lexer_error (Range.lex_range lexbuf, + Printf.sprintf "Unexpected character: '%c'" c)) + + (* Lexing reserved words *) + let reserved_words = [ + (* Keywords *) + ("struct", STRUCT); + ("null", NULL); + ("void", TVOID); + ("int", TINT); + ("string", TSTRING); + ("else", ELSE); + ("if", IF); + ("if?", IFQ); + ("while", WHILE); + ("return", RETURN); + ("var", VAR); + ("global", GLOBAL); + ("length", LENGTH); + + (* Symbols *) + ( ".", DOT); + ( ";", SEMI); + ( ",", COMMA); + ( "{", LBRACE); + ( "}", RBRACE); + ( "+", PLUS); + ( "-", DASH); + ( "*", STAR); + ( "=", EQ); + ( "==", EQEQ); + ( "!", BANG); + ( "~", TILDE); + ( "(", LPAREN); + ( ")", RPAREN); + ( "[", LBRACKET); + ( "]", RBRACKET); + ("for", FOR); + ("new", NEW); + ("true", TRUE); + ("false", FALSE); + ("bool", TBOOL); + ( "<<", LTLT); + ( ">>", GTGT); + ( ">>>", GTGTGT); + ( "!=", BANGEQ); + ( "<", LT); + ( "<=", LTEQ); + ( ">", GT); + ( ">=", GTEQ); + ( "&", AMPER); + ( "|", BAR); + ( "[&]", IAND); + ( "[|]", IOR); + ( "->", ARROW); + ( "?", QUESTION); + ] + +let (symbol_table : (string, Parser.token) Hashtbl.t) = Hashtbl.create 1024 + let _ = + List.iter (fun (str,t) -> Hashtbl.add symbol_table str t) reserved_words + + let create_token lexbuf = + let str = lexeme lexbuf in + try (Hashtbl.find symbol_table str) + with _ -> IDENT str + + let create_uident lexbuf = UIDENT (lexeme lexbuf) + + (* Lexing comments and strings *) + let string_buffer = ref (Bytes.create 2048) + let string_end = ref 0 + let start_lex = ref (Range.start_of_range Range.norange) + + let start_pos_of_lexbuf lexbuf : pos = + (Range.pos_of_lexpos (lexeme_start_p lexbuf)) + + let lex_long_range lexbuf : Range.t = + let end_p = lexeme_end_p lexbuf in + mk_range end_p.pos_fname (!start_lex) (pos_of_lexpos end_p) + + let reset_str () = string_end := 0 + + let add_str ch = + let x = !string_end in + let buffer = !string_buffer + in + if x = Bytes.length buffer then + begin + let new_buffer = Bytes.create (x*2) in + Bytes.blit buffer 0 new_buffer 0 x; + Bytes.set new_buffer x ch; + string_buffer := new_buffer; + string_end := x+1 + end + else + begin + Bytes.set buffer x ch; + string_end := x+1 + end + + let get_str () = Bytes.sub_string (!string_buffer) 0 (!string_end) + + (* Lexing directives *) + let lnum = ref 1 +} + +(* Declare your aliases (let foo = regex) and rules here. *) +let newline = '\n' | ('\r' '\n') | '\r' +let lowercase = ['a'-'z'] +let uppercase = ['A'-'Z'] +let character = uppercase | lowercase +let whitespace = ['\t' ' '] +let digit = ['0'-'9'] +let hexdigit = ['0'-'9'] | ['a'-'f'] | ['A'-'F'] + +rule token = parse + | eof { EOF } + + | "/*" { start_lex := start_pos_of_lexbuf lexbuf; comments 0 lexbuf } + | '"' { reset_str(); start_lex := start_pos_of_lexbuf lexbuf; string false lexbuf } + | '#' { let p = lexeme_start_p lexbuf in + if p.pos_cnum - p.pos_bol = 0 then directive 0 lexbuf + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "# can only be the 1st char in a line.")) } + + | lowercase (digit | character | '_')* { create_token lexbuf } + | uppercase (digit | character | '_')* { create_uident lexbuf } + | digit+ | "0x" hexdigit+ { INT (Int64.of_string (lexeme lexbuf)) } + | whitespace+ { token lexbuf } + | newline { newline lexbuf; token lexbuf } + + | ';' | ',' | '{' | '}' | '+' | '-' | '*' | '=' | "==" + | "!=" | '!' | '~' | '(' | ')' | '[' | ']' + | '<' | "<=" | '>' | ">=" | "=>" | '&' | '|' | '.' | "->" + | "[|]" | "[&]" | "<<" | ">>" | ">>>" | "?" | "if?" + { create_token lexbuf } + + | _ as c { unexpected_char lexbuf c } + +and directive state = parse + | whitespace+ { directive state lexbuf } + | digit+ { if state = 0 then + (lnum := int_of_string (lexeme lexbuf); + directive 1 lexbuf) + else if state = 2 then directive 3 lexbuf + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + | '"' { if state = 1 then + begin + reset_str(); + start_lex := start_pos_of_lexbuf lexbuf; + string true lexbuf + end + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) + } + | newline { if state = 2 || state = 3 then + begin + reset_lexbuf (get_str()) !lnum lexbuf; + token lexbuf + end + else raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + | _ { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "Illegal directives")) } + +and comments level = parse + | "*/" { if level = 0 then token lexbuf + else comments (level-1) lexbuf } + | "/*" { comments (level+1) lexbuf} + | [^ '\n'] { comments level lexbuf } + | "\n" { newline lexbuf; comments level lexbuf } + | eof { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "comments are not closed")) } + +and string in_directive = parse + | '"' { if in_directive = false then + STRING (get_str()) + else directive 2 lexbuf } + | '\\' { add_str(escaped lexbuf); string in_directive lexbuf } + | '\n' { add_str '\n'; newline lexbuf; string in_directive lexbuf } + | eof { raise (Lexer_error (lex_long_range lexbuf, + Printf.sprintf "String is not terminated")) } + | _ { add_str (Lexing.lexeme_char lexbuf 0); string in_directive lexbuf } + +and escaped = parse + | 'n' { '\n' } + | 't' { '\t' } + | '\\' { '\\' } + | '"' { '\034' } + | '\'' { '\'' } + | ['0'-'9']['0'-'9']['0'-'9'] + { + let x = int_of_string(lexeme lexbuf) in + if x > 255 then + raise (Lexer_error (lex_long_range lexbuf, + (Printf.sprintf "%s is an illegal escaped character constant" (lexeme lexbuf)))) + else + Char.chr x + } + | [^ '"' '\\' 't' 'n' '\''] + { raise (Lexer_error (lex_long_range lexbuf, + (Printf.sprintf "%s is an illegal escaped character constant" (lexeme lexbuf) ))) } + diff --git a/hw6/liveness.ml b/hw6/liveness.ml new file mode 100644 index 0000000..236cfee --- /dev/null +++ b/hw6/liveness.ml @@ -0,0 +1,98 @@ +open Ll +open Datastructures + +(* liveness analysis -------------------------------------------------------- *) + +(* Instantiates the generic dataflow analysis framework with the + lattice for liveness analysis. + - the lattice elements are sets of LL uids + - the flow functions propagate uses toward their definitions +*) + +(* the operands of an instruction ------------------------------------------- *) +let insn_ops : insn -> operand list = function + | Alloca _ -> [] + | Load (_,o) + | Bitcast (_,o,_) -> [o] + | Binop (_,_,o1,o2) + | Store (_,o1,o2) + | Icmp (_,_,o1,o2) -> [o1; o2] + | Call (_,o,args) -> o::List.map snd args + | Gep (_,o,os) -> o::os + +(* the operands of a terminator --------------------------------------------- *) +let terminator_ops : terminator -> operand list = function + | Ret (_,None) + | Br _ -> [] + | Ret (_,Some o) + | Cbr (o,_,_) -> [o] + +(* compute 'use' information for instructions and terminators --------------- *) +let uids_of_ops : operand list -> UidS.t = + List.fold_left (fun s o -> match o with Id u -> UidS.add u s | _ -> s) + UidS.empty + +let insn_uses (i:insn) : UidS.t = uids_of_ops (insn_ops i) +let terminator_uses (t:terminator) : UidS.t = uids_of_ops (terminator_ops t) + +(* The following two flow functions implement the liveness analysis: + + the dataflow equation for liveness analysis is: + in[n] = use[n] U (out[n] \ defs[n]) + + Because liveness is a backward analysis, the flow function expresses + in[n] as a _function_ of n and out[n]: + in[n] = flow n out[n] + + (In our representation, there is one flow function for instructions + and another for terminators. *) +let insn_flow (u,i:uid * insn) (out:UidS.t) : UidS.t = + out |> UidS.remove u + |> UidS.union (insn_uses i) + +let terminator_flow (t:terminator) (out:UidS.t) : UidS.t = + out |> UidS.union (terminator_uses t) + +module Fact = + struct + let forwards = false + let insn_flow = insn_flow + let terminator_flow = terminator_flow + + (* the lattice ---------------------------------------------------------- *) + type t = UidS.t + let combine ds = List.fold_left UidS.union UidS.empty ds + let equal = UidS.equal + + let compare = UidS.compare + let to_string = UidS.to_string + end + +(* instantiate the general framework ---------------------------------------- *) +module Graph = Cfg.AsGraph (Fact) +module Solver = Solver.Make (Fact) (Graph) + +(* expose a top-level analysis operation ------------------------------------ *) +let analyze (cfg:Cfg.cfg) : Graph.t = + let init l = UidS.empty in + let live_out = UidS.empty in + let g = Graph.of_cfg init live_out cfg in + Solver.solve g + +(* Get liveness information as taken in by the backend. For the live_in map, + for each block label or instruction uid in the graph, the result is the set of + ids that are live on entry to that block or instruction. Similarly for live_out. +*) +type liveness = {live_in : uid -> UidS.t; live_out : uid -> UidS.t} +let get_liveness (f : Ll.fdecl) : liveness = + let cfg = Cfg.of_ast f in + let graph = analyze cfg in + let make_fn block_info uid_info = LblS.fold + (fun l f -> + let l_in = block_info graph l in + let lb = uid_info graph l in + fun u -> try if l = u then l_in else lb u with Not_found -> f u) + (Cfg.nodes cfg) + (fun u -> ((* print_endline u; *) raise Not_found)) in + { live_in = make_fn Graph.block_in Graph.uid_in; + live_out = make_fn Graph.block_out Graph.uid_out} diff --git a/hw6/ll/ll-original.ml b/hw6/ll/ll-original.ml new file mode 100644 index 0000000..c0acb18 --- /dev/null +++ b/hw6/ll/ll-original.ml @@ -0,0 +1,81 @@ +(* LLVMlite: A simplified subset of the LLVM IR *) + +type uid = string (* Local identifiers *) +type gid = string (* Global identifiers *) +type tid = string (* Named types *) +type lbl = string (* Labels *) + +(* LLVM IR types *) +type ty = + | Void (* mix of unit/bottom from C *) + | I1 | I8 | I64 (* integer types *) + | Ptr of ty (* t* *) + | Struct of ty list (* { t1, t2, ... , tn } *) + | Array of int * ty (* [ NNN x t ] *) + | Fun of fty (* t1, ..., tn -> tr *) + | Namedt of tid (* named type aliases *) + +(* Function type: argument types and return type *) +and fty = ty list * ty + +(* Syntactic Values *) +type operand = + | Null (* null pointer *) + | Const of int64 (* integer constant *) + | Gid of gid (* A global identifier *) + | Id of uid (* A local identifier *) + +(* Type-annotated operands *) + +(* Binary operations *) +type bop = Add | Sub | Mul | Shl | Lshr | Ashr | And | Or | Xor + +(* Comparison Operators *) +type cnd = Eq | Ne | Slt | Sle | Sgt | Sge + +(* Instructions *) +type insn = + | Binop of bop * ty * operand * operand (* bop ty %o1, %o2 *) + | Alloca of ty (* alloca ty *) + | Load of ty * operand (* load ty %u *) + | Store of ty * operand * operand (* store ty %t, ty* %u *) + | Icmp of cnd * ty * operand * operand (* icmp %s ty %s, %s *) + | Call of ty * operand * (ty * operand) list (* fn(%1, %2, ...) *) + | Bitcast of ty * operand * ty (* bitcast ty1 %u to ty2 *) + | Gep of ty * operand * operand list (* getelementptr ty* %u, i64 %vi, ... *) + +(* Block terminators *) +type terminator = + | Ret of ty * operand option (* ret i64 %s *) + | Br of lbl (* br label %lbl *) + | Cbr of operand * lbl * lbl (* br i1 %s, label %l1, label %l2 *) + +(* Basic blocks *) +type block = { insns: (uid * insn) list; terminator: uid * terminator } + +(* Control Flow Graph: a pair of an entry block and a set labeled blocks *) +type cfg = block * (lbl * block) list + +(* Function declarations *) +type fdecl = { fty: fty; param: uid list; cfg: cfg } + +(* Initializers for global data *) +type ginit = + | GNull (* null literal *) + | GGid of gid (* reference another global *) + | GInt of int64 (* global integer value *) + | GString of string (* constant global string *) + | GArray of gdecl list (* global array *) + | GStruct of gdecl list (* global struct *) + +(* Global declaration *) +and gdecl = ty * ginit + +(* LLVMlite programs *) +type prog = + { tdecls: (tid * ty) list (* named types *) + ; gdecls: (gid * gdecl) list (* global data *) + ; fdecls: (gid * fdecl) list (* code *) + ; edecls: (gid * ty) list (* external declarations *) + } + diff --git a/hw6/ll/ll.ml b/hw6/ll/ll.ml new file mode 100644 index 0000000..9cd2ff8 --- /dev/null +++ b/hw6/ll/ll.ml @@ -0,0 +1,98 @@ +(* LLVMlite: A simplified subset of LLVM IR *) + +(* Local identifiers *) +type uid = string + +(* Global identifiers *) +type gid = string + +(* Named types *) +type tid = string + +(* Labels *) +type lbl = string + +(* LLVM types *) +type ty = +| Void +| I1 +| I8 +| I64 +| Ptr of ty +| Struct of ty list +| Array of int * ty +| Fun of ty list * ty +| Namedt of tid + +(* Function type: argument types and return type *) +type fty = ty list * ty + +(* Syntactic Values *) +type operand = +| Null +| Const of int64 +| Gid of gid +| Id of uid + +(* Binary i64 Operations *) +type bop = +| Add +| Sub +| Mul +| Shl +| Lshr +| Ashr +| And +| Or +| Xor + +(* Comparison Operators *) +type cnd = +| Eq +| Ne +| Slt +| Sle +| Sgt +| Sge + +(* Instructions *) +type insn = +| Binop of bop * ty * operand * operand +| Alloca of ty +| Load of ty * operand +| Store of ty * operand * operand +| Icmp of cnd * ty * operand * operand +| Call of ty * operand * (ty * operand) list +| Bitcast of ty * operand * ty +| Gep of ty * operand * operand list + +type terminator = +| Ret of ty * operand option +| Br of lbl +| Cbr of operand * lbl * lbl + +(* Basic Blocks *) +type block = { insns : (uid * insn) list; term : (uid * terminator) } + +(* Control Flow Graphs: entry and labeled blocks *) +type cfg = block * (lbl * block) list + +(* Function Declarations *) +type fdecl = { f_ty : fty; f_param : uid list; f_cfg : cfg } + +(* Global Data Initializers *) +type ginit = +| GNull +| GGid of gid +| GInt of int64 +| GString of string +| GArray of (ty * ginit) list +| GStruct of (ty * ginit) list +| GBitcast of ty * ginit * ty + +(* Global Declarations *) +type gdecl = ty * ginit + +(* LLVMlite Programs *) +type prog = { tdecls : (tid * ty) list; gdecls : (gid * gdecl) list; + fdecls : (gid * fdecl) list; edecls : (gid * ty) list } diff --git a/hw6/ll/llinterp.ml b/hw6/ll/llinterp.ml new file mode 100644 index 0000000..2e2388b --- /dev/null +++ b/hw6/ll/llinterp.ml @@ -0,0 +1,470 @@ +open Ll +open Llutil + +(* LLVMlite interpreter *) + +type mid = int (* memory block id *) +type fid = int (* stack frame id *) +type idx = int (* index *) + +(* Memory block identifier *) +type bid = GlobId of gid + | HeapId of mid + | StckId of fid + | NullId + +(* Pointers are tagged with a description of the block they reference + offsets are represented as paths into memory values *) +type ptr = ty * bid * idx list + +(* "Simple" or stack values *) +type sval = + | VUndef + | VInt of int64 + | VPtr of ptr + +(* Memory values *) +type mtree = MWord of sval + | MStr of string + | MNode of mval +and mval = mtree list + +(* Locals *) +type locals = uid -> sval + +(* The memory state *) +type config = + { globals : (gid * mval) list + ; heap : (mid * mval) list + ; stack : (fid * mval) list + } + +(* Create memory value for global declaration *) +let mval_of_gdecl (gd:gdecl) : mval = + let rec mtree_of_gdecl : gdecl -> mtree = function + | ty, GNull -> MWord (VPtr (ty, NullId, [0])) + | ty, GGid g -> MWord (VPtr (ty, GlobId g, [0])) + | _, GBitcast (t1, v,t2) -> mtree_of_gdecl (t1, v) + | _, GInt i -> MWord (VInt i) + | _, GString s -> MStr s + | _, GArray gs + | _, GStruct gs -> MNode (List.map mtree_of_gdecl gs) + in [mtree_of_gdecl gd] + +(* Create fully undefined memory value for a type *) +let mval_of_ty (nt:tid -> ty) (t:ty) : mval = + let rec mtree_of_ty : ty -> mtree = function + | I1 | I8 | I64 | Ptr _ -> MWord VUndef + | Array (n, I8) -> MStr (String.make n '\x00') + | Array (n, t) -> MNode Array.(make n (MWord VUndef) |> to_list) + | Struct ts -> MNode (List.map mtree_of_ty ts) + | Fun _ | Void -> failwith "mval_of_ty: mval for bad type" + | Namedt id -> mtree_of_ty (nt id) + in [mtree_of_ty t] + + +(* Printing machine states *) +let mapcat s f l = String.concat s @@ List.map f l +let prefix p f a = p ^ f a +let ( ^. ) s t = if s = "" || t = "" then "" else s ^ t +let pp = Printf.sprintf + +let string_of_bid = function + | GlobId gid -> "@" ^ gid + | HeapId mid -> "M" ^ (string_of_int mid) + | StckId fid -> "S" ^ (string_of_int fid) + | NullId -> "null" + +let string_of_ptr (t, b, i) = + pp "%s %s %s" (string_of_ty t) (string_of_bid b) + (mapcat ", " string_of_int i) + +let string_of_sval (sv:sval) : string = + match sv with + | VUndef -> "undef" + | VInt x -> Int64.to_string x + | VPtr p -> string_of_ptr p + +let rec string_of_mval (mv:mval) : string = + "[" ^ (mapcat " " string_of_mtree mv) ^ "]" + +and string_of_mtree = function + | MWord sv -> string_of_sval sv + | MStr s -> "\"" ^ s ^ "\"" + | MNode m -> string_of_mval m + + +(* Varieties of undefined behavior. Can be raised by load/store *) +exception OOBIndexDeref (* mem access not in bounds of an array *) +exception NullPtrDeref (* deref Null *) +exception UndefPtrDeref (* deref Undef pointer (from bad GEP) *) +exception IncompatTagDeref (* deref pointer at wrong type (bad bitcast) *) +exception UndefMemDeref (* read uninitialized memory *) +exception UninitMemLoad (* uninitialized memory load *) +exception UseAfterFree (* deref freed stack/heap memory *) + + +(* Arithmetic operations are all signed 64bit 2s compliment (mod In64.max_int) *) +let interp_bop (b:bop) (v1:sval) (v2:sval) : sval = + let i, j = match v1, v2 with + | VInt i, VInt j -> i, j + | _ -> invalid_arg "interp_bop" + in + let open Int64 in + let f = match b with + | Add -> add | Sub -> sub | Mul -> mul + | And -> logand | Or -> logor | Xor -> logxor + | Shl -> fun i j -> shift_left i @@ to_int j + | Lshr -> fun i j -> shift_right_logical i @@ to_int j + | Ashr -> fun i j -> shift_right i @@ to_int j + in VInt (f i j) + +let interp_cnd (c:cnd) (v1:sval) (v2:sval) = + let f = match c with + | Eq -> (=) | Ne -> (<>) | Slt -> (<) + | Sle -> (<=) | Sgt -> (>) | Sge -> (>=) + in + match v1, v2, c with + | VPtr (_,b1,i1), VPtr (_,b2,i2), Eq + | VPtr (_,b1,i1), VPtr (_,b2,i2), Ne -> + VInt (if f (b1,i1) (b2,i2) then 1L else 0L) + | VInt i, VInt j, _ -> + VInt (if f i j then 1L else 0L) + | _ -> invalid_arg "interp_cnd" + +let interp_i1 : sval -> bool = function + | VInt 0L -> false + | VInt 1L -> true + | _ -> invalid_arg "interp_i1" + +let rec interp_operand (nt:tid -> ty) (locs:locals) (ty:ty) (o:operand) : sval = + match ty, o with + | I64, Const i -> VInt i + | Ptr ty, Null -> VPtr (ty, NullId, [0]) + | Ptr ty, Gid g -> VPtr (ty, GlobId g, [0]) + | _, Id u -> locs u + | Namedt id, o -> interp_operand nt locs (nt id) o + | _ -> failwith @@ "interp_operand: malformed operand " ^ soo o ^ ":" ^ sot ty + + +(* Some utility functions *) +let update f k v = fun k' -> if k = k' then v else f k' + +let rec is_prefix (l:'a list) (m:'a list) : bool = + match l, m with + | [], _ -> true + | _, [] -> false + | a::l, b::m -> a = b && is_prefix l m + +let replace_assoc (l:('a * 'b) list) (a:'a) (b:'b) : ('a * 'b) list = + let rec loop acc = function + | [] -> List.rev @@ (a,b)::acc + | (a',_)::l' when a = a' -> List.rev_append acc @@ (a,b):: l' + | e::l' -> loop (e::acc) l' + in + loop [] l + +let replace_nth (l:'a list) (n:int) (a:'a) : 'a list = + let rec loop acc n = function + | [] -> raise Not_found + | a'::l' -> if n = 0 then List.rev_append acc (a::l') + else loop (a'::acc) (pred n) l' + in + loop [] n l + + +(* Memory access *) +let rec load_idxs (m:mval) (idxs:idx list) : mtree = + match idxs with + | [] -> MNode m + | i::idxs' -> + let len = List.length m in + if len <= i || i < 0 then raise OOBIndexDeref else + match idxs', List.nth m i with + | [], mt -> mt + | [0], MStr s -> MStr s (* [n x i8]* %p and gep [n x i8]* %p, 0, 0 alias *) + | _, MWord v -> failwith "load_idxs: attempted to index into word" + | _, MStr _ -> failwith "load_idxs: attempted to index into string" + | _, MNode m' -> load_idxs m' idxs' + +let rec store_idxs (m:mval) (idxs:idx list) (mt:mtree) : mval = + match idxs with + | [] -> [mt] + | i::idxs' -> + let len = List.length m in + if len <= i || i < 0 then raise OOBIndexDeref else + match idxs', List.nth m i with + | [], _ -> replace_nth m i mt + | _, MWord v -> failwith "store_idxs: attempted to index into word" + | _, MStr _ -> failwith "store_idxs: attempted to index into string" + | _, MNode m' -> replace_nth m i @@ MNode (store_idxs m' idxs' mt) + +let load_bid (c:config) (bid:bid) : mval = + match bid with + | NullId -> raise NullPtrDeref + | HeapId mid -> + (try List.assoc mid c.heap + with Not_found -> raise UseAfterFree) + | GlobId gid -> + (try List.assoc gid c.globals + with Not_found -> failwith "Load: bogus gid") + | StckId fid -> + (try List.assoc fid c.stack + with Not_found -> raise UseAfterFree) + + +let load_ptr (c:config) (_, bid, idxs:ptr) : mtree = + load_idxs (load_bid c bid) idxs + +let store_ptr (c:config) (_, bid, idxs:ptr) (mt:mtree) : config = + let mval = load_bid c bid in + match bid with + | NullId -> raise NullPtrDeref + | HeapId mid -> + let mval' = store_idxs mval idxs mt in + let heap = replace_assoc c.heap mid mval' in + {c with heap} + | GlobId gid -> + let mval' = store_idxs mval idxs mt in + let globals = replace_assoc c.globals gid mval' in + {c with globals} + | StckId fid -> + let frame' = store_idxs mval idxs mt in + let stack = replace_assoc c.stack fid frame' in + {c with stack} + + +(* Tag and GEP implementation *) +let effective_tag (nt:tid -> ty) (tag, _, idxs :ptr) : ty = + let rec loop tag idxs = + match tag, idxs with + | t, [] -> t + | Struct ts, i::idxs' -> if List.length ts <= i + then failwith "effective_tag: index oob of struct" + else loop (List.nth ts i) idxs' + | Array (n, t), i::idxs' -> loop t idxs' (* Don't check if OOB! *) + | Namedt id, _ -> loop (nt id) idxs + | _, _::_ -> failwith "effective_tag: index into non-aggregate" + in + loop tag @@ try List.tl idxs + with Failure _ -> failwith "effective_tag: invalid pointer missing first index" + + +let rec gep_idxs (p:idx list) (idxs:idx list) : idx list = + match p, idxs with + | [], _ | _, [] -> failwith "gep_idxs: invalid indices" + | [i], j::idxs' -> i+j::idxs' + | i::p', _ -> i::gep_idxs p' idxs + + +let legal_gep (nt:tid -> ty) (sty:ty) (tag:ty) : bool = + let rec ptrtoi8 : ty -> ty = function + | Ptr _ -> Ptr I8 + | Struct ts -> Struct (List.map ptrtoi8 ts) + | Array (n, t) -> Array (n, ptrtoi8 t) + | Namedt id -> ptrtoi8 (nt id) + | t -> t + in + let rec flatten_ty : ty -> ty list = function + | Struct ts -> List.(concat @@ map flatten_ty ts) + | t -> [t] + in + is_prefix (flatten_ty @@ ptrtoi8 sty) (flatten_ty @@ ptrtoi8 tag) + +let gep_ptr (nt:tid -> ty) (ot:ty) (p:ptr) (idxs':idx list) : sval = + if not (legal_gep nt ot @@ effective_tag nt p) then VUndef else + match p with + | t, NullId, idxs -> VUndef + | t, bid, idxs -> + VPtr (t, bid, gep_idxs idxs idxs') + + +(* LLVMlite reference interpreter *) +let interp_prog {tdecls; gdecls; fdecls} (args:string list) : sval = + + let globals = List.map (fun (g,gd) -> g,mval_of_gdecl gd) gdecls in + + let nt (id:tid) : ty = + try List.assoc id tdecls + with Not_found -> failwith @@ "interp_prog: undefined named type " ^ id + in + + let interp_op = interp_operand nt in + + let next_id : unit -> fid = + let c = ref 0 in + fun () -> c := succ !c; !c + in + + (* Global identifiers that will be interpreted as external functions *) + let runtime_fns = [ "ll_puts"; "ll_strcat"; "ll_ltoa" ] + in + + (* External function implementation *) + let runtime_call (t:ty) (fn:gid) (args:sval list) (c:config) : config * sval = + let load_strptr p = match load_ptr c p with + | MStr s -> s + | _ -> failwith "runtime_call: non string-ptr arg" + in + match t, fn, args with + | Void, "ll_puts", [VPtr p] -> + let s = load_strptr p in + print_endline s; + c, VUndef + | Ptr t, "ll_strcat", [VPtr ps1; VPtr ps2] -> + let s1 = load_strptr ps1 in + let s2 = load_strptr ps2 in + let mid = next_id () in + let mv = [MStr (s1 ^ s2)] in + let heap = (mid, mv)::c.heap in + {c with heap}, VPtr (t, HeapId mid, [0]) + | I64, "ll_ltoa", [VInt i; VPtr dst] -> + let mid = next_id () in + let mv = [MStr (Int64.to_string i)] in + let heap = (mid, mv)::c.heap in + {c with heap}, VPtr (t, HeapId mid, [0]) + | _ -> failwith @@ "runtime_call: invalid call to " ^ fn + in + + + (* Interprety the body of a function *) + let rec interp_cfg (k, blocks:cfg) (locs:locals) (c:config) : config * sval = + match k.insns, k.term with + + | (u, Binop (b, t, o1, o2))::insns, _ -> + let v1 = interp_op locs t o1 in + let v2 = interp_op locs t o2 in + let vr = interp_bop b v1 v2 in + let locs' = update locs u vr in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Icmp (cnd, t, o1, o2))::insns, _ -> + let v1 = interp_op locs t o1 in + let v2 = interp_op locs t o2 in + let vr = interp_cnd cnd v1 v2 in + let locs' = update locs u vr in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Alloca ty)::insns, _ -> + begin match c.stack with + | [] -> failwith "stack empty" + | (fid,frame)::stack' -> + let ptr = VPtr (ty, StckId fid, [List.length frame]) in + let stack = (fid, frame @ [MWord VUndef])::stack' in + let locs' = update locs u ptr in + interp_cfg ({k with insns}, blocks) locs' {c with stack} + end + + | (u, Load (Ptr t, o))::insns, _ -> + let mt = match interp_op locs (Ptr t) o with + | VPtr p -> + if effective_tag nt p <> t + then raise IncompatTagDeref + else load_ptr c p + | VUndef -> raise UndefPtrDeref + | VInt _ -> failwith "non-ptr arg for load" + in + let v = match mt with + | MWord VUndef -> raise UninitMemLoad + | MWord v -> v + | _ -> failwith "load: returned aggregate" + in + let locs' = update locs u v in + interp_cfg ({k with insns}, blocks) locs' c + + | (_, Store (t, os, od))::insns, _ -> + let vs = interp_op locs t os in + let vd = interp_op locs (Ptr t) od in + let c' = match vd with + | VPtr p -> + if effective_tag nt p <> t + then raise IncompatTagDeref + else store_ptr c p (MWord vs) + | VUndef -> raise UndefPtrDeref + | VInt _ -> failwith "non-vptr arg for load" + in + interp_cfg ({k with insns}, blocks) locs c' + + | (u, Call (t, ofn, ato))::insns, _ -> + let ats, aos = List.split ato in + let ft = Ptr (Fun (ats, t)) in + let g = match interp_op locs ft ofn with + | VPtr (_, GlobId g, [0]) -> g + | _ -> failwith "bad call arg" + in + let args = List.map2 (interp_op locs) ats aos in + let c', r = interp_call t g args c in + let locs' = update locs u r in + interp_cfg ({k with insns}, blocks) locs' c' + + | (u, Bitcast (t1, o, _))::insns, _ -> + let v = interp_op locs t1 o in + let locs' = update locs u v in + interp_cfg ({k with insns}, blocks) locs' c + + | (u, Gep (Ptr t, o, os))::insns, _ -> + let idx_of_sval : sval -> idx = function + | VInt i -> Int64.to_int i + | _ -> failwith "idx_of_sval: non-integer value" + in + let vs = List.map (interp_op locs I64) os in + let idxs' = List.map idx_of_sval vs in + let v' = match interp_op locs (Ptr t) o with + | VPtr p -> gep_ptr nt t p idxs' + | VUndef -> VUndef + | VInt _ -> failwith "non-ptr arg for gep" + in + let locs' = update locs u v' in + interp_cfg ({k with insns}, blocks) locs' c + + | [], (_, Ret (_, None)) -> + {c with stack = List.tl c.stack}, VUndef + + | [], (_, Ret (t, Some o)) -> + {c with stack = List.tl c.stack}, interp_op locs t o + + | [], (_, Br l) -> + let k' = List.assoc l blocks in + interp_cfg (k', blocks) locs c + + | [], (_, Cbr (o, l1, l2)) -> + let v = interp_op locs I1 o in + let l' = if interp_i1 v then l1 else l2 in + let k' = List.assoc l' blocks in + interp_cfg (k', blocks) locs c + + | (u,i)::_, _ -> failwith @@ "interp_cfg: invalid instruction \"" + ^ string_of_insn i ^ "\" at %" ^ u + + and interp_call (ty:ty) (fn:gid) (args:sval list) (c:config) : config * sval = + if List.mem fn runtime_fns + then runtime_call ty fn args c + else + let {f_param; f_cfg} = try List.assoc fn fdecls + with Not_found -> failwith @@ "interp_call: undefined function " ^ fn + in + if List.(length f_param <> length args) then + failwith @@ "interp_call: wrong no. arguments for " ^ fn; + let init_locs l = failwith @@ "interp_call: undefined local " ^ l in + let locs = List.fold_left2 update init_locs f_param args in + let stack = (next_id(), [])::c.stack in + interp_cfg f_cfg locs {c with stack} + in + + let mkarg a (p,h) = + let id = next_id () in + VPtr (I8, HeapId id, [0])::p, (id, [MStr a])::h + in + let ptrs, heap = List.fold_right mkarg ("LLINTERP"::args) ([],[]) in + + let narg = List.length args + 1 in + let argc = VInt (Int64.of_int @@ narg) in + let aid = next_id () in + let argv = VPtr (Array (narg, Ptr I8), HeapId aid, [0; 0]) in + let amval = List.map (fun p -> MWord p) ptrs in + let heap = (aid, [MNode amval])::heap in + + let _, r = interp_call I64 "main" [argc; argv] {globals; heap; stack=[]} in + r + + diff --git a/hw6/ll/lllexer.mll b/hw6/ll/lllexer.mll new file mode 100644 index 0000000..2fbacba --- /dev/null +++ b/hw6/ll/lllexer.mll @@ -0,0 +1,83 @@ +{ open Lexing + open Llparser + + exception SyntaxError of string +} + +let newline = '\n' | ('\r' '\n') | '\r' +let whitespace = ['\t' ' '] +let lowercase = ['a'-'z'] +let uppercase = ['A'-'Z'] +let character = lowercase | uppercase +let digit = '-'? ['0'-'9'] +let identifier = (character | digit | '_' ) (character | digit | '_' | '.')* + +rule token = parse + | eof { EOF } + | whitespace+ { token lexbuf } + | newline+ { token lexbuf } + | "c\"" { read_string (Buffer.create 17) lexbuf } + | '*' { STAR } + | ',' { COMMA } + | ':' { COLON } + | '=' { EQUALS } + | '(' { LPAREN } + | ')' { RPAREN } + | '{' { LBRACE } + | '}' { RBRACE } + | '[' { LBRACKET } + | ']' { RBRACKET } + | "i1" { I1 } + | "i8" { I8 } + | "i32" { I32 } + | "i64" { I64 } + | "to" { TO } + | "br" { BR } + | "eq" { EQ } + | "ne" { NE } + | "or" { OR } + | "and" { AND } + | "add" { ADD } + | "sub" { SUB } + | "mul" { MUL } + | "xor" { XOR } + | "slt" { SLT } + | "sle" { SLE } + | "sgt" { SGT } + | "sge" { SGE } + | "shl" { SHL } + | "ret" { RET } + | "getelementptr" { GEP } + | "type" { TYPE } + | "null" { NULL } + | "lshr" { LSHR } + | "ashr" { ASHR } + | "call" { CALL } + | "icmp" { ICMP } + | "void" { VOID } + | "load" { LOAD } + | "entry" { ENTRY } + | "store" { STORE } + | "label" { LABEL } + | "global" { GLOBAL } + | "define" { DEFINE } + | "declare" { DECLARE } + | "external" { EXTERNAL } + | "alloca" { ALLOCA } + | "bitcast" { BITCAST } + | '%' ('.' ?) (identifier as i) { UID i } + | '@' ('.' ?) (identifier as i) { GID i } + | "x" { CROSS } (* for Array types *) + | digit+ as d { INT (int_of_string d) } + | identifier as i { LBL i } + | ";" ([^ '\n' '\r'])* newline { token lexbuf } (* comments *) + | "declare" ([^ '\n' '\r'])* newline { token lexbuf } (* declare acts as a comment for our IR *) + | _ as c { raise @@ SyntaxError ("Unexpected character: " ^ Char.escaped c) } + +and read_string buf = parse + | '\\' "00" '"' { STRING (Buffer.contents buf) } + | '\\' { Buffer.add_char buf '\\'; read_string buf lexbuf } + | [^ '"' '\\']+ { Buffer.add_string buf (Lexing.lexeme lexbuf) + ; read_string buf lexbuf } + | _ { raise (SyntaxError ("Illegal string character: " ^ Lexing.lexeme lexbuf)) } + | eof { raise (SyntaxError ("String is not terminated")) } diff --git a/hw6/ll/llparser.mly b/hw6/ll/llparser.mly new file mode 100644 index 0000000..ca28340 --- /dev/null +++ b/hw6/ll/llparser.mly @@ -0,0 +1,298 @@ +%{ open Ll + open Llutil.Parsing + +%} + +(* Symbols *) +%token STAR (* * *) +%token COMMA (* , *) +%token COLON (* : *) +%token EQUALS (* = *) +%token LPAREN (* ( *) +%token RPAREN (* ) *) +%token LBRACE (* { *) +%token RBRACE (* } *) +%token LBRACKET (* [ *) +%token RBRACKET (* ] *) +%token EOF + +(* Reserved Words *) +%token CROSS (* x *) +%token I1 (* i1 *) +%token I8 (* i8 *) +%token I32 (* i32 *) +%token I64 (* i64 *) +%token TO (* to *) +%token BR (* br *) +%token EQ (* eq *) +%token NE (* ne *) +%token OR (* or *) +%token AND (* and *) +%token ADD (* add *) +%token SUB (* sub *) +%token MUL (* mul *) +%token XOR (* xor *) +%token SLT (* slt *) +%token SLE (* sle *) +%token SGT (* sgt *) +%token SGE (* sge *) +%token SHL (* shl *) +%token RET (* ret *) +%token TYPE (* type *) +%token NULL (* null *) +%token LSHR (* lshr *) +%token ASHR (* ashr *) +%token CALL (* call *) +%token ICMP (* icmp *) +%token VOID (* void *) +%token LOAD (* load *) +%token STORE (* store *) +%token LABEL (* label *) +%token ENTRY (* entry *) +%token GLOBAL (* global *) +%token DEFINE (* define *) +%token DECLARE (* define *) +%token EXTERNAL (* external *) +%token ALLOCA (* alloca *) +%token BITCAST (* bitcast *) +%token GEP (* getelementptr *) + +%token INT (* int64 values *) +%token LBL (* labels *) +%token GID (* global identifier *) +%token UID (* local identifier *) +%token STRING (* string literals *) + +%start prog +%% + +prog: + | ds=decls EOF + { ds } + +decls: + | ds = decls_rev + { { tdecls = List.rev ds.tdecls + ; gdecls = List.rev ds.gdecls + ; fdecls = List.rev ds.fdecls + ; edecls = List.rev ds.edecls + } } + +decls_rev: + | (* empty *) + { { tdecls = [] ; gdecls = [] ; fdecls = [] ; edecls = [] } } + | ds=decls_rev f=fdecl + { { ds with fdecls = f :: ds.fdecls } } + | ds=decls_rev g=gdecl + { { ds with gdecls = g :: ds.gdecls } } + | ds=decls_rev t=tdecl + { { ds with tdecls = t :: ds.tdecls } } + | ds=decls_rev e=edecl + { { ds with edecls = e :: ds.edecls } } + +fdecl: + | DEFINE t=ty l=GID LPAREN a=arg_list RPAREN + LBRACE eb=entry_block bs=block_list RBRACE + { (l, { f_ty = (List.map fst a, t) + ; f_param = List.map snd a + ; f_cfg = (eb, bs) + } + ) } + +gdecl: + | g=GID EQUALS GLOBAL t=ty gi=ginit + { (g, (t,gi)) } + +tdecl: + | tid=UID EQUALS TYPE t=ty + { (tid, t) } + +edecl: + | DECLARE rt=ty g=GID LPAREN ts=separated_list(COMMA, ty) RPAREN + { (g, Fun (ts,rt)) } + | g=GID EQUALS EXTERNAL GLOBAL t=ty + { (g, t) } + +nonptr_ty: + | VOID { Void } + | I1 { I1 } + | I8 { I8 } + | I64 { I64 } + | LBRACE ts=ty_list RBRACE + { Struct ts } + | LBRACKET i=INT CROSS t=ty RBRACKET + { Array (i,t) } + | rt=ty LPAREN ts=ty_list RPAREN + { Fun (ts, rt) } + | t=UID + { Namedt t } + +ty: + | t=ty STAR + { Ptr t } + | t=nonptr_ty + { t } + +ty_list_rev: + | t=ty + { [t] } + | ts=ty_list_rev COMMA t=ty + { t::ts } + +ty_list: + | ts=ty_list_rev + { List.rev ts } + +arg: + | t=ty u=UID { (t,u) } + +arg_list_rev: + | (* empty *) + { [] } + | a=arg + { [a] } + | args=arg_list_rev COMMA a=arg + { a::args } + +arg_list: + | a=arg_list_rev + { List.rev a } + +operand: + | NULL + { Null } + | i=INT + { Const (Int64.of_int i) } + | g=GID + { Gid g } + | u=UID + { Id u } + +ty_operand_list_rev: + | (* empty *) + { [] } + | t=ty o=operand + { [(t,o)] } + | tos=ty_operand_list_rev COMMA t=ty o=operand + { (t,o)::tos } + +ty_operand_list: + | tos=ty_operand_list_rev + { List.rev tos } + +i_operand_list_rev: + | (* empty *) + { [] } + | I64 o=operand + { [o] } + | I32 o=operand + { [o] } + | os=i_operand_list_rev COMMA I64 o=operand + { o::os } + | os=i_operand_list_rev COMMA I32 o=operand + { o::os } + +i_operand_list: + | os=i_operand_list_rev + { List.rev os } + +terminator: + | RET t=ty o=operand + { Ret (t, Some o) } + | RET t=ty + { Ret (t, None) } + | BR LABEL l=UID + { Br l } + | BR I1 o=operand COMMA LABEL l1=UID COMMA LABEL l2=UID + { Cbr (o,l1,l2) } + +block: + | is=insn_list t=terminator + { { insns = is; term=(gensym "tmn", t) } } + +block_list_rev: + | (* empty *) + { [] } + | bs=block_list_rev l=LBL COLON b=block + { (l,b) :: bs } + +block_list: + | bs=block_list_rev + { List.rev bs } + +entry_block: + | ENTRY COLON b=block + { b } + | b=block + { b } + +bop: + | OR { Or } + | ADD { Add } + | SUB { Sub } + | MUL { Mul } + | SHL { Shl } + | XOR { Xor } + | AND { And } + | LSHR { Lshr } + | ASHR { Ashr } + +cnd: + | EQ { Eq } + | NE { Ne } + | SLT { Slt } + | SLE { Sle } + | SGT { Sgt } + | SGE { Sge } + +insn: + | u=UID EQUALS b=bop t=ty o1=operand COMMA o2=operand + { (u, Binop (b,t,o1,o2)) } + | u=UID EQUALS ALLOCA t=ty + { (u, Alloca t) } + | u=UID EQUALS LOAD ty COMMA t=ty o=operand + { (u, Load (t,o)) } + | STORE t1=ty o1=operand COMMA t2=ty o2=operand + { (gensym "store", Store (t1,o1,o2)) } + | u=UID EQUALS ICMP c=cnd t=ty o1=operand COMMA o2=operand + { (u, Icmp (c,t,o1,o2)) } + | CALL t=ty o=operand LPAREN args=ty_operand_list RPAREN + { (gensym "call", Call (t, o, args)) } + | u=UID EQUALS CALL t=ty o=operand LPAREN args=ty_operand_list RPAREN + { (u, Call (t, o, args)) } + | u=UID EQUALS BITCAST t1=ty o=operand TO t2=ty + { (u, Bitcast (t1,o,t2)) } + | u=UID EQUALS GEP ty COMMA t=ty o=operand COMMA os=i_operand_list + { (u, Gep (t,o,os)) } + +insn_list: + | is=list(insn) + { is } + +gdecl_list_rev: + | (* empty *) + { [] } + | t=ty g=ginit + { [(t,g)] } + | gs=gdecl_list_rev COMMA t=ty g=ginit + { (t,g)::gs } + +gdecl_list: + | gs=gdecl_list_rev + { List.rev gs } + +ginit: + | NULL + { GNull } + | g=GID + { GGid g } + | i=INT + { GInt (Int64.of_int i) } + | s=STRING + { GString s } + | LBRACKET gs=gdecl_list RBRACKET + { GArray gs } + | LBRACE gs=gdecl_list RBRACE + { GStruct gs } + | BITCAST LPAREN t1=ty g=ginit TO t2=ty RPAREN + { GBitcast (t1, g, t2) } diff --git a/hw6/ll/llruntime.c b/hw6/ll/llruntime.c new file mode 100644 index 0000000..895fe36 --- /dev/null +++ b/hw6/ll/llruntime.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +/* TODO: if we enforce that all char literals are null-terminated, + and all allocated memory is zero-initialized, are these safe + when llvmlite program does not exhibit UB? */ + +void *ll_malloc(int64_t n, int64_t size) { + return calloc(n, size); +} + +int64_t ll_strlen(int8_t *s) { + return 0; +} + +int8_t *ll_strncopy(int8_t *dst, int8_t *src, int64_t i) { + int64_t src_size = ll_strlen(src); + int64_t dst_size = ll_strlen(dst); + if (i >= dst_size) + return dst; + else + return (int8_t*)strncpy((char *)dst + i, (char *)src, dst_size - i); +} + +void ll_puts(int8_t *s) { + puts((char *)s); +} + +int64_t ll_atol(int8_t *s) { + return atol((char *)s); +} + +int64_t ll_ltoa(int64_t i, int8_t *dst) { + int64_t size = ll_strlen(dst); + return snprintf((char *)dst, size, "%ld", (long)i); +} diff --git a/hw6/ll/llutil.ml b/hw6/ll/llutil.ml new file mode 100644 index 0000000..f7bba0f --- /dev/null +++ b/hw6/ll/llutil.ml @@ -0,0 +1,170 @@ +;; open Ll + +(* serializing --------------------------------------------------------------- *) + +let mapcat s f l = String.concat s @@ List.map f l +let prefix p f a = p ^ f a +let ( ^. ) s t = if s = "" || t = "" then "" else s ^ t +let pp = Printf.sprintf + +let rec string_of_ty : ty -> string = function + | Void -> "void" + | I1 -> "i1" + | I8 -> "i8" + | I64 -> "i64" + | Ptr ty -> pp "%s*" (string_of_ty ty) + | Struct ts -> pp "{ %s }" (mapcat ", " string_of_ty ts) + | Array (n, t) -> pp "[%s x %s]" (string_of_int n) (string_of_ty t) + | Fun (ts,t) -> pp "%s (%s)" (string_of_ty t) (mapcat ", " string_of_ty ts) + | Namedt s -> pp "%%%s" s + +let sot = string_of_ty + +let dptr = function + | Ptr t -> t + | _ -> failwith "PP: expected pointer type" + +let string_of_operand : operand -> string = function + | Null -> "null" + | Const i -> Int64.to_string i + | Gid g -> "@" ^ g + | Id u -> "%" ^ u + +let soo = string_of_operand + +let soop (t,v:ty * operand) : string = + pp "%s %s" (sot t) (soo v) + +let string_of_bop : bop -> string = function + | Add -> "add" | Sub -> "sub" | Mul -> "mul" + | Shl -> "shl" | Lshr -> "lshr" | Ashr -> "ashr" + | And -> "and" | Or -> "or" | Xor -> "xor" + +let string_of_cnd : cnd -> string = function + | Eq -> "eq" | Ne -> "ne" | Slt -> "slt" + | Sle -> "sle" | Sgt -> "sgt" | Sge -> "sge" + +let string_of_gep_index : operand -> string = function + | Const i -> "i32 " ^ Int64.to_string i + | o -> "i64 " ^ soo o + +let string_of_insn : insn -> string = function + | Binop (b, t, o1, o2) -> pp "%s %s %s, %s" + (string_of_bop b) (sot t) (soo o1) (soo o2) + | Alloca t -> pp "alloca %s" (sot t) + | Load (t, o) -> pp "load %s, %s %s" (sot (dptr t)) (sot t) (soo o) + | Store (t, os, od) -> pp "store %s %s, %s %s" + (sot t) (soo os) (sot (Ptr t)) (soo od) + | Icmp (c, t, o1, o2) -> pp "icmp %s %s %s, %s" + (string_of_cnd c) (sot t) (soo o1) (soo o2) + | Call (t, o, oa) -> pp "call %s %s(%s)" + (sot t) (soo o) (mapcat ", " soop oa) + | Bitcast (t1, o, t2) -> pp "bitcast %s %s to %s" (sot t1) (soo o) (sot t2) + | Gep (t, o, oi) -> pp "getelementptr %s, %s %s, %s" (sot (dptr t)) (sot t) (soo o) + (mapcat ", " string_of_gep_index oi) + +let string_of_named_insn (u,i:uid * insn) : string = + match i with + | Store _ | Call (Void, _, _) -> string_of_insn i + | _ -> pp "%%%s = %s" u (string_of_insn i) + +let string_of_terminator : terminator -> string = function + | Ret (_, None) -> "ret void" + | Ret (t, Some o) -> pp "ret %s %s" (sot t) (soo o) + | Br l -> pp "br label %%%s" l + | Cbr (o, l, m) -> pp "br i1 %s, label %%%s, label %%%s" (soo o) l m + +let string_of_block (b:block) : string = + (mapcat "\n" (prefix " " string_of_named_insn) b.insns ^. "\n") + ^ (prefix " " string_of_terminator) (snd b.term) + +let string_of_cfg (e,bs:cfg) : string = + let string_of_named_block (l,b) = l ^ ":\n" ^ string_of_block b in + string_of_block e ^ "\n" ^. mapcat "\n" string_of_named_block bs + +let string_of_named_fdecl (g,f:gid * fdecl) : string = + let string_of_arg (t,u) = pp "%s %%%s" (sot t) u in + let ts, t = f.f_ty in + pp "define %s @%s(%s) {\n%s\n}\n" (sot t) g + (mapcat ", " string_of_arg List.(combine ts f.f_param)) + (string_of_cfg f.f_cfg) + +let rec string_of_ginit : ginit -> string = function + | GNull -> "null" + | GGid g -> pp "@%s" g + | GInt i -> Int64.to_string i + | GString s -> pp "c\"%s\\00\"" s + | GArray gis -> pp "[ %s ]" (mapcat ", " string_of_gdecl gis) + | GStruct gis -> pp "{ %s }" (mapcat ", " string_of_gdecl gis) + | GBitcast (t1,g,t2) -> pp "bitcast (%s %s to %s)" (sot t1) (string_of_ginit g) (sot t2) + +and string_of_gdecl (t,gi:gdecl) : string = + pp "%s %s" (sot t) (string_of_ginit gi) + +let string_of_named_gdecl (g,gd:gid * gdecl) : string = + pp "@%s = global %s" g (string_of_gdecl gd) + +let string_of_named_tdecl (n,t:tid * ty) : string = + pp "%%%s = type %s" n (sot t) + +let string_of_named_edecl (g,t:gid * ty) : string = + match t with + | Fun (ts, rt) -> pp "declare %s @%s(%s)" (string_of_ty rt) g + (mapcat ", " string_of_ty ts) + | _ -> pp "@%s = external global %s" g (string_of_ty t) + +let string_of_prog (p:prog) : string = + (mapcat "\n" string_of_named_tdecl p.tdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_gdecl p.gdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_fdecl p.fdecls ^. "\n\n") + ^ (mapcat "\n" string_of_named_edecl p.edecls) + +(* comparison for testing ----------------------------------------------------- *) + +(* delete dummy uids before comparison *) +let compare_block (b:block) (c:block) : int = + let del_dummy (u,i) = + match i with + | Store (_, _, _) -> "", i + | Call (Void, _, _) -> "", i + | _ -> u, i + in + let del_term (u,t) = ("", t) + in + Pervasives.compare + {insns=List.map del_dummy b.insns; term=del_term b.term} + {insns=List.map del_dummy c.insns; term=del_term c.term} + + + +(* helper module for AST ------------------------------------------------------ *) + +module IR = struct + let define t gid args f_cfg = + let ats, f_param = List.split args in + gid, { f_ty=ats,t; f_param; f_cfg} + + (* ignore first label *) + let cfg (lbs:(lbl * block) list) : cfg = + match lbs with + | [] -> failwith "cfg: no blocks!" + | (_,b)::lbs -> b, lbs + + let entry insns term : (lbl * block) = "", { insns; term } + let label lbl insns term = lbl, { insns; term } + + (* terminators *) + let ret_void = Ret (Void, None) + let ret t op = Ret (t, Some op) + let br l = Br l + let cbr op l1 l2 = Cbr (op, l1, l2) +end + +module Parsing = struct + +let gensym, reset = + let c = ref 0 in + ( fun (s:string) -> incr c; Printf.sprintf "_%s__%d" s (!c) ) + , ( fun () -> c := 0 ) + +end diff --git a/hw6/llprograms/add.ll b/hw6/llprograms/add.ll new file mode 100644 index 0000000..d756f0a --- /dev/null +++ b/hw6/llprograms/add.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + ret i64 %1 +} + diff --git a/hw6/llprograms/add_twice.ll b/hw6/llprograms/add_twice.ll new file mode 100644 index 0000000..221ebe8 --- /dev/null +++ b/hw6/llprograms/add_twice.ll @@ -0,0 +1,6 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = add i64 %1, 15 + ret i64 %2 +} + diff --git a/hw6/llprograms/alloca1.ll b/hw6/llprograms/alloca1.ll new file mode 100644 index 0000000..094ddb6 --- /dev/null +++ b/hw6/llprograms/alloca1.ll @@ -0,0 +1,7 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 17, i64* %1 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/alloca2.ll b/hw6/llprograms/alloca2.ll new file mode 100644 index 0000000..a2504c3 --- /dev/null +++ b/hw6/llprograms/alloca2.ll @@ -0,0 +1,10 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 17, i64* %1 + %2 = alloca i64* + store i64* %1, i64** %2 + %3 = load i64*, i64** %2 + %4 = load i64, i64* %3 + ret i64 %4 +} + diff --git a/hw6/llprograms/analysis1.ll b/hw6/llprograms/analysis1.ll new file mode 100644 index 0000000..647ab45 --- /dev/null +++ b/hw6/llprograms/analysis1.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + br label %l1 +l1: + %4 = bitcast i64* %3 to i8* + ret i64 %1 +} + diff --git a/hw6/llprograms/analysis10.ll b/hw6/llprograms/analysis10.ll new file mode 100644 index 0000000..81f1936 --- /dev/null +++ b/hw6/llprograms/analysis10.ll @@ -0,0 +1,29 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 30, 0 + %2 = sub i64 %1, 24 + %3 = sub i64 9, %2 + %4 = alloca i64 + store i64 %3, i64* %4 + %5 = load i64, i64* %4 + %6 = mul i64 %3, 4 + %7 = alloca i64 + store i64 %6, i64* %7 + %8 = load i64, i64* %7 + %9 = icmp sgt i64 %6, 10 + br i1 %9, label %then, label %else +then: + %10 = load i64, i64* %7 + %11 = sub i64 %10, 10 + store i64 %11, i64* %7 + br label %merge +else: + %12 = load i64, i64* %7 + %13 = add i64 %12, 10 + store i64 %13, i64* %7 + br label %merge +merge: + %14 = load i64, i64* %7 + %15 = sub i64 60, %1 + %16 = mul i64 %14, %15 + ret i64 %16 +} diff --git a/hw6/llprograms/analysis10_cf_opt.ll b/hw6/llprograms/analysis10_cf_opt.ll new file mode 100644 index 0000000..b609b9d --- /dev/null +++ b/hw6/llprograms/analysis10_cf_opt.ll @@ -0,0 +1,30 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 30, 0 + %2 = sub i64 30, 24 + %3 = sub i64 9, 6 + %4 = alloca i64 + store i64 3, i64* %4 + %5 = load i64, i64* %4 + %6 = mul i64 3, 4 + %7 = alloca i64 + store i64 12, i64* %7 + %8 = load i64, i64* %7 + %9 = icmp sgt i64 12, 10 + br i1 1, label %then, label %else +else: + %12 = load i64, i64* %7 + %13 = add i64 %12, 10 + store i64 %13, i64* %7 + br label %merge +merge: + %14 = load i64, i64* %7 + %15 = sub i64 60, 30 + %16 = mul i64 %14, 30 + ret i64 %16 +then: + %10 = load i64, i64* %7 + %11 = sub i64 %10, 10 + store i64 %11, i64* %7 + br label %merge +} + diff --git a/hw6/llprograms/analysis10_dce_opt.ll b/hw6/llprograms/analysis10_dce_opt.ll new file mode 100644 index 0000000..d04dcb3 --- /dev/null +++ b/hw6/llprograms/analysis10_dce_opt.ll @@ -0,0 +1,22 @@ +define i64 @program(i64 %argc, i8** %argv) { + %4 = alloca i64 + store i64 3, i64* %4 + %7 = alloca i64 + store i64 12, i64* %7 + br i1 1, label %then, label %else +else: + %12 = load i64, i64* %7 + %13 = add i64 %12, 10 + store i64 %13, i64* %7 + br label %merge +merge: + %14 = load i64, i64* %7 + %16 = mul i64 %14, 30 + ret i64 %16 +then: + %10 = load i64, i64* %7 + %11 = sub i64 %10, 10 + store i64 %11, i64* %7 + br label %merge +} + diff --git a/hw6/llprograms/analysis11.ll b/hw6/llprograms/analysis11.ll new file mode 100644 index 0000000..e2dd5c9 --- /dev/null +++ b/hw6/llprograms/analysis11.ll @@ -0,0 +1,18 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 0, 1 + %2 = add i64 0, 2 + %3 = add i64 %1, %2 + ret i64 %3 + +foo: + %4 = alloca i64 + store i64 1, i64* %4 + %5 = alloca i64 + store i64 2, i64* %5 + %6 = load i64, i64* %4 + %7 = load i64, i64* %5 + %8 = add i64 %6, %7 + %9 = add i64 %8, 10 + ret i64 %9 +} + diff --git a/hw6/llprograms/analysis11_cf_opt.ll b/hw6/llprograms/analysis11_cf_opt.ll new file mode 100644 index 0000000..27a4c3f --- /dev/null +++ b/hw6/llprograms/analysis11_cf_opt.ll @@ -0,0 +1,17 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 0, 1 + %2 = add i64 0, 2 + %3 = add i64 1, 2 + ret i64 3 +foo: + %4 = alloca i64 + store i64 1, i64* %4 + %5 = alloca i64 + store i64 2, i64* %5 + %6 = load i64, i64* %4 + %7 = load i64, i64* %5 + %8 = add i64 %6, %7 + %9 = add i64 %8, 10 + ret i64 %9 +} + diff --git a/hw6/llprograms/analysis11_dce_opt.ll b/hw6/llprograms/analysis11_dce_opt.ll new file mode 100644 index 0000000..d507937 --- /dev/null +++ b/hw6/llprograms/analysis11_dce_opt.ll @@ -0,0 +1,14 @@ +define i64 @program(i64 %argc, i8** %argv) { + ret i64 3 +foo: + %4 = alloca i64 + store i64 1, i64* %4 + %5 = alloca i64 + store i64 2, i64* %5 + %6 = load i64, i64* %4 + %7 = load i64, i64* %5 + %8 = add i64 %6, %7 + %9 = add i64 %8, 10 + ret i64 %9 +} + diff --git a/hw6/llprograms/analysis12.ll b/hw6/llprograms/analysis12.ll new file mode 100644 index 0000000..6644bbb --- /dev/null +++ b/hw6/llprograms/analysis12.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = sub i64 %1, 15 + %3 = mul i64 %2, %2 + %4 = shl i64 %3, 1 + %5 = lshr i64 %4, %1 + %6 = ashr i64 %5, 3 + %7 = and i64 %2, %1 + %8 = or i64 %5, %7 + %9 = xor i64 %1, %5 + ret i64 %9 +} + diff --git a/hw6/llprograms/analysis12_cf_opt.ll b/hw6/llprograms/analysis12_cf_opt.ll new file mode 100644 index 0000000..d81a195 --- /dev/null +++ b/hw6/llprograms/analysis12_cf_opt.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = sub i64 14, 15 + %3 = mul i64 -1, -1 + %4 = shl i64 1, 1 + %5 = lshr i64 2, 14 + %6 = ashr i64 0, 3 + %7 = and i64 -1, 14 + %8 = or i64 0, 14 + %9 = xor i64 14, 0 + ret i64 14 +} + diff --git a/hw6/llprograms/analysis12_dce_opt.ll b/hw6/llprograms/analysis12_dce_opt.ll new file mode 100644 index 0000000..23cdedb --- /dev/null +++ b/hw6/llprograms/analysis12_dce_opt.ll @@ -0,0 +1,4 @@ +define i64 @program(i64 %argc, i8** %arcv) { + ret i64 14 +} + diff --git a/hw6/llprograms/analysis13.ll b/hw6/llprograms/analysis13.ll new file mode 100644 index 0000000..c1417ab --- /dev/null +++ b/hw6/llprograms/analysis13.ll @@ -0,0 +1,31 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 0, 0 + %2 = add i64 0, 1 + %3 = add i64 0, 2 + %4 = add i64 0, 3 + %5 = add i64 0, 4 + %6 = add i64 0, 5 + %7 = add i64 0, 7 + %cmp1 = icmp sgt i64 3, 0 + br i1 %cmp1, label %one, label %wrong +one: + %cmp2 = icmp eq i64 1, %2 + br i1 %cmp2, label %two, label %wrong +two: + %cmp3 = icmp ne i64 %3, 3 + br i1 %cmp3, label %three, label %wrong +three: + %cmp4 = icmp slt i64 %4, 4 + br i1 %cmp4, label %four, label %wrong +four: + %cmp5 = icmp sle i64 %5, 10 + br i1 %cmp5, label %five, label %wrong +five: + %cmp6 = icmp sge i64 10, %6 + br i1 %cmp6, label %correct, label %wrong +correct: + ret i64 %7 +wrong: + ret i64 %1 +} + diff --git a/hw6/llprograms/analysis13_cf_opt.ll b/hw6/llprograms/analysis13_cf_opt.ll new file mode 100644 index 0000000..f79b7db --- /dev/null +++ b/hw6/llprograms/analysis13_cf_opt.ll @@ -0,0 +1,31 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 0, 0 + %2 = add i64 0, 1 + %3 = add i64 0, 2 + %4 = add i64 0, 3 + %5 = add i64 0, 4 + %6 = add i64 0, 5 + %7 = add i64 0, 7 + %cmp1 = icmp sgt i64 3, 0 + br i1 1, label %one, label %wrong +correct: + ret i64 7 +five: + %cmp6 = icmp sge i64 10, 5 + br i1 1, label %correct, label %wrong +four: + %cmp5 = icmp sle i64 4, 10 + br i1 1, label %five, label %wrong +one: + %cmp2 = icmp eq i64 1, 1 + br i1 1, label %two, label %wrong +three: + %cmp4 = icmp slt i64 3, 4 + br i1 1, label %four, label %wrong +two: + %cmp3 = icmp ne i64 2, 3 + br i1 1, label %three, label %wrong +wrong: + ret i64 0 +} + diff --git a/hw6/llprograms/analysis13_dce_opt.ll b/hw6/llprograms/analysis13_dce_opt.ll new file mode 100644 index 0000000..069f538 --- /dev/null +++ b/hw6/llprograms/analysis13_dce_opt.ll @@ -0,0 +1,18 @@ +define i64 @program(i64 %argc, i8** %arcv) { + br i1 1, label %one, label %wrong +correct: + ret i64 7 +five: + br i1 1, label %correct, label %wrong +four: + br i1 1, label %five, label %wrong +one: + br i1 1, label %two, label %wrong +three: + br i1 1, label %four, label %wrong +two: + br i1 1, label %three, label %wrong +wrong: + ret i64 0 +} + diff --git a/hw6/llprograms/analysis14.ll b/hw6/llprograms/analysis14.ll new file mode 100644 index 0000000..5758d8b --- /dev/null +++ b/hw6/llprograms/analysis14.ll @@ -0,0 +1,8 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = bitcast i64* %1 to i8* + %3 = mul i64 1, 2 + %4 = icmp slt i64 2, %3 + ret i64 42 +} + diff --git a/hw6/llprograms/analysis14_cf_opt.ll b/hw6/llprograms/analysis14_cf_opt.ll new file mode 100644 index 0000000..edc56e6 --- /dev/null +++ b/hw6/llprograms/analysis14_cf_opt.ll @@ -0,0 +1,8 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = bitcast i64* %1 to i8* + %3 = mul i64 1, 2 + %4 = icmp slt i64 2, 2 + ret i64 42 +} + diff --git a/hw6/llprograms/analysis14_dce_opt.ll b/hw6/llprograms/analysis14_dce_opt.ll new file mode 100644 index 0000000..fa93007 --- /dev/null +++ b/hw6/llprograms/analysis14_dce_opt.ll @@ -0,0 +1,5 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + ret i64 42 +} + diff --git a/hw6/llprograms/analysis15.ll b/hw6/llprograms/analysis15.ll new file mode 100644 index 0000000..34828a2 --- /dev/null +++ b/hw6/llprograms/analysis15.ll @@ -0,0 +1,18 @@ +%node = type { i64, %node* } + +@hd = global %node { i64 1, %node* @md } +@md = global %node { i64 2, %node* @tl } +@tl = global %node { i64 3, %node* null } + +define i64 @program(i64 %argc, i8** %arcv) { + %head = getelementptr %node, %node* @hd, i32 0, i32 0 + %link = getelementptr %node, %node* @hd, i32 0, i32 1 + %next = load %node*, %node** %link + %val = getelementptr %node, %node* %next, i32 0, i32 0 + %link2 = getelementptr %node, %node* %next, i32 0, i32 1 + %next2 = load %node*, %node** %link2 + %val2 = getelementptr %node, %node* %next2, i32 0, i32 0 + %1 = load i64, i64* %val + ret i64 %1 +} + diff --git a/hw6/llprograms/analysis15_cf_opt.ll b/hw6/llprograms/analysis15_cf_opt.ll new file mode 100644 index 0000000..34828a2 --- /dev/null +++ b/hw6/llprograms/analysis15_cf_opt.ll @@ -0,0 +1,18 @@ +%node = type { i64, %node* } + +@hd = global %node { i64 1, %node* @md } +@md = global %node { i64 2, %node* @tl } +@tl = global %node { i64 3, %node* null } + +define i64 @program(i64 %argc, i8** %arcv) { + %head = getelementptr %node, %node* @hd, i32 0, i32 0 + %link = getelementptr %node, %node* @hd, i32 0, i32 1 + %next = load %node*, %node** %link + %val = getelementptr %node, %node* %next, i32 0, i32 0 + %link2 = getelementptr %node, %node* %next, i32 0, i32 1 + %next2 = load %node*, %node** %link2 + %val2 = getelementptr %node, %node* %next2, i32 0, i32 0 + %1 = load i64, i64* %val + ret i64 %1 +} + diff --git a/hw6/llprograms/analysis15_dce_opt.ll b/hw6/llprograms/analysis15_dce_opt.ll new file mode 100644 index 0000000..cd7139a --- /dev/null +++ b/hw6/llprograms/analysis15_dce_opt.ll @@ -0,0 +1,16 @@ +%node = type { i64, %node* } + +@hd = global %node { i64 1, %node* @md } +@md = global %node { i64 2, %node* @tl } +@tl = global %node { i64 3, %node* null } + +define i64 @program(i64 %argc, i8** %arcv) { + %link = getelementptr %node, %node* @hd, i32 0, i32 1 + %next = load %node*, %node** %link + %val = getelementptr %node, %node* %next, i32 0, i32 0 + %link2 = getelementptr %node, %node* %next, i32 0, i32 1 + %next2 = load %node*, %node** %link2 + %1 = load i64, i64* %val + ret i64 %1 +} + diff --git a/hw6/llprograms/analysis16.ll b/hw6/llprograms/analysis16.ll new file mode 100644 index 0000000..57c77cd --- /dev/null +++ b/hw6/llprograms/analysis16.ll @@ -0,0 +1,40 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = alloca i64 + store i64 6, i64* %1 + store i64 7, i64* %2 + br label %foo + +foo: + %3 = load i64, i64* %1 + %4 = icmp eq i64 0, %3 + br i1 %4, label %retb, label %loop + +loop: + %5 = load i64, i64* %2 + %6 = icmp eq i64 0, %5 + br i1 %6, label %reta, label %continue_loop + +continue_loop: + %7 = load i64, i64* %1 + %8 = icmp sgt i64 %7, %5 + br i1 %8, label %if, label %else + +if: + %9 = sub i64 %7, %5 + store i64 %9, i64* %1 + br label %loop + +else: + %10 = sub i64 %5, %7 + store i64 %10, i64* %2 + br label %loop + +reta: + %11 = load i64, i64* %1 + ret i64 %11 + +retb: + %12 = load i64, i64* %2 + ret i64 %12 +} diff --git a/hw6/llprograms/analysis16_cf_opt.ll b/hw6/llprograms/analysis16_cf_opt.ll new file mode 100644 index 0000000..17f23b4 --- /dev/null +++ b/hw6/llprograms/analysis16_cf_opt.ll @@ -0,0 +1,34 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = alloca i64 + store i64 6, i64* %1 + store i64 7, i64* %2 + br label %foo +continue_loop: + %7 = load i64, i64* %1 + %8 = icmp sgt i64 %7, %5 + br i1 %8, label %if, label %else +else: + %10 = sub i64 %5, %7 + store i64 %10, i64* %2 + br label %loop +foo: + %3 = load i64, i64* %1 + %4 = icmp eq i64 0, %3 + br i1 %4, label %retb, label %loop +if: + %9 = sub i64 %7, %5 + store i64 %9, i64* %1 + br label %loop +loop: + %5 = load i64, i64* %2 + %6 = icmp eq i64 0, %5 + br i1 %6, label %reta, label %continue_loop +reta: + %11 = load i64, i64* %1 + ret i64 %11 +retb: + %12 = load i64, i64* %2 + ret i64 %12 +} + diff --git a/hw6/llprograms/analysis16_dce_opt.ll b/hw6/llprograms/analysis16_dce_opt.ll new file mode 100644 index 0000000..17f23b4 --- /dev/null +++ b/hw6/llprograms/analysis16_dce_opt.ll @@ -0,0 +1,34 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = alloca i64 + store i64 6, i64* %1 + store i64 7, i64* %2 + br label %foo +continue_loop: + %7 = load i64, i64* %1 + %8 = icmp sgt i64 %7, %5 + br i1 %8, label %if, label %else +else: + %10 = sub i64 %5, %7 + store i64 %10, i64* %2 + br label %loop +foo: + %3 = load i64, i64* %1 + %4 = icmp eq i64 0, %3 + br i1 %4, label %retb, label %loop +if: + %9 = sub i64 %7, %5 + store i64 %9, i64* %1 + br label %loop +loop: + %5 = load i64, i64* %2 + %6 = icmp eq i64 0, %5 + br i1 %6, label %reta, label %continue_loop +reta: + %11 = load i64, i64* %1 + ret i64 %11 +retb: + %12 = load i64, i64* %2 + ret i64 %12 +} + diff --git a/hw6/llprograms/analysis17.ll b/hw6/llprograms/analysis17.ll new file mode 100644 index 0000000..af31436 --- /dev/null +++ b/hw6/llprograms/analysis17.ll @@ -0,0 +1,19 @@ +define i64 @program(i64 %x, i64 %y) { + %sx = alloca i64 + store i64 %x, i64* %sx + %sy = alloca i64 + store i64 %y, i64* %sy + %i1 = add i64 0, 2 + %i2 = add i64 0, 3 + %v1 = add i64 %x, %y + %v2 = sub i64 %v1, %i1 + %v3 = mul i64 %v2, %i2 + br label %l1 + +l1: + %a1 = alloca i64 + store i64 0, i64* %a1 + %arg1 = add i64 0, 12 + %v4 = call i64 @foo(i64 %arg1, i64 2) + ret i64 %v3 +} diff --git a/hw6/llprograms/analysis17_cf_opt.ll b/hw6/llprograms/analysis17_cf_opt.ll new file mode 100644 index 0000000..6a4c124 --- /dev/null +++ b/hw6/llprograms/analysis17_cf_opt.ll @@ -0,0 +1,19 @@ +define i64 @program(i64 %x, i64 %y) { + %sx = alloca i64 + store i64 %x, i64* %sx + %sy = alloca i64 + store i64 %y, i64* %sy + %i1 = add i64 0, 2 + %i2 = add i64 0, 3 + %v1 = add i64 %x, %y + %v2 = sub i64 %v1, 2 + %v3 = mul i64 %v2, 3 + br label %l1 +l1: + %a1 = alloca i64 + store i64 0, i64* %a1 + %arg1 = add i64 0, 12 + %v4 = call i64 @foo(i64 12, i64 2) + ret i64 %v3 +} + diff --git a/hw6/llprograms/analysis17_dce_opt.ll b/hw6/llprograms/analysis17_dce_opt.ll new file mode 100644 index 0000000..189147b --- /dev/null +++ b/hw6/llprograms/analysis17_dce_opt.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %x, i64 %y) { + %sx = alloca i64 + %sy = alloca i64 + %v1 = add i64 %x, %y + %v2 = sub i64 %v1, 2 + %v3 = mul i64 %v2, 3 + br label %l1 +l1: + %a1 = alloca i64 + %v4 = call i64 @foo(i64 12, i64 2) + ret i64 %v3 +} + diff --git a/hw6/llprograms/analysis18.ll b/hw6/llprograms/analysis18.ll new file mode 100644 index 0000000..b457be7 --- /dev/null +++ b/hw6/llprograms/analysis18.ll @@ -0,0 +1,24 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = add i64 5, 9 + %3 = mul i64 3, %2 + %4 = sub i64 %3, 2 + br label %bar +bar: + %sa = alloca i64 + %sb = alloca i64 + %sc = alloca i64 + store i64 %2, i64* %sa + store i64 %3, i64* %sb + store i64 %4, i64* %sb + br label %foo +foo: + %v1 = load i64, i64* %sa + %v2 = load i64, i64* %sa + %v3 = load i64, i64* %sa + %v4 = add i64 %v1, %v2 + %res = add i64 %v4, %v3 + store i64 %res, i64* %1 + ret i64 %res +} + diff --git a/hw6/llprograms/analysis18_cf_opt.ll b/hw6/llprograms/analysis18_cf_opt.ll new file mode 100644 index 0000000..5564a61 --- /dev/null +++ b/hw6/llprograms/analysis18_cf_opt.ll @@ -0,0 +1,24 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = add i64 5, 9 + %3 = mul i64 3, 14 + %4 = sub i64 42, 2 + br label %bar +bar: + %sa = alloca i64 + %sb = alloca i64 + %sc = alloca i64 + store i64 14, i64* %sa + store i64 42, i64* %sb + store i64 40, i64* %sb + br label %foo +foo: + %v1 = load i64, i64* %sa + %v2 = load i64, i64* %sa + %v3 = load i64, i64* %sa + %v4 = add i64 %v1, %v2 + %res = add i64 %v4, %v3 + store i64 %res, i64* %1 + ret i64 %res +} + diff --git a/hw6/llprograms/analysis18_dce_opt.ll b/hw6/llprograms/analysis18_dce_opt.ll new file mode 100644 index 0000000..9a09371 --- /dev/null +++ b/hw6/llprograms/analysis18_dce_opt.ll @@ -0,0 +1,18 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + br label %bar +bar: + %sa = alloca i64 + %sb = alloca i64 + store i64 14, i64* %sa + store i64 42, i64* %sb + br label %foo +foo: + %v1 = load i64, i64* %sa + %v2 = load i64, i64* %sa + %v3 = load i64, i64* %sa + %v4 = add i64 %v1, %v2 + %res = add i64 %v4, %v3 + ret i64 %res +} + diff --git a/hw6/llprograms/analysis19.ll b/hw6/llprograms/analysis19.ll new file mode 100644 index 0000000..e00f40f --- /dev/null +++ b/hw6/llprograms/analysis19.ll @@ -0,0 +1,11 @@ +%arr = type [5 x i64] + +@tmp = global %arr [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = getelementptr %arr, %arr* @tmp, i32 0, i32 3 + %3 = load i64, i64* %1 + ret i64 5 +} + diff --git a/hw6/llprograms/analysis19_cf_opt.ll b/hw6/llprograms/analysis19_cf_opt.ll new file mode 100644 index 0000000..e00f40f --- /dev/null +++ b/hw6/llprograms/analysis19_cf_opt.ll @@ -0,0 +1,11 @@ +%arr = type [5 x i64] + +@tmp = global %arr [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = getelementptr %arr, %arr* @tmp, i32 0, i32 3 + %3 = load i64, i64* %1 + ret i64 5 +} + diff --git a/hw6/llprograms/analysis19_dce_opt.ll b/hw6/llprograms/analysis19_dce_opt.ll new file mode 100644 index 0000000..572127c --- /dev/null +++ b/hw6/llprograms/analysis19_dce_opt.ll @@ -0,0 +1,9 @@ +%arr = type [5 x i64] + +@tmp = global %arr [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = alloca i64 + ret i64 5 +} + diff --git a/hw6/llprograms/analysis1_cf_opt.ll b/hw6/llprograms/analysis1_cf_opt.ll new file mode 100644 index 0000000..39d9d9a --- /dev/null +++ b/hw6/llprograms/analysis1_cf_opt.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + br label %l1 +l1: + %4 = bitcast i64* %3 to i8* + ret i64 49 +} + diff --git a/hw6/llprograms/analysis1_dce_opt.ll b/hw6/llprograms/analysis1_dce_opt.ll new file mode 100644 index 0000000..2b8c08c --- /dev/null +++ b/hw6/llprograms/analysis1_dce_opt.ll @@ -0,0 +1,7 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %3 = alloca i64 + br label %l1 +l1: + ret i64 49 +} + diff --git a/hw6/llprograms/analysis2.ll b/hw6/llprograms/analysis2.ll new file mode 100644 index 0000000..28107a7 --- /dev/null +++ b/hw6/llprograms/analysis2.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + %4 = icmp eq i64 0, %1 + br i1 %4, label %l1, label %l2 +l1: + %5 = bitcast i64* %3 to i8* + ret i64 %1 +l2: + ret i64 8 +} + diff --git a/hw6/llprograms/analysis2_cf_opt.ll b/hw6/llprograms/analysis2_cf_opt.ll new file mode 100644 index 0000000..8612b3b --- /dev/null +++ b/hw6/llprograms/analysis2_cf_opt.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + %4 = icmp eq i64 0, 49 + br i1 0, label %l1, label %l2 +l1: + %5 = bitcast i64* %3 to i8* + ret i64 49 +l2: + ret i64 8 +} + diff --git a/hw6/llprograms/analysis2_dce_opt.ll b/hw6/llprograms/analysis2_dce_opt.ll new file mode 100644 index 0000000..a61d6b6 --- /dev/null +++ b/hw6/llprograms/analysis2_dce_opt.ll @@ -0,0 +1,9 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %3 = alloca i64 + br i1 0, label %l1, label %l2 +l1: + ret i64 49 +l2: + ret i64 8 +} + diff --git a/hw6/llprograms/analysis3.ll b/hw6/llprograms/analysis3.ll new file mode 100644 index 0000000..0cfbf69 --- /dev/null +++ b/hw6/llprograms/analysis3.ll @@ -0,0 +1,31 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 7, 7 + br label %l2 +l2: + %2 = mul i64 2, %1 + br label %l3 +l3: + %3 = sub i64 %2, 32 + br label %l4 +l4: + %4 = shl i64 %3, 1 + br label %l5 +l5: + %5 = lshr i64 %4, 60 + br label %l6 +l6: + %6 = ashr i64 %5, 2 + br label %l7 +l7: + %7 = and i64 255, %6 + br label %l8 +l8: + %8 = or i64 64, %7 + br label %l9 +l9: + %9 = xor i64 %8, 255 + br label %lexit +lexit: + ret i64 %9 +} + diff --git a/hw6/llprograms/analysis3_cf_opt.ll b/hw6/llprograms/analysis3_cf_opt.ll new file mode 100644 index 0000000..9e77cce --- /dev/null +++ b/hw6/llprograms/analysis3_cf_opt.ll @@ -0,0 +1,31 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 7, 7 + br label %l2 +l2: + %2 = mul i64 2, 14 + br label %l3 +l3: + %3 = sub i64 28, 32 + br label %l4 +l4: + %4 = shl i64 -4, 1 + br label %l5 +l5: + %5 = lshr i64 -8, 60 + br label %l6 +l6: + %6 = ashr i64 15, 2 + br label %l7 +l7: + %7 = and i64 255, 3 + br label %l8 +l8: + %8 = or i64 64, 3 + br label %l9 +l9: + %9 = xor i64 67, 255 + br label %lexit +lexit: + ret i64 188 +} + diff --git a/hw6/llprograms/analysis3_dce_opt.ll b/hw6/llprograms/analysis3_dce_opt.ll new file mode 100644 index 0000000..bb98a0a --- /dev/null +++ b/hw6/llprograms/analysis3_dce_opt.ll @@ -0,0 +1,22 @@ +define i64 @program(i64 %argc, i8** %arcv) { + br label %l2 +l2: + br label %l3 +l3: + br label %l4 +l4: + br label %l5 +l5: + br label %l6 +l6: + br label %l7 +l7: + br label %l8 +l8: + br label %l9 +l9: + br label %lexit +lexit: + ret i64 188 +} + diff --git a/hw6/llprograms/analysis4.ll b/hw6/llprograms/analysis4.ll new file mode 100644 index 0000000..9b97230 --- /dev/null +++ b/hw6/llprograms/analysis4.ll @@ -0,0 +1,20 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + store i64 %1, i64* %3 + br label %l1 +l1: + %4 = icmp sle i64 64, %2 + %5 = load i64, i64* %3 + %6 = bitcast i64* %3 to i8* + %7 = getelementptr i8, i8* %6, i32 0 + %8 = sub i64 %5, 3 + store i64 %8, i64* %3 + %9 = icmp sgt i64 %8, 0 + br i1 %9, label %l1, label %l2 +l2: + %10 = load i64, i64* %3 + ret i64 %10 +} + diff --git a/hw6/llprograms/analysis4_cf_opt.ll b/hw6/llprograms/analysis4_cf_opt.ll new file mode 100644 index 0000000..89fe0a1 --- /dev/null +++ b/hw6/llprograms/analysis4_cf_opt.ll @@ -0,0 +1,20 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = mul i64 7, 7 + %2 = add i64 42, %argc + %3 = alloca i64 + store i64 49, i64* %3 + br label %l1 +l1: + %4 = icmp sle i64 64, %2 + %5 = load i64, i64* %3 + %6 = bitcast i64* %3 to i8* + %7 = getelementptr i8, i8* %6, i32 0 + %8 = sub i64 %5, 3 + store i64 %8, i64* %3 + %9 = icmp sgt i64 %8, 0 + br i1 %9, label %l1, label %l2 +l2: + %10 = load i64, i64* %3 + ret i64 %10 +} + diff --git a/hw6/llprograms/analysis4_dce_opt.ll b/hw6/llprograms/analysis4_dce_opt.ll new file mode 100644 index 0000000..570d406 --- /dev/null +++ b/hw6/llprograms/analysis4_dce_opt.ll @@ -0,0 +1,17 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %2 = add i64 42, %argc + %3 = alloca i64 + store i64 49, i64* %3 + br label %l1 +l1: + %5 = load i64, i64* %3 + %6 = bitcast i64* %3 to i8* + %8 = sub i64 %5, 3 + store i64 %8, i64* %3 + %9 = icmp sgt i64 %8, 0 + br i1 %9, label %l1, label %l2 +l2: + %10 = load i64, i64* %3 + ret i64 %10 +} + diff --git a/hw6/llprograms/analysis5.ll b/hw6/llprograms/analysis5.ll new file mode 100644 index 0000000..e6a57d5 --- /dev/null +++ b/hw6/llprograms/analysis5.ll @@ -0,0 +1,7 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 5, 2 + %2 = add i64 2, 5 + %3 = mul i64 %1, 2 + ret i64 %3 +} + diff --git a/hw6/llprograms/analysis5_cf_opt.ll b/hw6/llprograms/analysis5_cf_opt.ll new file mode 100644 index 0000000..eb0adae --- /dev/null +++ b/hw6/llprograms/analysis5_cf_opt.ll @@ -0,0 +1,7 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 5, 2 + %2 = add i64 2, 5 + %3 = mul i64 7, 2 + ret i64 14 +} + diff --git a/hw6/llprograms/analysis5_dce_opt.ll b/hw6/llprograms/analysis5_dce_opt.ll new file mode 100644 index 0000000..a704f22 --- /dev/null +++ b/hw6/llprograms/analysis5_dce_opt.ll @@ -0,0 +1,4 @@ +define i64 @program(i64 %argc, i8** %argv) { + ret i64 14 +} + diff --git a/hw6/llprograms/analysis6.ll b/hw6/llprograms/analysis6.ll new file mode 100644 index 0000000..efd68c3 --- /dev/null +++ b/hw6/llprograms/analysis6.ll @@ -0,0 +1,13 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 2, 0 + %2 = add i64 3, 0 + %3 = add i64 4, 0 + br i1 0, label %then, label %else +then: + ret i64 %1 +else: + %4 = sub i64 %3, %2 + br i1 %4, label %then, label %merge +merge: + ret i64 %3 +} diff --git a/hw6/llprograms/analysis6_cf_opt.ll b/hw6/llprograms/analysis6_cf_opt.ll new file mode 100644 index 0000000..2c65ca2 --- /dev/null +++ b/hw6/llprograms/analysis6_cf_opt.ll @@ -0,0 +1,14 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 2, 0 + %2 = add i64 3, 0 + %3 = add i64 4, 0 + br i1 0, label %then, label %else +else: + %4 = sub i64 4, 3 + br i1 1, label %then, label %merge +merge: + ret i64 4 +then: + ret i64 2 +} + diff --git a/hw6/llprograms/analysis6_dce_opt.ll b/hw6/llprograms/analysis6_dce_opt.ll new file mode 100644 index 0000000..d85fe9f --- /dev/null +++ b/hw6/llprograms/analysis6_dce_opt.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %argv) { + br i1 0, label %then, label %else +else: + br i1 1, label %then, label %merge +merge: + ret i64 4 +then: + ret i64 2 +} + diff --git a/hw6/llprograms/analysis7.ll b/hw6/llprograms/analysis7.ll new file mode 100644 index 0000000..2778021 --- /dev/null +++ b/hw6/llprograms/analysis7.ll @@ -0,0 +1,21 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 10, 0 + %2 = alloca i64 + store i64 %1, i64* %2 + %3 = add i64 1, 0 + %4 = alloca i64 + store i64 %3, i64* %4 + br label %guard +guard: + %5 = load i64, i64* %4 + %6 = icmp slt i64 %5, %1 + br i1 %6, label %body, label %end +body: + %7 = load i64, i64* %4 + %8 = mul i64 %7, 2 + store i64 %8, i64* %4 + br label %guard +end: + ret i64 %1 +} + diff --git a/hw6/llprograms/analysis7_cf_opt.ll b/hw6/llprograms/analysis7_cf_opt.ll new file mode 100644 index 0000000..c074c9d --- /dev/null +++ b/hw6/llprograms/analysis7_cf_opt.ll @@ -0,0 +1,21 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 10, 0 + %2 = alloca i64 + store i64 10, i64* %2 + %3 = add i64 1, 0 + %4 = alloca i64 + store i64 1, i64* %4 + br label %guard +body: + %7 = load i64, i64* %4 + %8 = mul i64 %7, 2 + store i64 %8, i64* %4 + br label %guard +end: + ret i64 10 +guard: + %5 = load i64, i64* %4 + %6 = icmp slt i64 %5, 10 + br i1 %6, label %body, label %end +} + diff --git a/hw6/llprograms/analysis7_dce_opt.ll b/hw6/llprograms/analysis7_dce_opt.ll new file mode 100644 index 0000000..b26f4c1 --- /dev/null +++ b/hw6/llprograms/analysis7_dce_opt.ll @@ -0,0 +1,18 @@ +define i64 @program(i64 %argc, i8** %argv) { + %2 = alloca i64 + %4 = alloca i64 + store i64 1, i64* %4 + br label %guard +body: + %7 = load i64, i64* %4 + %8 = mul i64 %7, 2 + store i64 %8, i64* %4 + br label %guard +end: + ret i64 10 +guard: + %5 = load i64, i64* %4 + %6 = icmp slt i64 %5, 10 + br i1 %6, label %body, label %end +} + diff --git a/hw6/llprograms/analysis8.ll b/hw6/llprograms/analysis8.ll new file mode 100644 index 0000000..abc9f0b --- /dev/null +++ b/hw6/llprograms/analysis8.ll @@ -0,0 +1,33 @@ +define i64 @program(i64 %argc, i8** %argv) { + %a = add i64 1, 0 + %b = add i64 2, %a + %c = add i64 3, %b + %d = add i64 4, %c + %e = add i64 5, %d + %f = add i64 6, %e + %g = add i64 7, %f + %h = add i64 8, %g + %i = add i64 9, %h + %j = add i64 10, %i + %k = add i64 11, %j + %l = add i64 12, %k + %m = add i64 13, %l + %tmp1 = alloca i64 + store i64 %m, i64* %tmp1 + %tmp2 = load i64, i64* %tmp1 + %n = add i64 14, %tmp2 + %o = add i64 15, %n + %p = add i64 16, %o + %q = add i64 17, %p + %r = add i64 18, %q + %s = add i64 19, %r + %t = add i64 20, %s + %u = add i64 21, %t + %v = add i64 22, %u + %w = add i64 23, %v + %x = add i64 24, %w + %y = add i64 25, %x + %z = add i64 26, %y + ret i64 %z +} + diff --git a/hw6/llprograms/analysis8_cf_opt.ll b/hw6/llprograms/analysis8_cf_opt.ll new file mode 100644 index 0000000..48171fc --- /dev/null +++ b/hw6/llprograms/analysis8_cf_opt.ll @@ -0,0 +1,33 @@ +define i64 @program(i64 %argc, i8** %argv) { + %a = add i64 1, 0 + %b = add i64 2, 1 + %c = add i64 3, 3 + %d = add i64 4, 6 + %e = add i64 5, 10 + %f = add i64 6, 15 + %g = add i64 7, 21 + %h = add i64 8, 28 + %i = add i64 9, 36 + %j = add i64 10, 45 + %k = add i64 11, 55 + %l = add i64 12, 66 + %m = add i64 13, 78 + %tmp1 = alloca i64 + store i64 91, i64* %tmp1 + %tmp2 = load i64, i64* %tmp1 + %n = add i64 14, %tmp2 + %o = add i64 15, %n + %p = add i64 16, %o + %q = add i64 17, %p + %r = add i64 18, %q + %s = add i64 19, %r + %t = add i64 20, %s + %u = add i64 21, %t + %v = add i64 22, %u + %w = add i64 23, %v + %x = add i64 24, %w + %y = add i64 25, %x + %z = add i64 26, %y + ret i64 %z +} + diff --git a/hw6/llprograms/analysis8_dce_opt.ll b/hw6/llprograms/analysis8_dce_opt.ll new file mode 100644 index 0000000..6e47a26 --- /dev/null +++ b/hw6/llprograms/analysis8_dce_opt.ll @@ -0,0 +1,20 @@ +define i64 @program(i64 %argc, i8** %argv) { + %tmp1 = alloca i64 + store i64 91, i64* %tmp1 + %tmp2 = load i64, i64* %tmp1 + %n = add i64 14, %tmp2 + %o = add i64 15, %n + %p = add i64 16, %o + %q = add i64 17, %p + %r = add i64 18, %q + %s = add i64 19, %r + %t = add i64 20, %s + %u = add i64 21, %t + %v = add i64 22, %u + %w = add i64 23, %v + %x = add i64 24, %w + %y = add i64 25, %x + %z = add i64 26, %y + ret i64 %z +} + diff --git a/hw6/llprograms/analysis9.ll b/hw6/llprograms/analysis9.ll new file mode 100644 index 0000000..b642407 --- /dev/null +++ b/hw6/llprograms/analysis9.ll @@ -0,0 +1,27 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = alloca i64 + store i64 5, i64* %1 + %2 = alloca i64 + store i64 1, i64* %2 + %d0 = add i64 0, 1 + br label %guard +guard: + %3 = load i64, i64* %2 + %4 = icmp sle i64 %3, 10 + %d1 = add i64 %d0, 4 + br i1 %4, label %body, label %end +body: + %5 = load i64, i64* %2 + %6 = load i64, i64* %1 + %d2 = add i64 %d1, 6 + %7 = mul i64 %5, %6 + store i64 %7, i64* %1 + %8 = load i64, i64* %2 + %9 = add i64 %8, 1 + store i64 %9, i64* %2 + br label %guard +end: + %10 = load i64, i64* %1 + ret i64 %10 +} + diff --git a/hw6/llprograms/analysis9_cf_opt.ll b/hw6/llprograms/analysis9_cf_opt.ll new file mode 100644 index 0000000..60f889e --- /dev/null +++ b/hw6/llprograms/analysis9_cf_opt.ll @@ -0,0 +1,27 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = alloca i64 + store i64 5, i64* %1 + %2 = alloca i64 + store i64 1, i64* %2 + %d0 = add i64 0, 1 + br label %guard +body: + %5 = load i64, i64* %2 + %6 = load i64, i64* %1 + %d2 = add i64 5, 6 + %7 = mul i64 %5, %6 + store i64 %7, i64* %1 + %8 = load i64, i64* %2 + %9 = add i64 %8, 1 + store i64 %9, i64* %2 + br label %guard +end: + %10 = load i64, i64* %1 + ret i64 %10 +guard: + %3 = load i64, i64* %2 + %4 = icmp sle i64 %3, 10 + %d1 = add i64 1, 4 + br i1 %4, label %body, label %end +} + diff --git a/hw6/llprograms/analysis9_dce_opt.ll b/hw6/llprograms/analysis9_dce_opt.ll new file mode 100644 index 0000000..b61e5b5 --- /dev/null +++ b/hw6/llprograms/analysis9_dce_opt.ll @@ -0,0 +1,24 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = alloca i64 + store i64 5, i64* %1 + %2 = alloca i64 + store i64 1, i64* %2 + br label %guard +body: + %5 = load i64, i64* %2 + %6 = load i64, i64* %1 + %7 = mul i64 %5, %6 + store i64 %7, i64* %1 + %8 = load i64, i64* %2 + %9 = add i64 %8, 1 + store i64 %9, i64* %2 + br label %guard +end: + %10 = load i64, i64* %1 + ret i64 %10 +guard: + %3 = load i64, i64* %2 + %4 = icmp sle i64 %3, 10 + br i1 %4, label %body, label %end +} + diff --git a/hw6/llprograms/and.ll b/hw6/llprograms/and.ll new file mode 100644 index 0000000..a0a9db3 --- /dev/null +++ b/hw6/llprograms/and.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = and i64 1, 0 + ret i64 %1 +} diff --git a/hw6/llprograms/args1.ll b/hw6/llprograms/args1.ll new file mode 100644 index 0000000..add1db8 --- /dev/null +++ b/hw6/llprograms/args1.ll @@ -0,0 +1,27 @@ +@toofew = global [9 x i8] c"argc < 3\00" +@toomany = global [9 x i8] c"argc > 3\00" + +define i64 @main(i64 %argc, i8** %argv) { + %lt = icmp slt i64 %argc, 3 + br i1 %lt, label %few, label %else +few: + %1 = getelementptr [9 x i8], [9 x i8]* @toofew, i32 0, i32 0 + call void @ll_puts(i8* %1) + ret i64 0 +else: + %gt = icmp sgt i64 %argc, 3 + br i1 %gt, label %many, label %right +many: + %2 = getelementptr [9 x i8], [9 x i8]* @toomany, i32 0, i32 0 + call void @ll_puts(i8* %2) + ret i64 0 +right: + %3 = getelementptr i8*, i8** %argv, i32 1 + %4 = load i8*, i8** %3 + %5 = getelementptr i8*, i8** %argv, i32 2 + %6 = load i8*, i8** %5 + %7 = call i8* @ll_strcat(i8* %4, i8* %6) + call void @ll_puts(i8* %7) + ret i64 0 +} + diff --git a/hw6/llprograms/arith_combo.ll b/hw6/llprograms/arith_combo.ll new file mode 100644 index 0000000..bc2db51 --- /dev/null +++ b/hw6/llprograms/arith_combo.ll @@ -0,0 +1,7 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = mul i64 3, 6 + %3 = sub i64 %2, %1 + ret i64 %3 +} + diff --git a/hw6/llprograms/arith_combo_dce.ll b/hw6/llprograms/arith_combo_dce.ll new file mode 100644 index 0000000..7d3690a --- /dev/null +++ b/hw6/llprograms/arith_combo_dce.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + ret i64 4 +} + diff --git a/hw6/llprograms/arith_combo_fold.ll b/hw6/llprograms/arith_combo_fold.ll new file mode 100644 index 0000000..a3fef90 --- /dev/null +++ b/hw6/llprograms/arith_combo_fold.ll @@ -0,0 +1,7 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = mul i64 3, 6 + %3 = sub i64 18, 14 + ret i64 4 +} + diff --git a/hw6/llprograms/ashr.ll b/hw6/llprograms/ashr.ll new file mode 100644 index 0000000..11bdee3 --- /dev/null +++ b/hw6/llprograms/ashr.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = ashr i64 42, 3 + ret i64 %1 +} + diff --git a/hw6/llprograms/ashu_ian_opt.ll b/hw6/llprograms/ashu_ian_opt.ll new file mode 100644 index 0000000..dcbadf3 --- /dev/null +++ b/hw6/llprograms/ashu_ian_opt.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %arcv) { + br i1 1, label %then22, label %else21 +else21: + br label %merge20 +merge20: + ret i64 -1 +then22: + ret i64 5 +} + diff --git a/hw6/llprograms/binary_gcd.ll b/hw6/llprograms/binary_gcd.ll new file mode 100644 index 0000000..1b9e155 --- /dev/null +++ b/hw6/llprograms/binary_gcd.ll @@ -0,0 +1,62 @@ +define i64 @binary_gcd(i64 %u, i64 %v) { + %u_eq_v = icmp eq i64 %u, %v + br i1 %u_eq_v, label %ret_u, label %term1 +term1: + %u_0 = icmp eq i64 0, %u + br i1 %u_0, label %ret_v, label %term2 +term2: + %v_0 = icmp eq i64 0, %v + br i1 %v_0, label %ret_u, label %gcd +gcd: + %neg1 = sub i64 0, 1 + %1 = xor i64 %neg1, %u + %2 = and i64 1, %1 + %3 = icmp ne i64 0, %2 + br i1 %3, label %u_even, label %u_odd +u_odd: + %4 = xor i64 %neg1, %v + %5 = and i64 1, %4 + %6 = icmp ne i64 0, %5 + br i1 %6, label %v_even, label %v_odd +v_odd: + %7 = icmp sgt i64 %u, %v + br i1 %7, label %u_gt, label %v_gt +v_gt: + %8 = sub i64 %v, %u + %9 = lshr i64 %8, 1 + %10 = call i64 @binary_gcd(i64 %9, i64 %u) + ret i64 %10 +u_gt: + %11 = sub i64 %u, %v + %12 = lshr i64 %11, 1 + %13 = call i64 @binary_gcd(i64 %12, i64 %v) + ret i64 %13 +v_even: + %14 = lshr i64 %v, 1 + %15 = call i64 @binary_gcd(i64 %u, i64 %14) + ret i64 %15 +u_even: + %16 = and i64 %v, 1 + %17 = icmp ne i64 0, %16 + br i1 %17, label %ue_vo, label %both_even +ue_vo: + %18 = lshr i64 %u, 1 + %19 = call i64 @binary_gcd(i64 %18, i64 %v) + ret i64 %19 +both_even: + %20 = lshr i64 %u, 1 + %21 = lshr i64 %v, 1 + %22 = call i64 @binary_gcd(i64 %20, i64 %21) + %23 = shl i64 %22, 1 + ret i64 %23 +ret_u: + ret i64 %u +ret_v: + ret i64 %v +} + +define i64 @main(i64 %argc, i8** %argv) { + %1 = call i64 @binary_gcd(i64 21, i64 15) + ret i64 %1 +} + diff --git a/hw6/llprograms/binarysearch.ll b/hw6/llprograms/binarysearch.ll new file mode 100644 index 0000000..7fd7d58 --- /dev/null +++ b/hw6/llprograms/binarysearch.ll @@ -0,0 +1,74 @@ +%struct.Node = type { %struct.Node*, %struct.Node*, i64 } + +@node1 = global %struct.Node { %struct.Node* @node2, %struct.Node* @node3, i64 50 } +@node2 = global %struct.Node { %struct.Node* @node4, %struct.Node* @node5, i64 25 } +@node3 = global %struct.Node { %struct.Node* @node6, %struct.Node* @node7, i64 75 } +@node4 = global %struct.Node { %struct.Node* @node8, %struct.Node* null, i64 10 } +@node5 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 30 } +@node6 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 60 } +@node7 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 80 } +@node8 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 1 } + +define i64 @contains(%struct.Node* %root, i64 %value) { + %1 = getelementptr %struct.Node, %struct.Node* %root, i32 0, i32 2 + %2 = load i64, i64* %1 + %3 = icmp eq i64 %2, %value + br i1 %3, label %equal, label %notequal +equal: + ret i64 1 +notequal: + %4 = icmp sgt i64 %2, %value + br i1 %4, label %left, label %right +left: + %5 = getelementptr %struct.Node, %struct.Node* %root, i32 0, i32 0 + %6 = load %struct.Node*, %struct.Node** %5 + %7 = icmp eq %struct.Node* %6, null + br i1 %7, label %none, label %left_next +left_next: + %8 = call i64 @contains(%struct.Node* %6, i64 %value) + ret i64 %8 +right: + %9 = getelementptr %struct.Node, %struct.Node* %root, i32 0, i32 1 + %10 = load %struct.Node*, %struct.Node** %9 + %11 = icmp eq %struct.Node* %10, null + br i1 %11, label %none, label %right_next +right_next: + %12 = call i64 @contains(%struct.Node* %10, i64 %value) + ret i64 %12 +none: + ret i64 0 +} + +define i64 @main(i64 %argc, i8** %argv) { + %1 = add i64 50, 0 + %2 = add i64 25, 0 + %3 = add i64 75, 0 + %4 = add i64 10, 0 + %5 = add i64 30, 0 + %6 = add i64 60, 0 + %7 = add i64 80, 0 + %8 = add i64 1, 0 + %9 = add i64 100, 0 + %10 = add i64 120, 0 + %11 = call i64 @contains(%struct.Node* @node1, i64 %1) + %12 = call i64 @contains(%struct.Node* @node1, i64 %2) + %13 = call i64 @contains(%struct.Node* @node1, i64 %3) + %14 = call i64 @contains(%struct.Node* @node1, i64 %4) + %15 = call i64 @contains(%struct.Node* @node1, i64 %5) + %16 = call i64 @contains(%struct.Node* @node1, i64 %6) + %17 = call i64 @contains(%struct.Node* @node1, i64 %7) + %18 = call i64 @contains(%struct.Node* @node1, i64 %8) + %19 = call i64 @contains(%struct.Node* @node1, i64 %9) + %20 = call i64 @contains(%struct.Node* @node1, i64 %10) + %21 = add i64 %11, %12 + %22 = add i64 %13, %14 + %23 = add i64 %15, %16 + %24 = add i64 %17, %18 + %25 = add i64 %19, %20 + %26 = add i64 %21, %22 + %27 = add i64 %23, %24 + %28 = add i64 %26, %27 + %29 = add i64 %28, %25 + ret i64 %29 +} + diff --git a/hw6/llprograms/bitcast1.ll b/hw6/llprograms/bitcast1.ll new file mode 100644 index 0000000..b508167 --- /dev/null +++ b/hw6/llprograms/bitcast1.ll @@ -0,0 +1,9 @@ +define i64 @main(i64 %argc, i8** %argv) { + %1 = alloca i64 + store i64 3, i64* %1 + %2 = bitcast i64* %1 to [10 x i64]* + %3 = bitcast [10 x i64]* %2 to i64* + %4 = load i64, i64* %3 + ret i64 %4 +} + diff --git a/hw6/llprograms/br1.ll b/hw6/llprograms/br1.ll new file mode 100644 index 0000000..d3a81c8 --- /dev/null +++ b/hw6/llprograms/br1.ll @@ -0,0 +1,6 @@ +define i64 @main(i64 %argc, i8** %arcv) { + br label %end +end: + ret i64 9 +} + diff --git a/hw6/llprograms/br2.ll b/hw6/llprograms/br2.ll new file mode 100644 index 0000000..159e478 --- /dev/null +++ b/hw6/llprograms/br2.ll @@ -0,0 +1,9 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 12 + br label %next +next: + br label %end +end: + ret i64 %1 +} + diff --git a/hw6/llprograms/c_weighted_sum.c b/hw6/llprograms/c_weighted_sum.c new file mode 100644 index 0000000..8e581be --- /dev/null +++ b/hw6/llprograms/c_weighted_sum.c @@ -0,0 +1,15 @@ +#include + +int64_t ll_weighted_sum(int64_t a1, int64_t a2, int64_t a3, int64_t a4, + int64_t a5, int64_t a6, int64_t a7, int64_t a8) { + int64_t sum = 0; + sum += a1 * 1; + sum += a2 * 2; + sum += a3 * 3; + sum += a4 * 4; + sum += a5 * 5; + sum += a6 * 6; + sum += a7 * 7; + sum += a8 * 8; + return sum; +} diff --git a/hw6/llprograms/call.ll b/hw6/llprograms/call.ll new file mode 100644 index 0000000..92e025f --- /dev/null +++ b/hw6/llprograms/call.ll @@ -0,0 +1,9 @@ +define i64 @foo() { + ret i64 42 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo() + ret i64 %1 +} + diff --git a/hw6/llprograms/call1.ll b/hw6/llprograms/call1.ll new file mode 100644 index 0000000..e2785ee --- /dev/null +++ b/hw6/llprograms/call1.ll @@ -0,0 +1,9 @@ +define i64 @foo(i64 %x) { + ret i64 %x +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 17) + ret i64 %1 +} + diff --git a/hw6/llprograms/call2.ll b/hw6/llprograms/call2.ll new file mode 100644 index 0000000..10226cc --- /dev/null +++ b/hw6/llprograms/call2.ll @@ -0,0 +1,10 @@ +define i64 @foo(i64 %x) { + ret i64 %x +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 17) + %2 = call i64 @foo(i64 19) + ret i64 %2 +} + diff --git a/hw6/llprograms/call3.ll b/hw6/llprograms/call3.ll new file mode 100644 index 0000000..e0dd5a0 --- /dev/null +++ b/hw6/llprograms/call3.ll @@ -0,0 +1,10 @@ +define i64 @foo(i64 %x) { + %1 = add i64 %x, %x + ret i64 %1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 17) + ret i64 %1 +} + diff --git a/hw6/llprograms/call4.ll b/hw6/llprograms/call4.ll new file mode 100644 index 0000000..20511e6 --- /dev/null +++ b/hw6/llprograms/call4.ll @@ -0,0 +1,15 @@ +define i64 @bar(i64 %x, i64 %y) { + %1 = add i64 %x, %y + ret i64 %1 +} + +define i64 @foo(i64 %x) { + %1 = call i64 @bar(i64 %x, i64 %x) + ret i64 %1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 17) + ret i64 %1 +} + diff --git a/hw6/llprograms/call5.ll b/hw6/llprograms/call5.ll new file mode 100644 index 0000000..3d6ad68 --- /dev/null +++ b/hw6/llprograms/call5.ll @@ -0,0 +1,21 @@ +define i64 @bar(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + %1 = add i64 %x1, %x2 + %2 = add i64 %1, %x3 + %3 = add i64 %2, %x4 + %4 = add i64 %3, %x5 + %5 = add i64 %4, %x6 + %6 = add i64 %5, %x7 + %7 = add i64 %6, %x8 + ret i64 %7 +} + +define i64 @foo(i64 %x) { + %1 = call i64 @bar(i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x) + ret i64 %1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 3) + ret i64 %1 +} + diff --git a/hw6/llprograms/call6.ll b/hw6/llprograms/call6.ll new file mode 100644 index 0000000..4194e2f --- /dev/null +++ b/hw6/llprograms/call6.ll @@ -0,0 +1,34 @@ +define i64 @baz(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + %1 = add i64 %x1, %x2 + %2 = add i64 %1, %x3 + %3 = add i64 %2, %x4 + %4 = add i64 %3, %x5 + %5 = add i64 %4, %x6 + %6 = add i64 %5, %x7 + %7 = add i64 %6, %x8 + ret i64 %7 +} + +define i64 @bar(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + %1 = add i64 %x1, %x2 + %2 = add i64 %1, %x3 + %3 = add i64 %2, %x4 + %4 = add i64 %3, %x5 + %tmp = call i64 @baz(i64 %1, i64 %2, i64 %3, i64 %4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) + %5 = add i64 %4, %x6 + %6 = add i64 %5, %x7 + %7 = add i64 %6, %x8 + %8 = add i64 %7, %tmp + ret i64 %8 +} + +define i64 @foo(i64 %x) { + %1 = call i64 @bar(i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x) + ret i64 %1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 1) + ret i64 %1 +} + diff --git a/hw6/llprograms/call7.ll b/hw6/llprograms/call7.ll new file mode 100644 index 0000000..38a594e --- /dev/null +++ b/hw6/llprograms/call7.ll @@ -0,0 +1,9 @@ +define i64 @bar(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + ret i64 %x7 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @bar(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8) + ret i64 %1 +} + diff --git a/hw6/llprograms/call8.ll b/hw6/llprograms/call8.ll new file mode 100644 index 0000000..bf26331 --- /dev/null +++ b/hw6/llprograms/call8.ll @@ -0,0 +1,21 @@ +define i64 @foo(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + ret i64 %x6 +} + +define i64 @bar(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + ret i64 %x7 +} + +define i64 @baz(i64 %x1, i64 %x2, i64 %x3, i64 %x4, i64 %x5, i64 %x6, i64 %x7, i64 %x8) { + ret i64 %x8 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @foo(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8) + %2 = call i64 @bar(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8) + %3 = call i64 @baz(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8) + %4 = add i64 %1, %2 + %5 = add i64 %4, %3 + ret i64 %5 +} + diff --git a/hw6/llprograms/callback1.ll b/hw6/llprograms/callback1.ll new file mode 100644 index 0000000..55101c9 --- /dev/null +++ b/hw6/llprograms/callback1.ll @@ -0,0 +1,17 @@ +%fty = type i64 (i64, i64) + +define i64 @foo(i64 %x, i64 %y) { + %1 = alloca i64 + %2 = add i64 %x, %y + store i64 %2, i64* %1 + %3 = load i64, i64* %1 + ret i64 %3 +} + +define i64 @main(i64 %argc, i8** %argv) { + %1 = call i64 @ll_callback(%fty* @foo) + %2 = call i8* @ll_ltoa(i64 %1) + call void @ll_puts(i8* %2) + ret i64 0 +} + diff --git a/hw6/llprograms/cbr.ll b/hw6/llprograms/cbr.ll new file mode 100644 index 0000000..0038776 --- /dev/null +++ b/hw6/llprograms/cbr.ll @@ -0,0 +1,29 @@ +define i64 @foo() { + ret i64 42 +} + +define i64 @bar() { + ret i64 0 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %y = alloca i64 + store i64 0, i64* %1 + store i64 100, i64* %y + %2 = load i64, i64* %y + %3 = icmp ne i64 %2, 0 + br i1 %3, label %then, label %else +then: + %4 = call i64 @foo() + store i64 %4, i64* %1 + br label %end +else: + %5 = call i64 @bar() + store i64 %5, i64* %1 + br label %end +end: + %6 = load i64, i64* %1 + ret i64 %6 +} + diff --git a/hw6/llprograms/cbr1.ll b/hw6/llprograms/cbr1.ll new file mode 100644 index 0000000..f27e509 --- /dev/null +++ b/hw6/llprograms/cbr1.ll @@ -0,0 +1,9 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %cmp = icmp sgt i64 3, 0 + br i1 %cmp, label %then, label %else +then: + ret i64 7 +else: + ret i64 9 +} + diff --git a/hw6/llprograms/cbr2.ll b/hw6/llprograms/cbr2.ll new file mode 100644 index 0000000..e52e9f0 --- /dev/null +++ b/hw6/llprograms/cbr2.ll @@ -0,0 +1,9 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %cmp = icmp slt i64 3, 0 + br i1 %cmp, label %then, label %else +then: + ret i64 7 +else: + ret i64 9 +} + diff --git a/hw6/llprograms/cbr3.ll b/hw6/llprograms/cbr3.ll new file mode 100644 index 0000000..89a8496 --- /dev/null +++ b/hw6/llprograms/cbr3.ll @@ -0,0 +1,8 @@ +define i64 @main(i64 %argc, i8** %arcv) { + br i1 0, label %then, label %else +then: + ret i64 7 +else: + ret i64 9 +} + diff --git a/hw6/llprograms/certified_random_number_generator.ll b/hw6/llprograms/certified_random_number_generator.ll new file mode 100644 index 0000000..42aeb61 --- /dev/null +++ b/hw6/llprograms/certified_random_number_generator.ll @@ -0,0 +1,29 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %p_lfsr = alloca i64 + %start = add i64 8, 0 + store i64 %start, i64* %p_lfsr + br label %loop +loop: + %iter = load i64, i64* %p_lfsr + %inc = add i64 %iter, 1 + store i64 %inc, i64* %p_lfsr + br label %lfsr_step +lfsr_step: + %x15 = lshr i64 46421, 0 + %x13 = lshr i64 46421, 2 + %x12 = lshr i64 46421, 3 + %x10 = lshr i64 46421, 5 + %bit1 = xor i64 %x15, %x13 + %bit2 = xor i64 %bit1, %x12 + %bit3 = xor i64 %bit2, %x10 + %bit4 = and i64 %bit3, 1 + %lfsr1 = lshr i64 8, 1 + %lfsr2 = shl i64 %bit4, 15 + %lfsr3 = or i64 %lfsr1, %lfsr2 + store i64 %lfsr3, i64* %p_lfsr + br label %loop_end +loop_end: + %lfsr = load i64, i64* %p_lfsr + ret i64 %lfsr +} + diff --git a/hw6/llprograms/certified_random_number_generator_soln.ll b/hw6/llprograms/certified_random_number_generator_soln.ll new file mode 100644 index 0000000..35ecea5 --- /dev/null +++ b/hw6/llprograms/certified_random_number_generator_soln.ll @@ -0,0 +1,17 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %p_lfsr = alloca i64 + store i64 8, i64* %p_lfsr + br label %loop +loop: + %iter = load i64, i64* %p_lfsr + %inc = add i64 %iter, 1 + store i64 %inc, i64* %p_lfsr + br label %lfsr_step +lfsr_step: + store i64 4, i64* %p_lfsr + br label %loop_end +loop_end: + %lfsr = load i64, i64* %p_lfsr + ret i64 %lfsr +} + diff --git a/hw6/llprograms/euclid.ll b/hw6/llprograms/euclid.ll new file mode 100644 index 0000000..e668ae9 --- /dev/null +++ b/hw6/llprograms/euclid.ll @@ -0,0 +1,23 @@ +define i64 @gcd_rec(i64 %a, i64 %b) { + %1 = alloca i64 + store i64 %a, i64* %1 + %cmp = icmp ne i64 %b, 0 + br i1 %cmp, label %neq0, label %eq0 +eq0: + ret i64 %a +neq0: + %2 = load i64, i64* %1 + %3 = sub i64 %2, %b + store i64 %3, i64* %1 + %cmp1 = icmp sgt i64 %3, %b + br i1 %cmp1, label %neq0, label %recurse +recurse: + %4 = call i64 @gcd_rec(i64 %b, i64 %3) + ret i64 %4 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @gcd_rec(i64 424, i64 34) + ret i64 %1 +} + diff --git a/hw6/llprograms/factorial.ll b/hw6/llprograms/factorial.ll new file mode 100644 index 0000000..a6d0199 --- /dev/null +++ b/hw6/llprograms/factorial.ll @@ -0,0 +1,31 @@ +define i64 @factorial(i64 %n) { + %1 = alloca i64 + %acc = alloca i64 + store i64 %n, i64* %1 + store i64 1, i64* %acc + br label %start +start: + %2 = load i64, i64* %1 + %3 = icmp sgt i64 %2, 0 + br i1 %3, label %then, label %end +then: + %4 = load i64, i64* %acc + %5 = load i64, i64* %1 + %6 = mul i64 %4, %5 + store i64 %6, i64* %acc + %7 = load i64, i64* %1 + %8 = sub i64 %7, 1 + store i64 %8, i64* %1 + br label %start +end: + %9 = load i64, i64* %acc + ret i64 %9 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 0, i64* %1 + %2 = call i64 @factorial(i64 5) + ret i64 %2 +} + diff --git a/hw6/llprograms/factrect.ll b/hw6/llprograms/factrect.ll new file mode 100644 index 0000000..cec349c --- /dev/null +++ b/hw6/llprograms/factrect.ll @@ -0,0 +1,17 @@ +define i64 @factorial(i64 %n) { + %cmp = icmp eq i64 %n, 0 + br i1 %cmp, label %ret1, label %recurse +ret1: + ret i64 1 +recurse: + %1 = sub i64 %n, 1 + %2 = call i64 @factorial(i64 %1) + %3 = mul i64 %n, %2 + ret i64 %3 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = call i64 @factorial(i64 5) + ret i64 %1 +} + diff --git a/hw6/llprograms/gcd_euclidian.ll b/hw6/llprograms/gcd_euclidian.ll new file mode 100644 index 0000000..078db71 --- /dev/null +++ b/hw6/llprograms/gcd_euclidian.ll @@ -0,0 +1,34 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = alloca i64 + store i64 8, i64* %1 + store i64 10, i64* %2 + br label %gcd +gcd: + %3 = load i64, i64* %1 + %4 = icmp eq i64 0, %3 + br i1 %4, label %ret_b, label %loop +loop: + %5 = load i64, i64* %2 + %6 = icmp eq i64 0, %5 + br i1 %6, label %ret_a, label %continue_loop +continue_loop: + %7 = load i64, i64* %1 + %8 = icmp sgt i64 %7, %5 + br i1 %8, label %if, label %else +if: + %9 = sub i64 %7, %5 + store i64 %9, i64* %1 + br label %loop +else: + %10 = sub i64 %5, %7 + store i64 %10, i64* %2 + br label %loop +ret_a: + %11 = load i64, i64* %1 + ret i64 %11 +ret_b: + %12 = load i64, i64* %2 + ret i64 %12 +} + diff --git a/hw6/llprograms/gep1.ll b/hw6/llprograms/gep1.ll new file mode 100644 index 0000000..f152480 --- /dev/null +++ b/hw6/llprograms/gep1.ll @@ -0,0 +1,27 @@ +%disju = type { i64, i8* } +%var1 = type { i64, i64* } +%var2 = type { i64, i8** } + +@gint = global i64 42 +@v1 = global %var1 { i64 0, i64* @gint } +@v2 = global %var2 { i64 1, i8** null } +@gstr = global [14 x i8] c"hello, world!\00" + + +define i64 @main(i64 %argc, i8** %argv) { + %p0 = alloca i64 + %p1 = getelementptr %var2, %var2* @v2, i32 0, i32 0 + store i64 5, i64* %p1 + %vb = bitcast %var2* @v2 to %disju* + call void @foo(%disju* %vb) + %n1 = load i64, i64* %p1 + ret i64 %n1 +} + +define void @foo(%disju* %pu) { + %p1 = getelementptr %disju, %disju* %pu, i32 0, i32 0 + store i64 6, i64* %p1 + %n1 = load i64, i64* %p1 + ret void +} + diff --git a/hw6/llprograms/gep10.ll b/hw6/llprograms/gep10.ll new file mode 100644 index 0000000..8879abc --- /dev/null +++ b/hw6/llprograms/gep10.ll @@ -0,0 +1,11 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 0, %argc + %2 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i64 %1 + %3 = load i64, i64* %2 + ret i64 %3 +} + diff --git a/hw6/llprograms/gep2.ll b/hw6/llprograms/gep2.ll new file mode 100644 index 0000000..3a63b46 --- /dev/null +++ b/hw6/llprograms/gep2.ll @@ -0,0 +1,11 @@ +%arr = type [5 x i64] + +@tmp = global %arr [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + %2 = getelementptr %arr, %arr* @tmp, i32 0, i32 3 + %3 = load i64, i64* %2 + ret i64 %3 +} + diff --git a/hw6/llprograms/gep3.ll b/hw6/llprograms/gep3.ll new file mode 100644 index 0000000..56b822d --- /dev/null +++ b/hw6/llprograms/gep3.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 0 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/gep4.ll b/hw6/llprograms/gep4.ll new file mode 100644 index 0000000..db1a688 --- /dev/null +++ b/hw6/llprograms/gep4.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i32 0 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/gep5.ll b/hw6/llprograms/gep5.ll new file mode 100644 index 0000000..621ee23 --- /dev/null +++ b/hw6/llprograms/gep5.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i32 2 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/gep6.ll b/hw6/llprograms/gep6.ll new file mode 100644 index 0000000..f7ad620 --- /dev/null +++ b/hw6/llprograms/gep6.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 2 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/gep7.ll b/hw6/llprograms/gep7.ll new file mode 100644 index 0000000..6e5870f --- /dev/null +++ b/hw6/llprograms/gep7.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i32 5 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/gep8.ll b/hw6/llprograms/gep8.ll new file mode 100644 index 0000000..c85ad27 --- /dev/null +++ b/hw6/llprograms/gep8.ll @@ -0,0 +1,11 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 0, 0 + %2 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i64 %1 + %3 = load i64, i64* %2 + ret i64 %3 +} + diff --git a/hw6/llprograms/gep9.ll b/hw6/llprograms/gep9.ll new file mode 100644 index 0000000..287e0a2 --- /dev/null +++ b/hw6/llprograms/gep9.ll @@ -0,0 +1,10 @@ +%struct = type { i64, [5 x i64], i64 } + +@gbl = global %struct { i64 1, [5 x i64] [ i64 2, i64 3, i64 4, i64 5, i64 6 ], i64 7 } + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = getelementptr %struct, %struct* @gbl, i32 0, i32 1, i32 3 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/global1.ll b/hw6/llprograms/global1.ll new file mode 100644 index 0000000..f1f1d38 --- /dev/null +++ b/hw6/llprograms/global1.ll @@ -0,0 +1,7 @@ +@gbl = global i64 12 + +define i64 @main(i64 %argc, i8** %arcv) { + %1 = load i64, i64* @gbl + ret i64 %1 +} + diff --git a/hw6/llprograms/helloworld.ll b/hw6/llprograms/helloworld.ll new file mode 100644 index 0000000..34721ef --- /dev/null +++ b/hw6/llprograms/helloworld.ll @@ -0,0 +1,8 @@ +@gstr = global [14 x i8] c"hello, world!\00" + +define i64 @main(i64 %argc, i8** %argv) { + %1 = getelementptr [14 x i8], [14 x i8]* @gstr, i32 0, i32 0 + call void @ll_puts(i8* %1) + ret i64 0 +} + diff --git a/hw6/llprograms/kaiterry_pi.ll b/hw6/llprograms/kaiterry_pi.ll new file mode 100644 index 0000000..98c447d --- /dev/null +++ b/hw6/llprograms/kaiterry_pi.ll @@ -0,0 +1,2011 @@ +define i64 @main(i64 %argc, i8** %argv) { + %x0 = add i64 0, 0 + %x1 = add i64 %x0, 1000000000000 + %x2 = sub i64 %x1, 333333333333 + %x3 = add i64 %x2, 200000000000 + %x4 = sub i64 %x3, 142857142857 + %x5 = add i64 %x4, 111111111111 + %x6 = sub i64 %x5, 90909090909 + %x7 = add i64 %x6, 76923076923 + %x8 = sub i64 %x7, 66666666666 + %x9 = add i64 %x8, 58823529411 + %x10 = sub i64 %x9, 52631578947 + %x11 = add i64 %x10, 47619047619 + %x12 = sub i64 %x11, 43478260869 + %x13 = add i64 %x12, 40000000000 + %x14 = sub i64 %x13, 37037037037 + %x15 = add i64 %x14, 34482758620 + %x16 = sub i64 %x15, 32258064516 + %x17 = add i64 %x16, 30303030303 + %x18 = sub i64 %x17, 28571428571 + %x19 = add i64 %x18, 27027027027 + %x20 = sub i64 %x19, 25641025641 + %x21 = add i64 %x20, 24390243902 + %x22 = sub i64 %x21, 23255813953 + %x23 = add i64 %x22, 22222222222 + %x24 = sub i64 %x23, 21276595744 + %x25 = add i64 %x24, 20408163265 + %x26 = sub i64 %x25, 19607843137 + %x27 = add i64 %x26, 18867924528 + %x28 = sub i64 %x27, 18181818181 + %x29 = add i64 %x28, 17543859649 + %x30 = sub i64 %x29, 16949152542 + %x31 = add i64 %x30, 16393442622 + %x32 = sub i64 %x31, 15873015873 + %x33 = add i64 %x32, 15384615384 + %x34 = sub i64 %x33, 14925373134 + %x35 = add i64 %x34, 14492753623 + %x36 = sub i64 %x35, 14084507042 + %x37 = add i64 %x36, 13698630136 + %x38 = sub i64 %x37, 13333333333 + %x39 = add i64 %x38, 12987012987 + %x40 = sub i64 %x39, 12658227848 + %x41 = add i64 %x40, 12345679012 + %x42 = sub i64 %x41, 12048192771 + %x43 = add i64 %x42, 11764705882 + %x44 = sub i64 %x43, 11494252873 + %x45 = add i64 %x44, 11235955056 + %x46 = sub i64 %x45, 10989010989 + %x47 = add i64 %x46, 10752688172 + %x48 = sub i64 %x47, 10526315789 + %x49 = add i64 %x48, 10309278350 + %x50 = sub i64 %x49, 10101010101 + %x51 = add i64 %x50, 9900990099 + %x52 = sub i64 %x51, 9708737864 + %x53 = add i64 %x52, 9523809523 + %x54 = sub i64 %x53, 9345794392 + %x55 = add i64 %x54, 9174311926 + %x56 = sub i64 %x55, 9009009009 + %x57 = add i64 %x56, 8849557522 + %x58 = sub i64 %x57, 8695652173 + %x59 = add i64 %x58, 8547008547 + %x60 = sub i64 %x59, 8403361344 + %x61 = add i64 %x60, 8264462809 + %x62 = sub i64 %x61, 8130081300 + %x63 = add i64 %x62, 8000000000 + %x64 = sub i64 %x63, 7874015748 + %x65 = add i64 %x64, 7751937984 + %x66 = sub i64 %x65, 7633587786 + %x67 = add i64 %x66, 7518796992 + %x68 = sub i64 %x67, 7407407407 + %x69 = add i64 %x68, 7299270072 + %x70 = sub i64 %x69, 7194244604 + %x71 = add i64 %x70, 7092198581 + %x72 = sub i64 %x71, 6993006993 + %x73 = add i64 %x72, 6896551724 + %x74 = sub i64 %x73, 6802721088 + %x75 = add i64 %x74, 6711409395 + %x76 = sub i64 %x75, 6622516556 + %x77 = add i64 %x76, 6535947712 + %x78 = sub i64 %x77, 6451612903 + %x79 = add i64 %x78, 6369426751 + %x80 = sub i64 %x79, 6289308176 + %x81 = add i64 %x80, 6211180124 + %x82 = sub i64 %x81, 6134969325 + %x83 = add i64 %x82, 6060606060 + %x84 = sub i64 %x83, 5988023952 + %x85 = add i64 %x84, 5917159763 + %x86 = sub i64 %x85, 5847953216 + %x87 = add i64 %x86, 5780346820 + %x88 = sub i64 %x87, 5714285714 + %x89 = add i64 %x88, 5649717514 + %x90 = sub i64 %x89, 5586592178 + %x91 = add i64 %x90, 5524861878 + %x92 = sub i64 %x91, 5464480874 + %x93 = add i64 %x92, 5405405405 + %x94 = sub i64 %x93, 5347593582 + %x95 = add i64 %x94, 5291005291 + %x96 = sub i64 %x95, 5235602094 + %x97 = add i64 %x96, 5181347150 + %x98 = sub i64 %x97, 5128205128 + %x99 = add i64 %x98, 5076142131 + %x100 = sub i64 %x99, 5025125628 + %x101 = add i64 %x100, 4975124378 + %x102 = sub i64 %x101, 4926108374 + %x103 = add i64 %x102, 4878048780 + %x104 = sub i64 %x103, 4830917874 + %x105 = add i64 %x104, 4784688995 + %x106 = sub i64 %x105, 4739336492 + %x107 = add i64 %x106, 4694835680 + %x108 = sub i64 %x107, 4651162790 + %x109 = add i64 %x108, 4608294930 + %x110 = sub i64 %x109, 4566210045 + %x111 = add i64 %x110, 4524886877 + %x112 = sub i64 %x111, 4484304932 + %x113 = add i64 %x112, 4444444444 + %x114 = sub i64 %x113, 4405286343 + %x115 = add i64 %x114, 4366812227 + %x116 = sub i64 %x115, 4329004329 + %x117 = add i64 %x116, 4291845493 + %x118 = sub i64 %x117, 4255319148 + %x119 = add i64 %x118, 4219409282 + %x120 = sub i64 %x119, 4184100418 + %x121 = add i64 %x120, 4149377593 + %x122 = sub i64 %x121, 4115226337 + %x123 = add i64 %x122, 4081632653 + %x124 = sub i64 %x123, 4048582995 + %x125 = add i64 %x124, 4016064257 + %x126 = sub i64 %x125, 3984063745 + %x127 = add i64 %x126, 3952569169 + %x128 = sub i64 %x127, 3921568627 + %x129 = add i64 %x128, 3891050583 + %x130 = sub i64 %x129, 3861003861 + %x131 = add i64 %x130, 3831417624 + %x132 = sub i64 %x131, 3802281368 + %x133 = add i64 %x132, 3773584905 + %x134 = sub i64 %x133, 3745318352 + %x135 = add i64 %x134, 3717472118 + %x136 = sub i64 %x135, 3690036900 + %x137 = add i64 %x136, 3663003663 + %x138 = sub i64 %x137, 3636363636 + %x139 = add i64 %x138, 3610108303 + %x140 = sub i64 %x139, 3584229390 + %x141 = add i64 %x140, 3558718861 + %x142 = sub i64 %x141, 3533568904 + %x143 = add i64 %x142, 3508771929 + %x144 = sub i64 %x143, 3484320557 + %x145 = add i64 %x144, 3460207612 + %x146 = sub i64 %x145, 3436426116 + %x147 = add i64 %x146, 3412969283 + %x148 = sub i64 %x147, 3389830508 + %x149 = add i64 %x148, 3367003367 + %x150 = sub i64 %x149, 3344481605 + %x151 = add i64 %x150, 3322259136 + %x152 = sub i64 %x151, 3300330033 + %x153 = add i64 %x152, 3278688524 + %x154 = sub i64 %x153, 3257328990 + %x155 = add i64 %x154, 3236245954 + %x156 = sub i64 %x155, 3215434083 + %x157 = add i64 %x156, 3194888178 + %x158 = sub i64 %x157, 3174603174 + %x159 = add i64 %x158, 3154574132 + %x160 = sub i64 %x159, 3134796238 + %x161 = add i64 %x160, 3115264797 + %x162 = sub i64 %x161, 3095975232 + %x163 = add i64 %x162, 3076923076 + %x164 = sub i64 %x163, 3058103975 + %x165 = add i64 %x164, 3039513677 + %x166 = sub i64 %x165, 3021148036 + %x167 = add i64 %x166, 3003003003 + %x168 = sub i64 %x167, 2985074626 + %x169 = add i64 %x168, 2967359050 + %x170 = sub i64 %x169, 2949852507 + %x171 = add i64 %x170, 2932551319 + %x172 = sub i64 %x171, 2915451895 + %x173 = add i64 %x172, 2898550724 + %x174 = sub i64 %x173, 2881844380 + %x175 = add i64 %x174, 2865329512 + %x176 = sub i64 %x175, 2849002849 + %x177 = add i64 %x176, 2832861189 + %x178 = sub i64 %x177, 2816901408 + %x179 = add i64 %x178, 2801120448 + %x180 = sub i64 %x179, 2785515320 + %x181 = add i64 %x180, 2770083102 + %x182 = sub i64 %x181, 2754820936 + %x183 = add i64 %x182, 2739726027 + %x184 = sub i64 %x183, 2724795640 + %x185 = add i64 %x184, 2710027100 + %x186 = sub i64 %x185, 2695417789 + %x187 = add i64 %x186, 2680965147 + %x188 = sub i64 %x187, 2666666666 + %x189 = add i64 %x188, 2652519893 + %x190 = sub i64 %x189, 2638522427 + %x191 = add i64 %x190, 2624671916 + %x192 = sub i64 %x191, 2610966057 + %x193 = add i64 %x192, 2597402597 + %x194 = sub i64 %x193, 2583979328 + %x195 = add i64 %x194, 2570694087 + %x196 = sub i64 %x195, 2557544757 + %x197 = add i64 %x196, 2544529262 + %x198 = sub i64 %x197, 2531645569 + %x199 = add i64 %x198, 2518891687 + %x200 = sub i64 %x199, 2506265664 + %x201 = add i64 %x200, 2493765586 + %x202 = sub i64 %x201, 2481389578 + %x203 = add i64 %x202, 2469135802 + %x204 = sub i64 %x203, 2457002457 + %x205 = add i64 %x204, 2444987775 + %x206 = sub i64 %x205, 2433090024 + %x207 = add i64 %x206, 2421307506 + %x208 = sub i64 %x207, 2409638554 + %x209 = add i64 %x208, 2398081534 + %x210 = sub i64 %x209, 2386634844 + %x211 = add i64 %x210, 2375296912 + %x212 = sub i64 %x211, 2364066193 + %x213 = add i64 %x212, 2352941176 + %x214 = sub i64 %x213, 2341920374 + %x215 = add i64 %x214, 2331002331 + %x216 = sub i64 %x215, 2320185614 + %x217 = add i64 %x216, 2309468822 + %x218 = sub i64 %x217, 2298850574 + %x219 = add i64 %x218, 2288329519 + %x220 = sub i64 %x219, 2277904328 + %x221 = add i64 %x220, 2267573696 + %x222 = sub i64 %x221, 2257336343 + %x223 = add i64 %x222, 2247191011 + %x224 = sub i64 %x223, 2237136465 + %x225 = add i64 %x224, 2227171492 + %x226 = sub i64 %x225, 2217294900 + %x227 = add i64 %x226, 2207505518 + %x228 = sub i64 %x227, 2197802197 + %x229 = add i64 %x228, 2188183807 + %x230 = sub i64 %x229, 2178649237 + %x231 = add i64 %x230, 2169197396 + %x232 = sub i64 %x231, 2159827213 + %x233 = add i64 %x232, 2150537634 + %x234 = sub i64 %x233, 2141327623 + %x235 = add i64 %x234, 2132196162 + %x236 = sub i64 %x235, 2123142250 + %x237 = add i64 %x236, 2114164904 + %x238 = sub i64 %x237, 2105263157 + %x239 = add i64 %x238, 2096436058 + %x240 = sub i64 %x239, 2087682672 + %x241 = add i64 %x240, 2079002079 + %x242 = sub i64 %x241, 2070393374 + %x243 = add i64 %x242, 2061855670 + %x244 = sub i64 %x243, 2053388090 + %x245 = add i64 %x244, 2044989775 + %x246 = sub i64 %x245, 2036659877 + %x247 = add i64 %x246, 2028397565 + %x248 = sub i64 %x247, 2020202020 + %x249 = add i64 %x248, 2012072434 + %x250 = sub i64 %x249, 2004008016 + %x251 = add i64 %x250, 1996007984 + %x252 = sub i64 %x251, 1988071570 + %x253 = add i64 %x252, 1980198019 + %x254 = sub i64 %x253, 1972386587 + %x255 = add i64 %x254, 1964636542 + %x256 = sub i64 %x255, 1956947162 + %x257 = add i64 %x256, 1949317738 + %x258 = sub i64 %x257, 1941747572 + %x259 = add i64 %x258, 1934235976 + %x260 = sub i64 %x259, 1926782273 + %x261 = add i64 %x260, 1919385796 + %x262 = sub i64 %x261, 1912045889 + %x263 = add i64 %x262, 1904761904 + %x264 = sub i64 %x263, 1897533206 + %x265 = add i64 %x264, 1890359168 + %x266 = sub i64 %x265, 1883239171 + %x267 = add i64 %x266, 1876172607 + %x268 = sub i64 %x267, 1869158878 + %x269 = add i64 %x268, 1862197392 + %x270 = sub i64 %x269, 1855287569 + %x271 = add i64 %x270, 1848428835 + %x272 = sub i64 %x271, 1841620626 + %x273 = add i64 %x272, 1834862385 + %x274 = sub i64 %x273, 1828153564 + %x275 = add i64 %x274, 1821493624 + %x276 = sub i64 %x275, 1814882032 + %x277 = add i64 %x276, 1808318264 + %x278 = sub i64 %x277, 1801801801 + %x279 = add i64 %x278, 1795332136 + %x280 = sub i64 %x279, 1788908765 + %x281 = add i64 %x280, 1782531194 + %x282 = sub i64 %x281, 1776198934 + %x283 = add i64 %x282, 1769911504 + %x284 = sub i64 %x283, 1763668430 + %x285 = add i64 %x284, 1757469244 + %x286 = sub i64 %x285, 1751313485 + %x287 = add i64 %x286, 1745200698 + %x288 = sub i64 %x287, 1739130434 + %x289 = add i64 %x288, 1733102253 + %x290 = sub i64 %x289, 1727115716 + %x291 = add i64 %x290, 1721170395 + %x292 = sub i64 %x291, 1715265866 + %x293 = add i64 %x292, 1709401709 + %x294 = sub i64 %x293, 1703577512 + %x295 = add i64 %x294, 1697792869 + %x296 = sub i64 %x295, 1692047377 + %x297 = add i64 %x296, 1686340640 + %x298 = sub i64 %x297, 1680672268 + %x299 = add i64 %x298, 1675041876 + %x300 = sub i64 %x299, 1669449081 + %x301 = add i64 %x300, 1663893510 + %x302 = sub i64 %x301, 1658374792 + %x303 = add i64 %x302, 1652892561 + %x304 = sub i64 %x303, 1647446457 + %x305 = add i64 %x304, 1642036124 + %x306 = sub i64 %x305, 1636661211 + %x307 = add i64 %x306, 1631321370 + %x308 = sub i64 %x307, 1626016260 + %x309 = add i64 %x308, 1620745542 + %x310 = sub i64 %x309, 1615508885 + %x311 = add i64 %x310, 1610305958 + %x312 = sub i64 %x311, 1605136436 + %x313 = add i64 %x312, 1600000000 + %x314 = sub i64 %x313, 1594896331 + %x315 = add i64 %x314, 1589825119 + %x316 = sub i64 %x315, 1584786053 + %x317 = add i64 %x316, 1579778830 + %x318 = sub i64 %x317, 1574803149 + %x319 = add i64 %x318, 1569858712 + %x320 = sub i64 %x319, 1564945226 + %x321 = add i64 %x320, 1560062402 + %x322 = sub i64 %x321, 1555209953 + %x323 = add i64 %x322, 1550387596 + %x324 = sub i64 %x323, 1545595054 + %x325 = add i64 %x324, 1540832049 + %x326 = sub i64 %x325, 1536098310 + %x327 = add i64 %x326, 1531393568 + %x328 = sub i64 %x327, 1526717557 + %x329 = add i64 %x328, 1522070015 + %x330 = sub i64 %x329, 1517450682 + %x331 = add i64 %x330, 1512859304 + %x332 = sub i64 %x331, 1508295625 + %x333 = add i64 %x332, 1503759398 + %x334 = sub i64 %x333, 1499250374 + %x335 = add i64 %x334, 1494768310 + %x336 = sub i64 %x335, 1490312965 + %x337 = add i64 %x336, 1485884101 + %x338 = sub i64 %x337, 1481481481 + %x339 = add i64 %x338, 1477104874 + %x340 = sub i64 %x339, 1472754050 + %x341 = add i64 %x340, 1468428781 + %x342 = sub i64 %x341, 1464128843 + %x343 = add i64 %x342, 1459854014 + %x344 = sub i64 %x343, 1455604075 + %x345 = add i64 %x344, 1451378809 + %x346 = sub i64 %x345, 1447178002 + %x347 = add i64 %x346, 1443001443 + %x348 = sub i64 %x347, 1438848920 + %x349 = add i64 %x348, 1434720229 + %x350 = sub i64 %x349, 1430615164 + %x351 = add i64 %x350, 1426533523 + %x352 = sub i64 %x351, 1422475106 + %x353 = add i64 %x352, 1418439716 + %x354 = sub i64 %x353, 1414427157 + %x355 = add i64 %x354, 1410437235 + %x356 = sub i64 %x355, 1406469760 + %x357 = add i64 %x356, 1402524544 + %x358 = sub i64 %x357, 1398601398 + %x359 = add i64 %x358, 1394700139 + %x360 = sub i64 %x359, 1390820584 + %x361 = add i64 %x360, 1386962552 + %x362 = sub i64 %x361, 1383125864 + %x363 = add i64 %x362, 1379310344 + %x364 = sub i64 %x363, 1375515818 + %x365 = add i64 %x364, 1371742112 + %x366 = sub i64 %x365, 1367989056 + %x367 = add i64 %x366, 1364256480 + %x368 = sub i64 %x367, 1360544217 + %x369 = add i64 %x368, 1356852103 + %x370 = sub i64 %x369, 1353179972 + %x371 = add i64 %x370, 1349527665 + %x372 = sub i64 %x371, 1345895020 + %x373 = add i64 %x372, 1342281879 + %x374 = sub i64 %x373, 1338688085 + %x375 = add i64 %x374, 1335113484 + %x376 = sub i64 %x375, 1331557922 + %x377 = add i64 %x376, 1328021248 + %x378 = sub i64 %x377, 1324503311 + %x379 = add i64 %x378, 1321003963 + %x380 = sub i64 %x379, 1317523056 + %x381 = add i64 %x380, 1314060446 + %x382 = sub i64 %x381, 1310615989 + %x383 = add i64 %x382, 1307189542 + %x384 = sub i64 %x383, 1303780964 + %x385 = add i64 %x384, 1300390117 + %x386 = sub i64 %x385, 1297016861 + %x387 = add i64 %x386, 1293661060 + %x388 = sub i64 %x387, 1290322580 + %x389 = add i64 %x388, 1287001287 + %x390 = sub i64 %x389, 1283697047 + %x391 = add i64 %x390, 1280409731 + %x392 = sub i64 %x391, 1277139208 + %x393 = add i64 %x392, 1273885350 + %x394 = sub i64 %x393, 1270648030 + %x395 = add i64 %x394, 1267427122 + %x396 = sub i64 %x395, 1264222503 + %x397 = add i64 %x396, 1261034047 + %x398 = sub i64 %x397, 1257861635 + %x399 = add i64 %x398, 1254705144 + %x400 = sub i64 %x399, 1251564455 + %x401 = add i64 %x400, 1248439450 + %x402 = sub i64 %x401, 1245330012 + %x403 = add i64 %x402, 1242236024 + %x404 = sub i64 %x403, 1239157372 + %x405 = add i64 %x404, 1236093943 + %x406 = sub i64 %x405, 1233045622 + %x407 = add i64 %x406, 1230012300 + %x408 = sub i64 %x407, 1226993865 + %x409 = add i64 %x408, 1223990208 + %x410 = sub i64 %x409, 1221001221 + %x411 = add i64 %x410, 1218026796 + %x412 = sub i64 %x411, 1215066828 + %x413 = add i64 %x412, 1212121212 + %x414 = sub i64 %x413, 1209189842 + %x415 = add i64 %x414, 1206272617 + %x416 = sub i64 %x415, 1203369434 + %x417 = add i64 %x416, 1200480192 + %x418 = sub i64 %x417, 1197604790 + %x419 = add i64 %x418, 1194743130 + %x420 = sub i64 %x419, 1191895113 + %x421 = add i64 %x420, 1189060642 + %x422 = sub i64 %x421, 1186239620 + %x423 = add i64 %x422, 1183431952 + %x424 = sub i64 %x423, 1180637544 + %x425 = add i64 %x424, 1177856301 + %x426 = sub i64 %x425, 1175088131 + %x427 = add i64 %x426, 1172332942 + %x428 = sub i64 %x427, 1169590643 + %x429 = add i64 %x428, 1166861143 + %x430 = sub i64 %x429, 1164144353 + %x431 = add i64 %x430, 1161440185 + %x432 = sub i64 %x431, 1158748551 + %x433 = add i64 %x432, 1156069364 + %x434 = sub i64 %x433, 1153402537 + %x435 = add i64 %x434, 1150747986 + %x436 = sub i64 %x435, 1148105625 + %x437 = add i64 %x436, 1145475372 + %x438 = sub i64 %x437, 1142857142 + %x439 = add i64 %x438, 1140250855 + %x440 = sub i64 %x439, 1137656427 + %x441 = add i64 %x440, 1135073779 + %x442 = sub i64 %x441, 1132502831 + %x443 = add i64 %x442, 1129943502 + %x444 = sub i64 %x443, 1127395715 + %x445 = add i64 %x444, 1124859392 + %x446 = sub i64 %x445, 1122334455 + %x447 = add i64 %x446, 1119820828 + %x448 = sub i64 %x447, 1117318435 + %x449 = add i64 %x448, 1114827201 + %x450 = sub i64 %x449, 1112347052 + %x451 = add i64 %x450, 1109877913 + %x452 = sub i64 %x451, 1107419712 + %x453 = add i64 %x452, 1104972375 + %x454 = sub i64 %x453, 1102535832 + %x455 = add i64 %x454, 1100110011 + %x456 = sub i64 %x455, 1097694840 + %x457 = add i64 %x456, 1095290251 + %x458 = sub i64 %x457, 1092896174 + %x459 = add i64 %x458, 1090512540 + %x460 = sub i64 %x459, 1088139281 + %x461 = add i64 %x460, 1085776330 + %x462 = sub i64 %x461, 1083423618 + %x463 = add i64 %x462, 1081081081 + %x464 = sub i64 %x463, 1078748651 + %x465 = add i64 %x464, 1076426264 + %x466 = sub i64 %x465, 1074113856 + %x467 = add i64 %x466, 1071811361 + %x468 = sub i64 %x467, 1069518716 + %x469 = add i64 %x468, 1067235859 + %x470 = sub i64 %x469, 1064962726 + %x471 = add i64 %x470, 1062699256 + %x472 = sub i64 %x471, 1060445387 + %x473 = add i64 %x472, 1058201058 + %x474 = sub i64 %x473, 1055966209 + %x475 = add i64 %x474, 1053740779 + %x476 = sub i64 %x475, 1051524710 + %x477 = add i64 %x476, 1049317943 + %x478 = sub i64 %x477, 1047120418 + %x479 = add i64 %x478, 1044932079 + %x480 = sub i64 %x479, 1042752867 + %x481 = add i64 %x480, 1040582726 + %x482 = sub i64 %x481, 1038421599 + %x483 = add i64 %x482, 1036269430 + %x484 = sub i64 %x483, 1034126163 + %x485 = add i64 %x484, 1031991744 + %x486 = sub i64 %x485, 1029866117 + %x487 = add i64 %x486, 1027749229 + %x488 = sub i64 %x487, 1025641025 + %x489 = add i64 %x488, 1023541453 + %x490 = sub i64 %x489, 1021450459 + %x491 = add i64 %x490, 1019367991 + %x492 = sub i64 %x491, 1017293997 + %x493 = add i64 %x492, 1015228426 + %x494 = sub i64 %x493, 1013171225 + %x495 = add i64 %x494, 1011122345 + %x496 = sub i64 %x495, 1009081735 + %x497 = add i64 %x496, 1007049345 + %x498 = sub i64 %x497, 1005025125 + %x499 = add i64 %x498, 1003009027 + %x500 = sub i64 %x499, 1001001001 + %x501 = add i64 %x500, 999000999 + %x502 = sub i64 %x501, 997008973 + %x503 = add i64 %x502, 995024875 + %x504 = sub i64 %x503, 993048659 + %x505 = add i64 %x504, 991080277 + %x506 = sub i64 %x505, 989119683 + %x507 = add i64 %x506, 987166831 + %x508 = sub i64 %x507, 985221674 + %x509 = add i64 %x508, 983284169 + %x510 = sub i64 %x509, 981354268 + %x511 = add i64 %x510, 979431929 + %x512 = sub i64 %x511, 977517106 + %x513 = add i64 %x512, 975609756 + %x514 = sub i64 %x513, 973709834 + %x515 = add i64 %x514, 971817298 + %x516 = sub i64 %x515, 969932104 + %x517 = add i64 %x516, 968054211 + %x518 = sub i64 %x517, 966183574 + %x519 = add i64 %x518, 964320154 + %x520 = sub i64 %x519, 962463907 + %x521 = add i64 %x520, 960614793 + %x522 = sub i64 %x521, 958772770 + %x523 = add i64 %x522, 956937799 + %x524 = sub i64 %x523, 955109837 + %x525 = add i64 %x524, 953288846 + %x526 = sub i64 %x525, 951474785 + %x527 = add i64 %x526, 949667616 + %x528 = sub i64 %x527, 947867298 + %x529 = add i64 %x528, 946073793 + %x530 = sub i64 %x529, 944287063 + %x531 = add i64 %x530, 942507068 + %x532 = sub i64 %x531, 940733772 + %x533 = add i64 %x532, 938967136 + %x534 = sub i64 %x533, 937207122 + %x535 = add i64 %x534, 935453695 + %x536 = sub i64 %x535, 933706816 + %x537 = add i64 %x536, 931966449 + %x538 = sub i64 %x537, 930232558 + %x539 = add i64 %x538, 928505106 + %x540 = sub i64 %x539, 926784059 + %x541 = add i64 %x540, 925069380 + %x542 = sub i64 %x541, 923361034 + %x543 = add i64 %x542, 921658986 + %x544 = sub i64 %x543, 919963201 + %x545 = add i64 %x544, 918273645 + %x546 = sub i64 %x545, 916590284 + %x547 = add i64 %x546, 914913083 + %x548 = sub i64 %x547, 913242009 + %x549 = add i64 %x548, 911577028 + %x550 = sub i64 %x549, 909918107 + %x551 = add i64 %x550, 908265213 + %x552 = sub i64 %x551, 906618313 + %x553 = add i64 %x552, 904977375 + %x554 = sub i64 %x553, 903342366 + %x555 = add i64 %x554, 901713255 + %x556 = sub i64 %x555, 900090009 + %x557 = add i64 %x556, 898472596 + %x558 = sub i64 %x557, 896860986 + %x559 = add i64 %x558, 895255147 + %x560 = sub i64 %x559, 893655049 + %x561 = add i64 %x560, 892060660 + %x562 = sub i64 %x561, 890471950 + %x563 = add i64 %x562, 888888888 + %x564 = sub i64 %x563, 887311446 + %x565 = add i64 %x564, 885739592 + %x566 = sub i64 %x565, 884173297 + %x567 = add i64 %x566, 882612533 + %x568 = sub i64 %x567, 881057268 + %x569 = add i64 %x568, 879507475 + %x570 = sub i64 %x569, 877963125 + %x571 = add i64 %x570, 876424189 + %x572 = sub i64 %x571, 874890638 + %x573 = add i64 %x572, 873362445 + %x574 = sub i64 %x573, 871839581 + %x575 = add i64 %x574, 870322019 + %x576 = sub i64 %x575, 868809730 + %x577 = add i64 %x576, 867302688 + %x578 = sub i64 %x577, 865800865 + %x579 = add i64 %x578, 864304235 + %x580 = sub i64 %x579, 862812769 + %x581 = add i64 %x580, 861326442 + %x582 = sub i64 %x581, 859845227 + %x583 = add i64 %x582, 858369098 + %x584 = sub i64 %x583, 856898029 + %x585 = add i64 %x584, 855431993 + %x586 = sub i64 %x585, 853970964 + %x587 = add i64 %x586, 852514919 + %x588 = sub i64 %x587, 851063829 + %x589 = add i64 %x588, 849617672 + %x590 = sub i64 %x589, 848176420 + %x591 = add i64 %x590, 846740050 + %x592 = sub i64 %x591, 845308537 + %x593 = add i64 %x592, 843881856 + %x594 = sub i64 %x593, 842459983 + %x595 = add i64 %x594, 841042893 + %x596 = sub i64 %x595, 839630562 + %x597 = add i64 %x596, 838222967 + %x598 = sub i64 %x597, 836820083 + %x599 = add i64 %x598, 835421888 + %x600 = sub i64 %x599, 834028356 + %x601 = add i64 %x600, 832639467 + %x602 = sub i64 %x601, 831255195 + %x603 = add i64 %x602, 829875518 + %x604 = sub i64 %x603, 828500414 + %x605 = add i64 %x604, 827129859 + %x606 = sub i64 %x605, 825763831 + %x607 = add i64 %x606, 824402308 + %x608 = sub i64 %x607, 823045267 + %x609 = add i64 %x608, 821692686 + %x610 = sub i64 %x609, 820344544 + %x611 = add i64 %x610, 819000819 + %x612 = sub i64 %x611, 817661488 + %x613 = add i64 %x612, 816326530 + %x614 = sub i64 %x613, 814995925 + %x615 = add i64 %x614, 813669650 + %x616 = sub i64 %x615, 812347684 + %x617 = add i64 %x616, 811030008 + %x618 = sub i64 %x617, 809716599 + %x619 = add i64 %x618, 808407437 + %x620 = sub i64 %x619, 807102502 + %x621 = add i64 %x620, 805801772 + %x622 = sub i64 %x621, 804505229 + %x623 = add i64 %x622, 803212851 + %x624 = sub i64 %x623, 801924619 + %x625 = add i64 %x624, 800640512 + %x626 = sub i64 %x625, 799360511 + %x627 = add i64 %x626, 798084596 + %x628 = sub i64 %x627, 796812749 + %x629 = add i64 %x628, 795544948 + %x630 = sub i64 %x629, 794281175 + %x631 = add i64 %x630, 793021411 + %x632 = sub i64 %x631, 791765637 + %x633 = add i64 %x632, 790513833 + %x634 = sub i64 %x633, 789265982 + %x635 = add i64 %x634, 788022064 + %x636 = sub i64 %x635, 786782061 + %x637 = add i64 %x636, 785545954 + %x638 = sub i64 %x637, 784313725 + %x639 = add i64 %x638, 783085356 + %x640 = sub i64 %x639, 781860828 + %x641 = add i64 %x640, 780640124 + %x642 = sub i64 %x641, 779423226 + %x643 = add i64 %x642, 778210116 + %x644 = sub i64 %x643, 777000777 + %x645 = add i64 %x644, 775795190 + %x646 = sub i64 %x645, 774593338 + %x647 = add i64 %x646, 773395204 + %x648 = sub i64 %x647, 772200772 + %x649 = add i64 %x648, 771010023 + %x650 = sub i64 %x649, 769822940 + %x651 = add i64 %x650, 768639508 + %x652 = sub i64 %x651, 767459708 + %x653 = add i64 %x652, 766283524 + %x654 = sub i64 %x653, 765110941 + %x655 = add i64 %x654, 763941940 + %x656 = sub i64 %x655, 762776506 + %x657 = add i64 %x656, 761614623 + %x658 = sub i64 %x657, 760456273 + %x659 = add i64 %x658, 759301442 + %x660 = sub i64 %x659, 758150113 + %x661 = add i64 %x660, 757002271 + %x662 = sub i64 %x661, 755857898 + %x663 = add i64 %x662, 754716981 + %x664 = sub i64 %x663, 753579502 + %x665 = add i64 %x664, 752445447 + %x666 = sub i64 %x665, 751314800 + %x667 = add i64 %x666, 750187546 + %x668 = sub i64 %x667, 749063670 + %x669 = add i64 %x668, 747943156 + %x670 = sub i64 %x669, 746825989 + %x671 = add i64 %x670, 745712155 + %x672 = sub i64 %x671, 744601638 + %x673 = add i64 %x672, 743494423 + %x674 = sub i64 %x673, 742390497 + %x675 = add i64 %x674, 741289844 + %x676 = sub i64 %x675, 740192450 + %x677 = add i64 %x676, 739098300 + %x678 = sub i64 %x677, 738007380 + %x679 = add i64 %x678, 736919675 + %x680 = sub i64 %x679, 735835172 + %x681 = add i64 %x680, 734753857 + %x682 = sub i64 %x681, 733675715 + %x683 = add i64 %x682, 732600732 + %x684 = sub i64 %x683, 731528895 + %x685 = add i64 %x684, 730460189 + %x686 = sub i64 %x685, 729394602 + %x687 = add i64 %x686, 728332119 + %x688 = sub i64 %x687, 727272727 + %x689 = add i64 %x688, 726216412 + %x690 = sub i64 %x689, 725163161 + %x691 = add i64 %x690, 724112961 + %x692 = sub i64 %x691, 723065798 + %x693 = add i64 %x692, 722021660 + %x694 = sub i64 %x693, 720980533 + %x695 = add i64 %x694, 719942404 + %x696 = sub i64 %x695, 718907260 + %x697 = add i64 %x696, 717875089 + %x698 = sub i64 %x697, 716845878 + %x699 = add i64 %x698, 715819613 + %x700 = sub i64 %x699, 714796283 + %x701 = add i64 %x700, 713775874 + %x702 = sub i64 %x701, 712758374 + %x703 = add i64 %x702, 711743772 + %x704 = sub i64 %x703, 710732054 + %x705 = add i64 %x704, 709723207 + %x706 = sub i64 %x705, 708717221 + %x707 = add i64 %x706, 707714083 + %x708 = sub i64 %x707, 706713780 + %x709 = add i64 %x708, 705716302 + %x710 = sub i64 %x709, 704721634 + %x711 = add i64 %x710, 703729767 + %x712 = sub i64 %x711, 702740688 + %x713 = add i64 %x712, 701754385 + %x714 = sub i64 %x713, 700770847 + %x715 = add i64 %x714, 699790062 + %x716 = sub i64 %x715, 698812019 + %x717 = add i64 %x716, 697836706 + %x718 = sub i64 %x717, 696864111 + %x719 = add i64 %x718, 695894224 + %x720 = sub i64 %x719, 694927032 + %x721 = add i64 %x720, 693962526 + %x722 = sub i64 %x721, 693000693 + %x723 = add i64 %x722, 692041522 + %x724 = sub i64 %x723, 691085003 + %x725 = add i64 %x724, 690131124 + %x726 = sub i64 %x725, 689179875 + %x727 = add i64 %x726, 688231245 + %x728 = sub i64 %x727, 687285223 + %x729 = add i64 %x728, 686341798 + %x730 = sub i64 %x729, 685400959 + %x731 = add i64 %x730, 684462696 + %x732 = sub i64 %x731, 683526999 + %x733 = add i64 %x732, 682593856 + %x734 = sub i64 %x733, 681663258 + %x735 = add i64 %x734, 680735194 + %x736 = sub i64 %x735, 679809653 + %x737 = add i64 %x736, 678886625 + %x738 = sub i64 %x737, 677966101 + %x739 = add i64 %x738, 677048070 + %x740 = sub i64 %x739, 676132521 + %x741 = add i64 %x740, 675219446 + %x742 = sub i64 %x741, 674308833 + %x743 = add i64 %x742, 673400673 + %x744 = sub i64 %x743, 672494956 + %x745 = add i64 %x744, 671591672 + %x746 = sub i64 %x745, 670690811 + %x747 = add i64 %x746, 669792364 + %x748 = sub i64 %x747, 668896321 + %x749 = add i64 %x748, 668002672 + %x750 = sub i64 %x749, 667111407 + %x751 = add i64 %x750, 666222518 + %x752 = sub i64 %x751, 665335994 + %x753 = add i64 %x752, 664451827 + %x754 = sub i64 %x753, 663570006 + %x755 = add i64 %x754, 662690523 + %x756 = sub i64 %x755, 661813368 + %x757 = add i64 %x756, 660938532 + %x758 = sub i64 %x757, 660066006 + %x759 = add i64 %x758, 659195781 + %x760 = sub i64 %x759, 658327847 + %x761 = add i64 %x760, 657462195 + %x762 = sub i64 %x761, 656598818 + %x763 = add i64 %x762, 655737704 + %x764 = sub i64 %x763, 654878847 + %x765 = add i64 %x764, 654022236 + %x766 = sub i64 %x765, 653167864 + %x767 = add i64 %x766, 652315720 + %x768 = sub i64 %x767, 651465798 + %x769 = add i64 %x768, 650618087 + %x770 = sub i64 %x769, 649772579 + %x771 = add i64 %x770, 648929266 + %x772 = sub i64 %x771, 648088139 + %x773 = add i64 %x772, 647249190 + %x774 = sub i64 %x773, 646412411 + %x775 = add i64 %x774, 645577792 + %x776 = sub i64 %x775, 644745325 + %x777 = add i64 %x776, 643915003 + %x778 = sub i64 %x777, 643086816 + %x779 = add i64 %x778, 642260757 + %x780 = sub i64 %x779, 641436818 + %x781 = add i64 %x780, 640614990 + %x782 = sub i64 %x781, 639795265 + %x783 = add i64 %x782, 638977635 + %x784 = sub i64 %x783, 638162093 + %x785 = add i64 %x784, 637348629 + %x786 = sub i64 %x785, 636537237 + %x787 = add i64 %x786, 635727908 + %x788 = sub i64 %x787, 634920634 + %x789 = add i64 %x788, 634115409 + %x790 = sub i64 %x789, 633312222 + %x791 = add i64 %x790, 632511068 + %x792 = sub i64 %x791, 631711939 + %x793 = add i64 %x792, 630914826 + %x794 = sub i64 %x793, 630119722 + %x795 = add i64 %x794, 629326620 + %x796 = sub i64 %x795, 628535512 + %x797 = add i64 %x796, 627746390 + %x798 = sub i64 %x797, 626959247 + %x799 = add i64 %x798, 626174076 + %x800 = sub i64 %x799, 625390869 + %x801 = add i64 %x800, 624609618 + %x802 = sub i64 %x801, 623830318 + %x803 = add i64 %x802, 623052959 + %x804 = sub i64 %x803, 622277535 + %x805 = add i64 %x804, 621504039 + %x806 = sub i64 %x805, 620732464 + %x807 = add i64 %x806, 619962802 + %x808 = sub i64 %x807, 619195046 + %x809 = add i64 %x808, 618429189 + %x810 = sub i64 %x809, 617665225 + %x811 = add i64 %x810, 616903146 + %x812 = sub i64 %x811, 616142945 + %x813 = add i64 %x812, 615384615 + %x814 = sub i64 %x813, 614628149 + %x815 = add i64 %x814, 613873542 + %x816 = sub i64 %x815, 613120784 + %x817 = add i64 %x816, 612369871 + %x818 = sub i64 %x817, 611620795 + %x819 = add i64 %x818, 610873549 + %x820 = sub i64 %x819, 610128126 + %x821 = add i64 %x820, 609384521 + %x822 = sub i64 %x821, 608642726 + %x823 = add i64 %x822, 607902735 + %x824 = sub i64 %x823, 607164541 + %x825 = add i64 %x824, 606428138 + %x826 = sub i64 %x825, 605693519 + %x827 = add i64 %x826, 604960677 + %x828 = sub i64 %x827, 604229607 + %x829 = add i64 %x828, 603500301 + %x830 = sub i64 %x829, 602772754 + %x831 = add i64 %x830, 602046959 + %x832 = sub i64 %x831, 601322910 + %x833 = add i64 %x832, 600600600 + %x834 = sub i64 %x833, 599880023 + %x835 = add i64 %x834, 599161174 + %x836 = sub i64 %x835, 598444045 + %x837 = add i64 %x836, 597728631 + %x838 = sub i64 %x837, 597014925 + %x839 = add i64 %x838, 596302921 + %x840 = sub i64 %x839, 595592614 + %x841 = add i64 %x840, 594883997 + %x842 = sub i64 %x841, 594177064 + %x843 = add i64 %x842, 593471810 + %x844 = sub i64 %x843, 592768227 + %x845 = add i64 %x844, 592066311 + %x846 = sub i64 %x845, 591366055 + %x847 = add i64 %x846, 590667454 + %x848 = sub i64 %x847, 589970501 + %x849 = add i64 %x848, 589275191 + %x850 = sub i64 %x849, 588581518 + %x851 = add i64 %x850, 587889476 + %x852 = sub i64 %x851, 587199060 + %x853 = add i64 %x852, 586510263 + %x854 = sub i64 %x853, 585823081 + %x855 = add i64 %x854, 585137507 + %x856 = sub i64 %x855, 584453535 + %x857 = add i64 %x856, 583771161 + %x858 = sub i64 %x857, 583090379 + %x859 = add i64 %x858, 582411182 + %x860 = sub i64 %x859, 581733566 + %x861 = add i64 %x860, 581057524 + %x862 = sub i64 %x861, 580383052 + %x863 = add i64 %x862, 579710144 + %x864 = sub i64 %x863, 579038795 + %x865 = add i64 %x864, 578368999 + %x866 = sub i64 %x865, 577700751 + %x867 = add i64 %x866, 577034045 + %x868 = sub i64 %x867, 576368876 + %x869 = add i64 %x868, 575705238 + %x870 = sub i64 %x869, 575043128 + %x871 = add i64 %x870, 574382538 + %x872 = sub i64 %x871, 573723465 + %x873 = add i64 %x872, 573065902 + %x874 = sub i64 %x873, 572409845 + %x875 = add i64 %x874, 571755288 + %x876 = sub i64 %x875, 571102227 + %x877 = add i64 %x876, 570450656 + %x878 = sub i64 %x877, 569800569 + %x879 = add i64 %x878, 569151963 + %x880 = sub i64 %x879, 568504832 + %x881 = add i64 %x880, 567859170 + %x882 = sub i64 %x881, 567214974 + %x883 = add i64 %x882, 566572237 + %x884 = sub i64 %x883, 565930956 + %x885 = add i64 %x884, 565291124 + %x886 = sub i64 %x885, 564652738 + %x887 = add i64 %x886, 564015792 + %x888 = sub i64 %x887, 563380281 + %x889 = add i64 %x888, 562746201 + %x890 = sub i64 %x889, 562113546 + %x891 = add i64 %x890, 561482313 + %x892 = sub i64 %x891, 560852495 + %x893 = add i64 %x892, 560224089 + %x894 = sub i64 %x893, 559597090 + %x895 = add i64 %x894, 558971492 + %x896 = sub i64 %x895, 558347292 + %x897 = add i64 %x896, 557724484 + %x898 = sub i64 %x897, 557103064 + %x899 = add i64 %x898, 556483027 + %x900 = sub i64 %x899, 555864369 + %x901 = add i64 %x900, 555247084 + %x902 = sub i64 %x901, 554631170 + %x903 = add i64 %x902, 554016620 + %x904 = sub i64 %x903, 553403431 + %x905 = add i64 %x904, 552791597 + %x906 = sub i64 %x905, 552181115 + %x907 = add i64 %x906, 551571980 + %x908 = sub i64 %x907, 550964187 + %x909 = add i64 %x908, 550357732 + %x910 = sub i64 %x909, 549752611 + %x911 = add i64 %x910, 549148819 + %x912 = sub i64 %x911, 548546352 + %x913 = add i64 %x912, 547945205 + %x914 = sub i64 %x913, 547345374 + %x915 = add i64 %x914, 546746856 + %x916 = sub i64 %x915, 546149645 + %x917 = add i64 %x916, 545553737 + %x918 = sub i64 %x917, 544959128 + %x919 = add i64 %x918, 544365813 + %x920 = sub i64 %x919, 543773790 + %x921 = add i64 %x920, 543183052 + %x922 = sub i64 %x921, 542593597 + %x923 = add i64 %x922, 542005420 + %x924 = sub i64 %x923, 541418516 + %x925 = add i64 %x924, 540832882 + %x926 = sub i64 %x925, 540248514 + %x927 = add i64 %x926, 539665407 + %x928 = sub i64 %x927, 539083557 + %x929 = add i64 %x928, 538502961 + %x930 = sub i64 %x929, 537923614 + %x931 = add i64 %x930, 537345513 + %x932 = sub i64 %x931, 536768652 + %x933 = add i64 %x932, 536193029 + %x934 = sub i64 %x933, 535618639 + %x935 = add i64 %x934, 535045478 + %x936 = sub i64 %x935, 534473543 + %x937 = add i64 %x936, 533902829 + %x938 = sub i64 %x937, 533333333 + %x939 = add i64 %x938, 532765050 + %x940 = sub i64 %x939, 532197977 + %x941 = add i64 %x940, 531632110 + %x942 = sub i64 %x941, 531067445 + %x943 = add i64 %x942, 530503978 + %x944 = sub i64 %x943, 529941706 + %x945 = add i64 %x944, 529380624 + %x946 = sub i64 %x945, 528820729 + %x947 = add i64 %x946, 528262017 + %x948 = sub i64 %x947, 527704485 + %x949 = add i64 %x948, 527148128 + %x950 = sub i64 %x949, 526592943 + %x951 = add i64 %x950, 526038926 + %x952 = sub i64 %x951, 525486074 + %x953 = add i64 %x952, 524934383 + %x954 = sub i64 %x953, 524383848 + %x955 = add i64 %x954, 523834468 + %x956 = sub i64 %x955, 523286237 + %x957 = add i64 %x956, 522739153 + %x958 = sub i64 %x957, 522193211 + %x959 = add i64 %x958, 521648408 + %x960 = sub i64 %x959, 521104742 + %x961 = add i64 %x960, 520562207 + %x962 = sub i64 %x961, 520020800 + %x963 = add i64 %x962, 519480519 + %x964 = sub i64 %x963, 518941359 + %x965 = add i64 %x964, 518403317 + %x966 = sub i64 %x965, 517866390 + %x967 = add i64 %x966, 517330574 + %x968 = sub i64 %x967, 516795865 + %x969 = add i64 %x968, 516262261 + %x970 = sub i64 %x969, 515729757 + %x971 = add i64 %x970, 515198351 + %x972 = sub i64 %x971, 514668039 + %x973 = add i64 %x972, 514138817 + %x974 = sub i64 %x973, 513610683 + %x975 = add i64 %x974, 513083632 + %x976 = sub i64 %x975, 512557662 + %x977 = add i64 %x976, 512032770 + %x978 = sub i64 %x977, 511508951 + %x979 = add i64 %x978, 510986203 + %x980 = sub i64 %x979, 510464522 + %x981 = add i64 %x980, 509943906 + %x982 = sub i64 %x981, 509424350 + %x983 = add i64 %x982, 508905852 + %x984 = sub i64 %x983, 508388408 + %x985 = add i64 %x984, 507872016 + %x986 = sub i64 %x985, 507356671 + %x987 = add i64 %x986, 506842372 + %x988 = sub i64 %x987, 506329113 + %x989 = add i64 %x988, 505816894 + %x990 = sub i64 %x989, 505305709 + %x991 = add i64 %x990, 504795557 + %x992 = sub i64 %x991, 504286434 + %x993 = add i64 %x992, 503778337 + %x994 = sub i64 %x993, 503271263 + %x995 = add i64 %x994, 502765208 + %x996 = sub i64 %x995, 502260170 + %x997 = add i64 %x996, 501756146 + %x998 = sub i64 %x997, 501253132 + %x999 = add i64 %x998, 500751126 + %x1000 = sub i64 %x999, 500250125 + %x1001 = add i64 %x1000, 499750124 + %x1002 = sub i64 %x1001, 499251123 + %x1003 = add i64 %x1002, 498753117 + %x1004 = sub i64 %x1003, 498256103 + %x1005 = add i64 %x1004, 497760079 + %x1006 = sub i64 %x1005, 497265042 + %x1007 = add i64 %x1006, 496770988 + %x1008 = sub i64 %x1007, 496277915 + %x1009 = add i64 %x1008, 495785820 + %x1010 = sub i64 %x1009, 495294700 + %x1011 = add i64 %x1010, 494804552 + %x1012 = sub i64 %x1011, 494315373 + %x1013 = add i64 %x1012, 493827160 + %x1014 = sub i64 %x1013, 493339911 + %x1015 = add i64 %x1014, 492853622 + %x1016 = sub i64 %x1015, 492368291 + %x1017 = add i64 %x1016, 491883915 + %x1018 = sub i64 %x1017, 491400491 + %x1019 = add i64 %x1018, 490918016 + %x1020 = sub i64 %x1019, 490436488 + %x1021 = add i64 %x1020, 489955903 + %x1022 = sub i64 %x1021, 489476260 + %x1023 = add i64 %x1022, 488997555 + %x1024 = sub i64 %x1023, 488519785 + %x1025 = add i64 %x1024, 488042947 + %x1026 = sub i64 %x1025, 487567040 + %x1027 = add i64 %x1026, 487092060 + %x1028 = sub i64 %x1027, 486618004 + %x1029 = add i64 %x1028, 486144871 + %x1030 = sub i64 %x1029, 485672656 + %x1031 = add i64 %x1030, 485201358 + %x1032 = sub i64 %x1031, 484730974 + %x1033 = add i64 %x1032, 484261501 + %x1034 = sub i64 %x1033, 483792936 + %x1035 = add i64 %x1034, 483325277 + %x1036 = sub i64 %x1035, 482858522 + %x1037 = add i64 %x1036, 482392667 + %x1038 = sub i64 %x1037, 481927710 + %x1039 = add i64 %x1038, 481463649 + %x1040 = sub i64 %x1039, 481000481 + %x1041 = add i64 %x1040, 480538202 + %x1042 = sub i64 %x1041, 480076812 + %x1043 = add i64 %x1042, 479616306 + %x1044 = sub i64 %x1043, 479156684 + %x1045 = add i64 %x1044, 478697941 + %x1046 = sub i64 %x1045, 478240076 + %x1047 = add i64 %x1046, 477783086 + %x1048 = sub i64 %x1047, 477326968 + %x1049 = add i64 %x1048, 476871721 + %x1050 = sub i64 %x1049, 476417341 + %x1051 = add i64 %x1050, 475963826 + %x1052 = sub i64 %x1051, 475511174 + %x1053 = add i64 %x1052, 475059382 + %x1054 = sub i64 %x1053, 474608448 + %x1055 = add i64 %x1054, 474158368 + %x1056 = sub i64 %x1055, 473709142 + %x1057 = add i64 %x1056, 473260766 + %x1058 = sub i64 %x1057, 472813238 + %x1059 = add i64 %x1058, 472366556 + %x1060 = sub i64 %x1059, 471920717 + %x1061 = add i64 %x1060, 471475719 + %x1062 = sub i64 %x1061, 471031559 + %x1063 = add i64 %x1062, 470588235 + %x1064 = sub i64 %x1063, 470145745 + %x1065 = add i64 %x1064, 469704086 + %x1066 = sub i64 %x1065, 469263256 + %x1067 = add i64 %x1066, 468823253 + %x1068 = sub i64 %x1067, 468384074 + %x1069 = add i64 %x1068, 467945718 + %x1070 = sub i64 %x1069, 467508181 + %x1071 = add i64 %x1070, 467071461 + %x1072 = sub i64 %x1071, 466635557 + %x1073 = add i64 %x1072, 466200466 + %x1074 = sub i64 %x1073, 465766185 + %x1075 = add i64 %x1074, 465332712 + %x1076 = sub i64 %x1075, 464900046 + %x1077 = add i64 %x1076, 464468183 + %x1078 = sub i64 %x1077, 464037122 + %x1079 = add i64 %x1078, 463606861 + %x1080 = sub i64 %x1079, 463177396 + %x1081 = add i64 %x1080, 462748727 + %x1082 = sub i64 %x1081, 462320850 + %x1083 = add i64 %x1082, 461893764 + %x1084 = sub i64 %x1083, 461467466 + %x1085 = add i64 %x1084, 461041954 + %x1086 = sub i64 %x1085, 460617227 + %x1087 = add i64 %x1086, 460193281 + %x1088 = sub i64 %x1087, 459770114 + %x1089 = add i64 %x1088, 459347726 + %x1090 = sub i64 %x1089, 458926112 + %x1091 = add i64 %x1090, 458505272 + %x1092 = sub i64 %x1091, 458085203 + %x1093 = add i64 %x1092, 457665903 + %x1094 = sub i64 %x1093, 457247370 + %x1095 = add i64 %x1094, 456829602 + %x1096 = sub i64 %x1095, 456412596 + %x1097 = add i64 %x1096, 455996352 + %x1098 = sub i64 %x1097, 455580865 + %x1099 = add i64 %x1098, 455166135 + %x1100 = sub i64 %x1099, 454752160 + %x1101 = add i64 %x1100, 454338936 + %x1102 = sub i64 %x1101, 453926463 + %x1103 = add i64 %x1102, 453514739 + %x1104 = sub i64 %x1103, 453103760 + %x1105 = add i64 %x1104, 452693526 + %x1106 = sub i64 %x1105, 452284034 + %x1107 = add i64 %x1106, 451875282 + %x1108 = sub i64 %x1107, 451467268 + %x1109 = add i64 %x1108, 451059990 + %x1110 = sub i64 %x1109, 450653447 + %x1111 = add i64 %x1110, 450247636 + %x1112 = sub i64 %x1111, 449842555 + %x1113 = add i64 %x1112, 449438202 + %x1114 = sub i64 %x1113, 449034575 + %x1115 = add i64 %x1114, 448631673 + %x1116 = sub i64 %x1115, 448229493 + %x1117 = add i64 %x1116, 447828034 + %x1118 = sub i64 %x1117, 447427293 + %x1119 = add i64 %x1118, 447027268 + %x1120 = sub i64 %x1119, 446627958 + %x1121 = add i64 %x1120, 446229361 + %x1122 = sub i64 %x1121, 445831475 + %x1123 = add i64 %x1122, 445434298 + %x1124 = sub i64 %x1123, 445037828 + %x1125 = add i64 %x1124, 444642063 + %x1126 = sub i64 %x1125, 444247001 + %x1127 = add i64 %x1126, 443852640 + %x1128 = sub i64 %x1127, 443458980 + %x1129 = add i64 %x1128, 443066016 + %x1130 = sub i64 %x1129, 442673749 + %x1131 = add i64 %x1130, 442282176 + %x1132 = sub i64 %x1131, 441891294 + %x1133 = add i64 %x1132, 441501103 + %x1134 = sub i64 %x1133, 441111601 + %x1135 = add i64 %x1134, 440722785 + %x1136 = sub i64 %x1135, 440334654 + %x1137 = add i64 %x1136, 439947206 + %x1138 = sub i64 %x1137, 439560439 + %x1139 = add i64 %x1138, 439174352 + %x1140 = sub i64 %x1139, 438788942 + %x1141 = add i64 %x1140, 438404208 + %x1142 = sub i64 %x1141, 438020148 + %x1143 = add i64 %x1142, 437636761 + %x1144 = sub i64 %x1143, 437254044 + %x1145 = add i64 %x1144, 436871996 + %x1146 = sub i64 %x1145, 436490615 + %x1147 = add i64 %x1146, 436109899 + %x1148 = sub i64 %x1147, 435729847 + %x1149 = add i64 %x1148, 435350457 + %x1150 = sub i64 %x1149, 434971726 + %x1151 = add i64 %x1150, 434593654 + %x1152 = sub i64 %x1151, 434216239 + %x1153 = add i64 %x1152, 433839479 + %x1154 = sub i64 %x1153, 433463372 + %x1155 = add i64 %x1154, 433087916 + %x1156 = sub i64 %x1155, 432713111 + %x1157 = add i64 %x1156, 432338953 + %x1158 = sub i64 %x1157, 431965442 + %x1159 = add i64 %x1158, 431592576 + %x1160 = sub i64 %x1159, 431220353 + %x1161 = add i64 %x1160, 430848772 + %x1162 = sub i64 %x1161, 430477830 + %x1163 = add i64 %x1162, 430107526 + %x1164 = sub i64 %x1163, 429737859 + %x1165 = add i64 %x1164, 429368827 + %x1166 = sub i64 %x1165, 429000429 + %x1167 = add i64 %x1166, 428632661 + %x1168 = sub i64 %x1167, 428265524 + %x1169 = add i64 %x1168, 427899015 + %x1170 = sub i64 %x1169, 427533133 + %x1171 = add i64 %x1170, 427167876 + %x1172 = sub i64 %x1171, 426803243 + %x1173 = add i64 %x1172, 426439232 + %x1174 = sub i64 %x1173, 426075841 + %x1175 = add i64 %x1174, 425713069 + %x1176 = sub i64 %x1175, 425350914 + %x1177 = add i64 %x1176, 424989375 + %x1178 = sub i64 %x1177, 424628450 + %x1179 = add i64 %x1178, 424268137 + %x1180 = sub i64 %x1179, 423908435 + %x1181 = add i64 %x1180, 423549343 + %x1182 = sub i64 %x1181, 423190859 + %x1183 = add i64 %x1182, 422832980 + %x1184 = sub i64 %x1183, 422475707 + %x1185 = add i64 %x1184, 422119037 + %x1186 = sub i64 %x1185, 421762969 + %x1187 = add i64 %x1186, 421407501 + %x1188 = sub i64 %x1187, 421052631 + %x1189 = add i64 %x1188, 420698359 + %x1190 = sub i64 %x1189, 420344682 + %x1191 = add i64 %x1190, 419991600 + %x1192 = sub i64 %x1191, 419639110 + %x1193 = add i64 %x1192, 419287211 + %x1194 = sub i64 %x1193, 418935902 + %x1195 = add i64 %x1194, 418585182 + %x1196 = sub i64 %x1195, 418235048 + %x1197 = add i64 %x1196, 417885499 + %x1198 = sub i64 %x1197, 417536534 + %x1199 = add i64 %x1198, 417188151 + %x1200 = sub i64 %x1199, 416840350 + %x1201 = add i64 %x1200, 416493127 + %x1202 = sub i64 %x1201, 416146483 + %x1203 = add i64 %x1202, 415800415 + %x1204 = sub i64 %x1203, 415454923 + %x1205 = add i64 %x1204, 415110004 + %x1206 = sub i64 %x1205, 414765657 + %x1207 = add i64 %x1206, 414421881 + %x1208 = sub i64 %x1207, 414078674 + %x1209 = add i64 %x1208, 413736036 + %x1210 = sub i64 %x1209, 413393964 + %x1211 = add i64 %x1210, 413052457 + %x1212 = sub i64 %x1211, 412711514 + %x1213 = add i64 %x1212, 412371134 + %x1214 = sub i64 %x1213, 412031314 + %x1215 = add i64 %x1214, 411692054 + %x1216 = sub i64 %x1215, 411353352 + %x1217 = add i64 %x1216, 411015207 + %x1218 = sub i64 %x1217, 410677618 + %x1219 = add i64 %x1218, 410340582 + %x1220 = sub i64 %x1219, 410004100 + %x1221 = add i64 %x1220, 409668168 + %x1222 = sub i64 %x1221, 409332787 + %x1223 = add i64 %x1222, 408997955 + %x1224 = sub i64 %x1223, 408663669 + %x1225 = add i64 %x1224, 408329930 + %x1226 = sub i64 %x1225, 407996736 + %x1227 = add i64 %x1226, 407664084 + %x1228 = sub i64 %x1227, 407331975 + %x1229 = add i64 %x1228, 407000407 + %x1230 = sub i64 %x1229, 406669377 + %x1231 = add i64 %x1230, 406338886 + %x1232 = sub i64 %x1231, 406008932 + %x1233 = add i64 %x1232, 405679513 + %x1234 = sub i64 %x1233, 405350628 + %x1235 = add i64 %x1234, 405022276 + %x1236 = sub i64 %x1235, 404694455 + %x1237 = add i64 %x1236, 404367165 + %x1238 = sub i64 %x1237, 404040404 + %x1239 = add i64 %x1238, 403714170 + %x1240 = sub i64 %x1239, 403388463 + %x1241 = add i64 %x1240, 403063280 + %x1242 = sub i64 %x1241, 402738622 + %x1243 = add i64 %x1242, 402414486 + %x1244 = sub i64 %x1243, 402090872 + %x1245 = add i64 %x1244, 401767778 + %x1246 = sub i64 %x1245, 401445202 + %x1247 = add i64 %x1246, 401123144 + %x1248 = sub i64 %x1247, 400801603 + %x1249 = add i64 %x1248, 400480576 + %x1250 = sub i64 %x1249, 400160064 + %x1251 = add i64 %x1250, 399840063 + %x1252 = sub i64 %x1251, 399520575 + %x1253 = add i64 %x1252, 399201596 + %x1254 = sub i64 %x1253, 398883127 + %x1255 = add i64 %x1254, 398565165 + %x1256 = sub i64 %x1255, 398247710 + %x1257 = add i64 %x1256, 397930760 + %x1258 = sub i64 %x1257, 397614314 + %x1259 = add i64 %x1258, 397298371 + %x1260 = sub i64 %x1259, 396982929 + %x1261 = add i64 %x1260, 396667988 + %x1262 = sub i64 %x1261, 396353547 + %x1263 = add i64 %x1262, 396039603 + %x1264 = sub i64 %x1263, 395726157 + %x1265 = add i64 %x1264, 395413206 + %x1266 = sub i64 %x1265, 395100750 + %x1267 = add i64 %x1266, 394788787 + %x1268 = sub i64 %x1267, 394477317 + %x1269 = add i64 %x1268, 394166338 + %x1270 = sub i64 %x1269, 393855848 + %x1271 = add i64 %x1270, 393545848 + %x1272 = sub i64 %x1271, 393236335 + %x1273 = add i64 %x1272, 392927308 + %x1274 = sub i64 %x1273, 392618767 + %x1275 = add i64 %x1274, 392310710 + %x1276 = sub i64 %x1275, 392003136 + %x1277 = add i64 %x1276, 391696043 + %x1278 = sub i64 %x1277, 391389432 + %x1279 = add i64 %x1278, 391083300 + %x1280 = sub i64 %x1279, 390777647 + %x1281 = add i64 %x1280, 390472471 + %x1282 = sub i64 %x1281, 390167772 + %x1283 = add i64 %x1282, 389863547 + %x1284 = sub i64 %x1283, 389559797 + %x1285 = add i64 %x1284, 389256520 + %x1286 = sub i64 %x1285, 388953714 + %x1287 = add i64 %x1286, 388651379 + %x1288 = sub i64 %x1287, 388349514 + %x1289 = add i64 %x1288, 388048117 + %x1290 = sub i64 %x1289, 387747188 + %x1291 = add i64 %x1290, 387446726 + %x1292 = sub i64 %x1291, 387146728 + %x1293 = add i64 %x1292, 386847195 + %x1294 = sub i64 %x1293, 386548125 + %x1295 = add i64 %x1294, 386249517 + %x1296 = sub i64 %x1295, 385951370 + %x1297 = add i64 %x1296, 385653682 + %x1298 = sub i64 %x1297, 385356454 + %x1299 = add i64 %x1298, 385059684 + %x1300 = sub i64 %x1299, 384763370 + %x1301 = add i64 %x1300, 384467512 + %x1302 = sub i64 %x1301, 384172109 + %x1303 = add i64 %x1302, 383877159 + %x1304 = sub i64 %x1303, 383582662 + %x1305 = add i64 %x1304, 383288616 + %x1306 = sub i64 %x1305, 382995021 + %x1307 = add i64 %x1306, 382701875 + %x1308 = sub i64 %x1307, 382409177 + %x1309 = add i64 %x1308, 382116927 + %x1310 = sub i64 %x1309, 381825124 + %x1311 = add i64 %x1310, 381533765 + %x1312 = sub i64 %x1311, 381242851 + %x1313 = add i64 %x1312, 380952380 + %x1314 = sub i64 %x1313, 380662352 + %x1315 = add i64 %x1314, 380372765 + %x1316 = sub i64 %x1315, 380083618 + %x1317 = add i64 %x1316, 379794910 + %x1318 = sub i64 %x1317, 379506641 + %x1319 = add i64 %x1318, 379218809 + %x1320 = sub i64 %x1319, 378931413 + %x1321 = add i64 %x1320, 378644452 + %x1322 = sub i64 %x1321, 378357926 + %x1323 = add i64 %x1322, 378071833 + %x1324 = sub i64 %x1323, 377786173 + %x1325 = add i64 %x1324, 377500943 + %x1326 = sub i64 %x1325, 377216144 + %x1327 = add i64 %x1326, 376931775 + %x1328 = sub i64 %x1327, 376647834 + %x1329 = add i64 %x1328, 376364320 + %x1330 = sub i64 %x1329, 376081233 + %x1331 = add i64 %x1330, 375798571 + %x1332 = sub i64 %x1331, 375516334 + %x1333 = add i64 %x1332, 375234521 + %x1334 = sub i64 %x1333, 374953130 + %x1335 = add i64 %x1334, 374672161 + %x1336 = sub i64 %x1335, 374391613 + %x1337 = add i64 %x1336, 374111485 + %x1338 = sub i64 %x1337, 373831775 + %x1339 = add i64 %x1338, 373552484 + %x1340 = sub i64 %x1339, 373273609 + %x1341 = add i64 %x1340, 372995151 + %x1342 = sub i64 %x1341, 372717107 + %x1343 = add i64 %x1342, 372439478 + %x1344 = sub i64 %x1343, 372162262 + %x1345 = add i64 %x1344, 371885459 + %x1346 = sub i64 %x1345, 371609067 + %x1347 = add i64 %x1346, 371333085 + %x1348 = sub i64 %x1347, 371057513 + %x1349 = add i64 %x1348, 370782350 + %x1350 = sub i64 %x1349, 370507595 + %x1351 = add i64 %x1350, 370233246 + %x1352 = sub i64 %x1351, 369959304 + %x1353 = add i64 %x1352, 369685767 + %x1354 = sub i64 %x1353, 369412633 + %x1355 = add i64 %x1354, 369139904 + %x1356 = sub i64 %x1355, 368867576 + %x1357 = add i64 %x1356, 368595650 + %x1358 = sub i64 %x1357, 368324125 + %x1359 = add i64 %x1358, 368052999 + %x1360 = sub i64 %x1359, 367782272 + %x1361 = add i64 %x1360, 367511944 + %x1362 = sub i64 %x1361, 367242012 + %x1363 = add i64 %x1362, 366972477 + %x1364 = sub i64 %x1363, 366703337 + %x1365 = add i64 %x1364, 366434591 + %x1366 = sub i64 %x1365, 366166239 + %x1367 = add i64 %x1366, 365898280 + %x1368 = sub i64 %x1367, 365630712 + %x1369 = add i64 %x1368, 365363536 + %x1370 = sub i64 %x1369, 365096750 + %x1371 = add i64 %x1370, 364830353 + %x1372 = sub i64 %x1371, 364564345 + %x1373 = add i64 %x1372, 364298724 + %x1374 = sub i64 %x1373, 364033491 + %x1375 = add i64 %x1374, 363768643 + %x1376 = sub i64 %x1375, 363504180 + %x1377 = add i64 %x1376, 363240101 + %x1378 = sub i64 %x1377, 362976406 + %x1379 = add i64 %x1378, 362713093 + %x1380 = sub i64 %x1379, 362450163 + %x1381 = add i64 %x1380, 362187613 + %x1382 = sub i64 %x1381, 361925443 + %x1383 = add i64 %x1382, 361663652 + %x1384 = sub i64 %x1383, 361402240 + %x1385 = add i64 %x1384, 361141206 + %x1386 = sub i64 %x1385, 360880548 + %x1387 = add i64 %x1386, 360620266 + %x1388 = sub i64 %x1387, 360360360 + %x1389 = add i64 %x1388, 360100828 + %x1390 = sub i64 %x1389, 359841669 + %x1391 = add i64 %x1390, 359582883 + %x1392 = sub i64 %x1391, 359324469 + %x1393 = add i64 %x1392, 359066427 + %x1394 = sub i64 %x1393, 358808754 + %x1395 = add i64 %x1394, 358551452 + %x1396 = sub i64 %x1395, 358294518 + %x1397 = add i64 %x1396, 358037952 + %x1398 = sub i64 %x1397, 357781753 + %x1399 = add i64 %x1398, 357525920 + %x1400 = sub i64 %x1399, 357270453 + %x1401 = add i64 %x1400, 357015351 + %x1402 = sub i64 %x1401, 356760613 + %x1403 = add i64 %x1402, 356506238 + %x1404 = sub i64 %x1403, 356252226 + %x1405 = add i64 %x1404, 355998576 + %x1406 = sub i64 %x1405, 355745286 + %x1407 = add i64 %x1406, 355492356 + %x1408 = sub i64 %x1407, 355239786 + %x1409 = add i64 %x1408, 354987575 + %x1410 = sub i64 %x1409, 354735721 + %x1411 = add i64 %x1410, 354484225 + %x1412 = sub i64 %x1411, 354233085 + %x1413 = add i64 %x1412, 353982300 + %x1414 = sub i64 %x1413, 353731871 + %x1415 = add i64 %x1414, 353481795 + %x1416 = sub i64 %x1415, 353232073 + %x1417 = add i64 %x1416, 352982703 + %x1418 = sub i64 %x1417, 352733686 + %x1419 = add i64 %x1418, 352485019 + %x1420 = sub i64 %x1419, 352236703 + %x1421 = add i64 %x1420, 351988736 + %x1422 = sub i64 %x1421, 351741118 + %x1423 = add i64 %x1422, 351493848 + %x1424 = sub i64 %x1423, 351246926 + %x1425 = add i64 %x1424, 351000351 + %x1426 = sub i64 %x1425, 350754121 + %x1427 = add i64 %x1426, 350508236 + %x1428 = sub i64 %x1427, 350262697 + %x1429 = add i64 %x1428, 350017500 + %x1430 = sub i64 %x1429, 349772647 + %x1431 = add i64 %x1430, 349528137 + %x1432 = sub i64 %x1431, 349283967 + %x1433 = add i64 %x1432, 349040139 + %x1434 = sub i64 %x1433, 348796651 + %x1435 = add i64 %x1434, 348553502 + %x1436 = sub i64 %x1435, 348310693 + %x1437 = add i64 %x1436, 348068221 + %x1438 = sub i64 %x1437, 347826086 + %x1439 = add i64 %x1438, 347584289 + %x1440 = sub i64 %x1439, 347342827 + %x1441 = add i64 %x1440, 347101700 + %x1442 = sub i64 %x1441, 346860908 + %x1443 = add i64 %x1442, 346620450 + %x1444 = sub i64 %x1443, 346380325 + %x1445 = add i64 %x1444, 346140533 + %x1446 = sub i64 %x1445, 345901072 + %x1447 = add i64 %x1446, 345661942 + %x1448 = sub i64 %x1447, 345423143 + %x1449 = add i64 %x1448, 345184673 + %x1450 = sub i64 %x1449, 344946533 + %x1451 = add i64 %x1450, 344708721 + %x1452 = sub i64 %x1451, 344471236 + %x1453 = add i64 %x1452, 344234079 + %x1454 = sub i64 %x1453, 343997248 + %x1455 = add i64 %x1454, 343760742 + %x1456 = sub i64 %x1455, 343524562 + %x1457 = add i64 %x1456, 343288705 + %x1458 = sub i64 %x1457, 343053173 + %x1459 = add i64 %x1458, 342817963 + %x1460 = sub i64 %x1459, 342583076 + %x1461 = add i64 %x1460, 342348510 + %x1462 = sub i64 %x1461, 342114266 + %x1463 = add i64 %x1462, 341880341 + %x1464 = sub i64 %x1463, 341646737 + %x1465 = add i64 %x1464, 341413451 + %x1466 = sub i64 %x1465, 341180484 + %x1467 = add i64 %x1466, 340947834 + %x1468 = sub i64 %x1467, 340715502 + %x1469 = add i64 %x1468, 340483486 + %x1470 = sub i64 %x1469, 340251786 + %x1471 = add i64 %x1470, 340020401 + %x1472 = sub i64 %x1471, 339789330 + %x1473 = add i64 %x1472, 339558573 + %x1474 = sub i64 %x1473, 339328130 + %x1475 = add i64 %x1474, 339097999 + %x1476 = sub i64 %x1475, 338868180 + %x1477 = add i64 %x1476, 338638672 + %x1478 = sub i64 %x1477, 338409475 + %x1479 = add i64 %x1478, 338180588 + %x1480 = sub i64 %x1479, 337952010 + %x1481 = add i64 %x1480, 337723741 + %x1482 = sub i64 %x1481, 337495781 + %x1483 = add i64 %x1482, 337268128 + %x1484 = sub i64 %x1483, 337040781 + %x1485 = add i64 %x1484, 336813742 + %x1486 = sub i64 %x1485, 336587007 + %x1487 = add i64 %x1486, 336360578 + %x1488 = sub i64 %x1487, 336134453 + %x1489 = add i64 %x1488, 335908632 + %x1490 = sub i64 %x1489, 335683115 + %x1491 = add i64 %x1490, 335457900 + %x1492 = sub i64 %x1491, 335232986 + %x1493 = add i64 %x1492, 335008375 + %x1494 = sub i64 %x1493, 334784064 + %x1495 = add i64 %x1494, 334560053 + %x1496 = sub i64 %x1495, 334336342 + %x1497 = add i64 %x1496, 334112930 + %x1498 = sub i64 %x1497, 333889816 + %x1499 = add i64 %x1498, 333667000 + %x1500 = sub i64 %x1499, 333444481 + %x1501 = add i64 %x1500, 333222259 + %x1502 = sub i64 %x1501, 333000333 + %x1503 = add i64 %x1502, 332778702 + %x1504 = sub i64 %x1503, 332557366 + %x1505 = add i64 %x1504, 332336324 + %x1506 = sub i64 %x1505, 332115576 + %x1507 = add i64 %x1506, 331895121 + %x1508 = sub i64 %x1507, 331674958 + %x1509 = add i64 %x1508, 331455087 + %x1510 = sub i64 %x1509, 331235508 + %x1511 = add i64 %x1510, 331016219 + %x1512 = sub i64 %x1511, 330797221 + %x1513 = add i64 %x1512, 330578512 + %x1514 = sub i64 %x1513, 330360092 + %x1515 = add i64 %x1514, 330141961 + %x1516 = sub i64 %x1515, 329924117 + %x1517 = add i64 %x1516, 329706561 + %x1518 = sub i64 %x1517, 329489291 + %x1519 = add i64 %x1518, 329272308 + %x1520 = sub i64 %x1519, 329055610 + %x1521 = add i64 %x1520, 328839197 + %x1522 = sub i64 %x1521, 328623069 + %x1523 = add i64 %x1522, 328407224 + %x1524 = sub i64 %x1523, 328191663 + %x1525 = add i64 %x1524, 327976385 + %x1526 = sub i64 %x1525, 327761389 + %x1527 = add i64 %x1526, 327546675 + %x1528 = sub i64 %x1527, 327332242 + %x1529 = add i64 %x1528, 327118089 + %x1530 = sub i64 %x1529, 326904217 + %x1531 = add i64 %x1530, 326690623 + %x1532 = sub i64 %x1531, 326477309 + %x1533 = add i64 %x1532, 326264274 + %x1534 = sub i64 %x1533, 326051516 + %x1535 = add i64 %x1534, 325839035 + %x1536 = sub i64 %x1535, 325626831 + %x1537 = add i64 %x1536, 325414904 + %x1538 = sub i64 %x1537, 325203252 + %x1539 = add i64 %x1538, 324991875 + %x1540 = sub i64 %x1539, 324780772 + %x1541 = add i64 %x1540, 324569944 + %x1542 = sub i64 %x1541, 324359390 + %x1543 = add i64 %x1542, 324149108 + %x1544 = sub i64 %x1543, 323939099 + %x1545 = add i64 %x1544, 323729362 + %x1546 = sub i64 %x1545, 323519896 + %x1547 = add i64 %x1546, 323310701 + %x1548 = sub i64 %x1547, 323101777 + %x1549 = add i64 %x1548, 322893122 + %x1550 = sub i64 %x1549, 322684737 + %x1551 = add i64 %x1550, 322476620 + %x1552 = sub i64 %x1551, 322268772 + %x1553 = add i64 %x1552, 322061191 + %x1554 = sub i64 %x1553, 321853878 + %x1555 = add i64 %x1554, 321646831 + %x1556 = sub i64 %x1555, 321440051 + %x1557 = add i64 %x1556, 321233536 + %x1558 = sub i64 %x1557, 321027287 + %x1559 = add i64 %x1558, 320821302 + %x1560 = sub i64 %x1559, 320615581 + %x1561 = add i64 %x1560, 320410124 + %x1562 = sub i64 %x1561, 320204931 + %x1563 = add i64 %x1562, 320000000 + %x1564 = sub i64 %x1563, 319795330 + %x1565 = add i64 %x1564, 319590923 + %x1566 = sub i64 %x1565, 319386777 + %x1567 = add i64 %x1566, 319182891 + %x1568 = sub i64 %x1567, 318979266 + %x1569 = add i64 %x1568, 318775900 + %x1570 = sub i64 %x1569, 318572793 + %x1571 = add i64 %x1570, 318369945 + %x1572 = sub i64 %x1571, 318167356 + %x1573 = add i64 %x1572, 317965023 + %x1574 = sub i64 %x1573, 317762948 + %x1575 = add i64 %x1574, 317561130 + %x1576 = sub i64 %x1575, 317359568 + %x1577 = add i64 %x1576, 317158261 + %x1578 = sub i64 %x1577, 316957210 + %x1579 = add i64 %x1578, 316756414 + %x1580 = sub i64 %x1579, 316555872 + %x1581 = add i64 %x1580, 316355583 + %x1582 = sub i64 %x1581, 316155548 + %x1583 = add i64 %x1582, 315955766 + %x1584 = sub i64 %x1583, 315756236 + %x1585 = add i64 %x1584, 315556958 + %x1586 = sub i64 %x1585, 315357931 + %x1587 = add i64 %x1586, 315159155 + %x1588 = sub i64 %x1587, 314960629 + %x1589 = add i64 %x1588, 314762354 + %x1590 = sub i64 %x1589, 314564328 + %x1591 = add i64 %x1590, 314366551 + %x1592 = sub i64 %x1591, 314169022 + %x1593 = add i64 %x1592, 313971742 + %x1594 = sub i64 %x1593, 313774709 + %x1595 = add i64 %x1594, 313577924 + %x1596 = sub i64 %x1595, 313381385 + %x1597 = add i64 %x1596, 313185092 + %x1598 = sub i64 %x1597, 312989045 + %x1599 = add i64 %x1598, 312793243 + %x1600 = sub i64 %x1599, 312597686 + %x1601 = add i64 %x1600, 312402374 + %x1602 = sub i64 %x1601, 312207305 + %x1603 = add i64 %x1602, 312012480 + %x1604 = sub i64 %x1603, 311817898 + %x1605 = add i64 %x1604, 311623558 + %x1606 = sub i64 %x1605, 311429461 + %x1607 = add i64 %x1606, 311235605 + %x1608 = sub i64 %x1607, 311041990 + %x1609 = add i64 %x1608, 310848616 + %x1610 = sub i64 %x1609, 310655483 + %x1611 = add i64 %x1610, 310462589 + %x1612 = sub i64 %x1611, 310269934 + %x1613 = add i64 %x1612, 310077519 + %x1614 = sub i64 %x1613, 309885342 + %x1615 = add i64 %x1614, 309693403 + %x1616 = sub i64 %x1615, 309501702 + %x1617 = add i64 %x1616, 309310238 + %x1618 = sub i64 %x1617, 309119010 + %x1619 = add i64 %x1618, 308928019 + %x1620 = sub i64 %x1619, 308737264 + %x1621 = add i64 %x1620, 308546744 + %x1622 = sub i64 %x1621, 308356460 + %x1623 = add i64 %x1622, 308166409 + %x1624 = sub i64 %x1623, 307976593 + %x1625 = add i64 %x1624, 307787011 + %x1626 = sub i64 %x1625, 307597662 + %x1627 = add i64 %x1626, 307408545 + %x1628 = sub i64 %x1627, 307219662 + %x1629 = add i64 %x1628, 307031010 + %x1630 = sub i64 %x1629, 306842589 + %x1631 = add i64 %x1630, 306654400 + %x1632 = sub i64 %x1631, 306466441 + %x1633 = add i64 %x1632, 306278713 + %x1634 = sub i64 %x1633, 306091215 + %x1635 = add i64 %x1634, 305903946 + %x1636 = sub i64 %x1635, 305716906 + %x1637 = add i64 %x1636, 305530094 + %x1638 = sub i64 %x1637, 305343511 + %x1639 = add i64 %x1638, 305157155 + %x1640 = sub i64 %x1639, 304971027 + %x1641 = add i64 %x1640, 304785126 + %x1642 = sub i64 %x1641, 304599451 + %x1643 = add i64 %x1642, 304414003 + %x1644 = sub i64 %x1643, 304228780 + %x1645 = add i64 %x1644, 304043782 + %x1646 = sub i64 %x1645, 303859009 + %x1647 = add i64 %x1646, 303674460 + %x1648 = sub i64 %x1647, 303490136 + %x1649 = add i64 %x1648, 303306035 + %x1650 = sub i64 %x1649, 303122158 + %x1651 = add i64 %x1650, 302938503 + %x1652 = sub i64 %x1651, 302755071 + %x1653 = add i64 %x1652, 302571860 + %x1654 = sub i64 %x1653, 302388872 + %x1655 = add i64 %x1654, 302206104 + %x1656 = sub i64 %x1655, 302023557 + %x1657 = add i64 %x1656, 301841231 + %x1658 = sub i64 %x1657, 301659125 + %x1659 = add i64 %x1658, 301477238 + %x1660 = sub i64 %x1659, 301295570 + %x1661 = add i64 %x1660, 301114122 + %x1662 = sub i64 %x1661, 300932891 + %x1663 = add i64 %x1662, 300751879 + %x1664 = sub i64 %x1663, 300571085 + %x1665 = add i64 %x1664, 300390507 + %x1666 = sub i64 %x1665, 300210147 + %x1667 = add i64 %x1666, 300030003 + %x1668 = sub i64 %x1667, 299850074 + %x1669 = add i64 %x1668, 299670362 + %x1670 = sub i64 %x1669, 299490865 + %x1671 = add i64 %x1670, 299311583 + %x1672 = sub i64 %x1671, 299132515 + %x1673 = add i64 %x1672, 298953662 + %x1674 = sub i64 %x1673, 298775022 + %x1675 = add i64 %x1674, 298596595 + %x1676 = sub i64 %x1675, 298418382 + %x1677 = add i64 %x1676, 298240381 + %x1678 = sub i64 %x1677, 298062593 + %x1679 = add i64 %x1678, 297885016 + %x1680 = sub i64 %x1679, 297707651 + %x1681 = add i64 %x1680, 297530496 + %x1682 = sub i64 %x1681, 297353553 + %x1683 = add i64 %x1682, 297176820 + %x1684 = sub i64 %x1683, 297000297 + %x1685 = add i64 %x1684, 296823983 + %x1686 = sub i64 %x1685, 296647878 + %x1687 = add i64 %x1686, 296471983 + %x1688 = sub i64 %x1687, 296296296 + %x1689 = add i64 %x1688, 296120817 + %x1690 = sub i64 %x1689, 295945546 + %x1691 = add i64 %x1690, 295770482 + %x1692 = sub i64 %x1691, 295595625 + %x1693 = add i64 %x1692, 295420974 + %x1694 = sub i64 %x1693, 295246530 + %x1695 = add i64 %x1694, 295072292 + %x1696 = sub i64 %x1695, 294898260 + %x1697 = add i64 %x1696, 294724432 + %x1698 = sub i64 %x1697, 294550810 + %x1699 = add i64 %x1698, 294377391 + %x1700 = sub i64 %x1699, 294204177 + %x1701 = add i64 %x1700, 294031167 + %x1702 = sub i64 %x1701, 293858360 + %x1703 = add i64 %x1702, 293685756 + %x1704 = sub i64 %x1703, 293513354 + %x1705 = add i64 %x1704, 293341155 + %x1706 = sub i64 %x1705, 293169158 + %x1707 = add i64 %x1706, 292997363 + %x1708 = sub i64 %x1707, 292825768 + %x1709 = add i64 %x1708, 292654375 + %x1710 = sub i64 %x1709, 292483182 + %x1711 = add i64 %x1710, 292312189 + %x1712 = sub i64 %x1711, 292141396 + %x1713 = add i64 %x1712, 291970802 + %x1714 = sub i64 %x1713, 291800408 + %x1715 = add i64 %x1714, 291630212 + %x1716 = sub i64 %x1715, 291460215 + %x1717 = add i64 %x1716, 291290416 + %x1718 = sub i64 %x1717, 291120815 + %x1719 = add i64 %x1718, 290951411 + %x1720 = sub i64 %x1719, 290782204 + %x1721 = add i64 %x1720, 290613193 + %x1722 = sub i64 %x1721, 290444379 + %x1723 = add i64 %x1722, 290275761 + %x1724 = sub i64 %x1723, 290107339 + %x1725 = add i64 %x1724, 289939112 + %x1726 = sub i64 %x1725, 289771080 + %x1727 = add i64 %x1726, 289603243 + %x1728 = sub i64 %x1727, 289435600 + %x1729 = add i64 %x1728, 289268151 + %x1730 = sub i64 %x1729, 289100896 + %x1731 = add i64 %x1730, 288933834 + %x1732 = sub i64 %x1731, 288766965 + %x1733 = add i64 %x1732, 288600288 + %x1734 = sub i64 %x1733, 288433804 + %x1735 = add i64 %x1734, 288267512 + %x1736 = sub i64 %x1735, 288101411 + %x1737 = add i64 %x1736, 287935502 + %x1738 = sub i64 %x1737, 287769784 + %x1739 = add i64 %x1738, 287604256 + %x1740 = sub i64 %x1739, 287438919 + %x1741 = add i64 %x1740, 287273771 + %x1742 = sub i64 %x1741, 287108814 + %x1743 = add i64 %x1742, 286944045 + %x1744 = sub i64 %x1743, 286779466 + %x1745 = add i64 %x1744, 286615075 + %x1746 = sub i64 %x1745, 286450873 + %x1747 = add i64 %x1746, 286286859 + %x1748 = sub i64 %x1747, 286123032 + %x1749 = add i64 %x1748, 285959393 + %x1750 = sub i64 %x1749, 285795941 + %x1751 = add i64 %x1750, 285632676 + %x1752 = sub i64 %x1751, 285469597 + %x1753 = add i64 %x1752, 285306704 + %x1754 = sub i64 %x1753, 285143997 + %x1755 = add i64 %x1754, 284981476 + %x1756 = sub i64 %x1755, 284819139 + %x1757 = add i64 %x1756, 284656988 + %x1758 = sub i64 %x1757, 284495021 + %x1759 = add i64 %x1758, 284333238 + %x1760 = sub i64 %x1759, 284171639 + %x1761 = add i64 %x1760, 284010224 + %x1762 = sub i64 %x1761, 283848992 + %x1763 = add i64 %x1762, 283687943 + %x1764 = sub i64 %x1763, 283527076 + %x1765 = add i64 %x1764, 283366392 + %x1766 = sub i64 %x1765, 283205890 + %x1767 = add i64 %x1766, 283045570 + %x1768 = sub i64 %x1767, 282885431 + %x1769 = add i64 %x1768, 282725473 + %x1770 = sub i64 %x1769, 282565696 + %x1771 = add i64 %x1770, 282406099 + %x1772 = sub i64 %x1771, 282246683 + %x1773 = add i64 %x1772, 282087447 + %x1774 = sub i64 %x1773, 281928390 + %x1775 = add i64 %x1774, 281769512 + %x1776 = sub i64 %x1775, 281610813 + %x1777 = add i64 %x1776, 281452293 + %x1778 = sub i64 %x1777, 281293952 + %x1779 = add i64 %x1778, 281135788 + %x1780 = sub i64 %x1779, 280977802 + %x1781 = add i64 %x1780, 280819994 + %x1782 = sub i64 %x1781, 280662363 + %x1783 = add i64 %x1782, 280504908 + %x1784 = sub i64 %x1783, 280347631 + %x1785 = add i64 %x1784, 280190529 + %x1786 = sub i64 %x1785, 280033604 + %x1787 = add i64 %x1786, 279876854 + %x1788 = sub i64 %x1787, 279720279 + %x1789 = add i64 %x1788, 279563880 + %x1790 = sub i64 %x1789, 279407655 + %x1791 = add i64 %x1790, 279251605 + %x1792 = sub i64 %x1791, 279095729 + %x1793 = add i64 %x1792, 278940027 + %x1794 = sub i64 %x1793, 278784499 + %x1795 = add i64 %x1794, 278629144 + %x1796 = sub i64 %x1795, 278473962 + %x1797 = add i64 %x1796, 278318953 + %x1798 = sub i64 %x1797, 278164116 + %x1799 = add i64 %x1798, 278009452 + %x1800 = sub i64 %x1799, 277854959 + %x1801 = add i64 %x1800, 277700638 + %x1802 = sub i64 %x1801, 277546489 + %x1803 = add i64 %x1802, 277392510 + %x1804 = sub i64 %x1803, 277238702 + %x1805 = add i64 %x1804, 277085065 + %x1806 = sub i64 %x1805, 276931597 + %x1807 = add i64 %x1806, 276778300 + %x1808 = sub i64 %x1807, 276625172 + %x1809 = add i64 %x1808, 276472214 + %x1810 = sub i64 %x1809, 276319425 + %x1811 = add i64 %x1810, 276166804 + %x1812 = sub i64 %x1811, 276014352 + %x1813 = add i64 %x1812, 275862068 + %x1814 = sub i64 %x1813, 275709953 + %x1815 = add i64 %x1814, 275558004 + %x1816 = sub i64 %x1815, 275406224 + %x1817 = add i64 %x1816, 275254610 + %x1818 = sub i64 %x1817, 275103163 + %x1819 = add i64 %x1818, 274951883 + %x1820 = sub i64 %x1819, 274800769 + %x1821 = add i64 %x1820, 274649821 + %x1822 = sub i64 %x1821, 274499039 + %x1823 = add i64 %x1822, 274348422 + %x1824 = sub i64 %x1823, 274197970 + %x1825 = add i64 %x1824, 274047684 + %x1826 = sub i64 %x1825, 273897562 + %x1827 = add i64 %x1826, 273747604 + %x1828 = sub i64 %x1827, 273597811 + %x1829 = add i64 %x1828, 273448181 + %x1830 = sub i64 %x1829, 273298715 + %x1831 = add i64 %x1830, 273149412 + %x1832 = sub i64 %x1831, 273000273 + %x1833 = add i64 %x1832, 272851296 + %x1834 = sub i64 %x1833, 272702481 + %x1835 = add i64 %x1834, 272553829 + %x1836 = sub i64 %x1835, 272405339 + %x1837 = add i64 %x1836, 272257010 + %x1838 = sub i64 %x1837, 272108843 + %x1839 = add i64 %x1838, 271960837 + %x1840 = sub i64 %x1839, 271812992 + %x1841 = add i64 %x1840, 271665308 + %x1842 = sub i64 %x1841, 271517784 + %x1843 = add i64 %x1842, 271370420 + %x1844 = sub i64 %x1843, 271223216 + %x1845 = add i64 %x1844, 271076172 + %x1846 = sub i64 %x1845, 270929287 + %x1847 = add i64 %x1846, 270782561 + %x1848 = sub i64 %x1847, 270635994 + %x1849 = add i64 %x1848, 270489586 + %x1850 = sub i64 %x1849, 270343336 + %x1851 = add i64 %x1850, 270197243 + %x1852 = sub i64 %x1851, 270051309 + %x1853 = add i64 %x1852, 269905533 + %x1854 = sub i64 %x1853, 269759913 + %x1855 = add i64 %x1854, 269614451 + %x1856 = sub i64 %x1855, 269469145 + %x1857 = add i64 %x1856, 269323996 + %x1858 = sub i64 %x1857, 269179004 + %x1859 = add i64 %x1858, 269034167 + %x1860 = sub i64 %x1859, 268889486 + %x1861 = add i64 %x1860, 268744961 + %x1862 = sub i64 %x1861, 268600590 + %x1863 = add i64 %x1862, 268456375 + %x1864 = sub i64 %x1863, 268312315 + %x1865 = add i64 %x1864, 268168409 + %x1866 = sub i64 %x1865, 268024658 + %x1867 = add i64 %x1866, 267881060 + %x1868 = sub i64 %x1867, 267737617 + %x1869 = add i64 %x1868, 267594327 + %x1870 = sub i64 %x1869, 267451190 + %x1871 = add i64 %x1870, 267308206 + %x1872 = sub i64 %x1871, 267165375 + %x1873 = add i64 %x1872, 267022696 + %x1874 = sub i64 %x1873, 266880170 + %x1875 = add i64 %x1874, 266737796 + %x1876 = sub i64 %x1875, 266595574 + %x1877 = add i64 %x1876, 266453503 + %x1878 = sub i64 %x1877, 266311584 + %x1879 = add i64 %x1878, 266169816 + %x1880 = sub i64 %x1879, 266028198 + %x1881 = add i64 %x1880, 265886732 + %x1882 = sub i64 %x1881, 265745415 + %x1883 = add i64 %x1882, 265604249 + %x1884 = sub i64 %x1883, 265463233 + %x1885 = add i64 %x1884, 265322366 + %x1886 = sub i64 %x1885, 265181649 + %x1887 = add i64 %x1886, 265041081 + %x1888 = sub i64 %x1887, 264900662 + %x1889 = add i64 %x1888, 264760391 + %x1890 = sub i64 %x1889, 264620269 + %x1891 = add i64 %x1890, 264480296 + %x1892 = sub i64 %x1891, 264340470 + %x1893 = add i64 %x1892, 264200792 + %x1894 = sub i64 %x1893, 264061262 + %x1895 = add i64 %x1894, 263921879 + %x1896 = sub i64 %x1895, 263782643 + %x1897 = add i64 %x1896, 263643553 + %x1898 = sub i64 %x1897, 263504611 + %x1899 = add i64 %x1898, 263365815 + %x1900 = sub i64 %x1899, 263227165 + %x1901 = add i64 %x1900, 263088660 + %x1902 = sub i64 %x1901, 262950302 + %x1903 = add i64 %x1902, 262812089 + %x1904 = sub i64 %x1903, 262674021 + %x1905 = add i64 %x1904, 262536098 + %x1906 = sub i64 %x1905, 262398320 + %x1907 = add i64 %x1906, 262260687 + %x1908 = sub i64 %x1907, 262123197 + %x1909 = add i64 %x1908, 261985852 + %x1910 = sub i64 %x1909, 261848651 + %x1911 = add i64 %x1910, 261711593 + %x1912 = sub i64 %x1911, 261574679 + %x1913 = add i64 %x1912, 261437908 + %x1914 = sub i64 %x1913, 261301280 + %x1915 = add i64 %x1914, 261164794 + %x1916 = sub i64 %x1915, 261028452 + %x1917 = add i64 %x1916, 260892251 + %x1918 = sub i64 %x1917, 260756192 + %x1919 = add i64 %x1918, 260620276 + %x1920 = sub i64 %x1919, 260484501 + %x1921 = add i64 %x1920, 260348867 + %x1922 = sub i64 %x1921, 260213374 + %x1923 = add i64 %x1922, 260078023 + %x1924 = sub i64 %x1923, 259942812 + %x1925 = add i64 %x1924, 259807742 + %x1926 = sub i64 %x1925, 259672812 + %x1927 = add i64 %x1926, 259538022 + %x1928 = sub i64 %x1927, 259403372 + %x1929 = add i64 %x1928, 259268861 + %x1930 = sub i64 %x1929, 259134490 + %x1931 = add i64 %x1930, 259000259 + %x1932 = sub i64 %x1931, 258866166 + %x1933 = add i64 %x1932, 258732212 + %x1934 = sub i64 %x1933, 258598396 + %x1935 = add i64 %x1934, 258464719 + %x1936 = sub i64 %x1935, 258331180 + %x1937 = add i64 %x1936, 258197779 + %x1938 = sub i64 %x1937, 258064516 + %x1939 = add i64 %x1938, 257931390 + %x1940 = sub i64 %x1939, 257798401 + %x1941 = add i64 %x1940, 257665550 + %x1942 = sub i64 %x1941, 257532835 + %x1943 = add i64 %x1942, 257400257 + %x1944 = sub i64 %x1943, 257267815 + %x1945 = add i64 %x1944, 257135510 + %x1946 = sub i64 %x1945, 257003341 + %x1947 = add i64 %x1946, 256871307 + %x1948 = sub i64 %x1947, 256739409 + %x1949 = add i64 %x1948, 256607646 + %x1950 = sub i64 %x1949, 256476019 + %x1951 = add i64 %x1950, 256344527 + %x1952 = sub i64 %x1951, 256213169 + %x1953 = add i64 %x1952, 256081946 + %x1954 = sub i64 %x1953, 255950857 + %x1955 = add i64 %x1954, 255819902 + %x1956 = sub i64 %x1955, 255689082 + %x1957 = add i64 %x1956, 255558395 + %x1958 = sub i64 %x1957, 255427841 + %x1959 = add i64 %x1958, 255297421 + %x1960 = sub i64 %x1959, 255167134 + %x1961 = add i64 %x1960, 255036980 + %x1962 = sub i64 %x1961, 254906958 + %x1963 = add i64 %x1962, 254777070 + %x1964 = sub i64 %x1963, 254647313 + %x1965 = add i64 %x1964, 254517688 + %x1966 = sub i64 %x1965, 254388196 + %x1967 = add i64 %x1966, 254258835 + %x1968 = sub i64 %x1967, 254129606 + %x1969 = add i64 %x1968, 254000508 + %x1970 = sub i64 %x1969, 253871541 + %x1971 = add i64 %x1970, 253742704 + %x1972 = sub i64 %x1971, 253613999 + %x1973 = add i64 %x1972, 253485424 + %x1974 = sub i64 %x1973, 253356979 + %x1975 = add i64 %x1974, 253228665 + %x1976 = sub i64 %x1975, 253100480 + %x1977 = add i64 %x1976, 252972426 + %x1978 = sub i64 %x1977, 252844500 + %x1979 = add i64 %x1978, 252716704 + %x1980 = sub i64 %x1979, 252589037 + %x1981 = add i64 %x1980, 252461499 + %x1982 = sub i64 %x1981, 252334090 + %x1983 = add i64 %x1982, 252206809 + %x1984 = sub i64 %x1983, 252079657 + %x1985 = add i64 %x1984, 251952632 + %x1986 = sub i64 %x1985, 251825736 + %x1987 = add i64 %x1986, 251698968 + %x1988 = sub i64 %x1987, 251572327 + %x1989 = add i64 %x1988, 251445813 + %x1990 = sub i64 %x1989, 251319426 + %x1991 = add i64 %x1990, 251193167 + %x1992 = sub i64 %x1991, 251067034 + %x1993 = add i64 %x1992, 250941028 + %x1994 = sub i64 %x1993, 250815149 + %x1995 = add i64 %x1994, 250689395 + %x1996 = sub i64 %x1995, 250563768 + %x1997 = add i64 %x1996, 250438266 + %x1998 = sub i64 %x1997, 250312891 + %x1999 = add i64 %x1998, 250187640 + %x2000 = sub i64 %x1999, 250062515 + %pi = mul i64 %x2000, 4 + %bop1 = icmp eq i64 %pi, 3141092653592 + br i1 %bop1, label %then1, label %else1 +then1: + ret i64 0 +else1: + ret i64 1 +} + diff --git a/hw6/llprograms/kaiterry_pi_opt.ll b/hw6/llprograms/kaiterry_pi_opt.ll new file mode 100644 index 0000000..50a0319 --- /dev/null +++ b/hw6/llprograms/kaiterry_pi_opt.ll @@ -0,0 +1,8 @@ +define i64 @main(i64 %argc, i8** %argv) { + br i1 1, label %then1, label %else1 +then1: + ret i64 0 +else1: + ret i64 1 +} + diff --git a/hw6/llprograms/kaiterry_units.ll b/hw6/llprograms/kaiterry_units.ll new file mode 100644 index 0000000..c4fccf7 --- /dev/null +++ b/hw6/llprograms/kaiterry_units.ll @@ -0,0 +1,54 @@ +define i64 @main(i64 %argc, i8** %argv) { + %one = add i64 0, 1 + %none = sub i64 0, %one + %five = add i64 0, 5 + %nfive = sub i64 0, %five + %ten = add i64 0, 10 + %nten = sub i64 0, %ten + %sixty = add i64 0, 60 + %1 = add i64 %ten, %five + %2 = sub i64 %ten, %five + %3 = mul i64 %ten, %five + %4 = shl i64 %ten, %one + %5 = lshr i64 %nten, %sixty + %6 = ashr i64 %nten, %one + %7 = and i64 %five, %one + %8 = or i64 %ten, %five + %9 = xor i64 %ten, %five + %t1 = icmp eq i64 %1, 15 + %t2 = icmp eq i64 %2, 5 + %t3 = icmp eq i64 %3, 50 + %t4 = icmp eq i64 %4, 20 + %t5 = icmp eq i64 %5, 15 + %t6 = icmp eq i64 %6, %nfive + %t7 = icmp eq i64 %7, 1 + %t8 = icmp eq i64 %8, 15 + %t9 = icmp eq i64 %9, 15 + %t9a = icmp ne i64 %9, 14 + %t9b = icmp slt i64 %9, 16 + %t9c = icmp sle i64 %9, 15 + %t9d = icmp sgt i64 %9, 14 + %t9e = icmp sgt i64 %9, %none + %t9f = icmp sge i64 %9, 15 + %r1 = and i1 %t1, 1 + %r2 = and i1 %t2, %r1 + %r3 = and i1 %t3, %r2 + %r4 = and i1 %t4, %r3 + %r5 = and i1 %t5, %r4 + %r6 = and i1 %t6, %r5 + %r7 = and i1 %t7, %r6 + %r8 = and i1 %t8, %r7 + %r9 = and i1 %t9, %r8 + %r9a = and i1 %t9a, %r9 + %r9b = and i1 %t9b, %r9a + %r9c = and i1 %t9c, %r9b + %r9d = and i1 %t9d, %r9c + %r9e = and i1 %t9e, %r9d + %r9f = and i1 %t9f, %r9e + br i1 %r9f, label %then1, label %else1 +then1: + ret i64 1 +else1: + ret i64 0 +} + diff --git a/hw6/llprograms/kaiterry_units_opt.ll b/hw6/llprograms/kaiterry_units_opt.ll new file mode 100644 index 0000000..984dc45 --- /dev/null +++ b/hw6/llprograms/kaiterry_units_opt.ll @@ -0,0 +1,8 @@ +define i64 @main(i64 %argc, i8** %argv) { + br i1 1, label %then1, label %else1 +then1: + ret i64 1 +else1: + ret i64 0 +} + diff --git a/hw6/llprograms/kierajmumick.ll b/hw6/llprograms/kierajmumick.ll new file mode 100644 index 0000000..1be5e0f --- /dev/null +++ b/hw6/llprograms/kierajmumick.ll @@ -0,0 +1,9 @@ +define i64 @program(i64 %argc, i8** %argv) { + %1 = add i64 30, 0 + %2 = sub i64 420, 24 + %3 = add i64 24, %2 + %4 = alloca i64 + store i64 %3, i64* %4 + ret i64 420 +} + diff --git a/hw6/llprograms/kierajmumickopt.ll b/hw6/llprograms/kierajmumickopt.ll new file mode 100644 index 0000000..65d615e --- /dev/null +++ b/hw6/llprograms/kierajmumickopt.ll @@ -0,0 +1,4 @@ +define i64 @program(i64 %argc, i8** %argv) { + ret i64 420 +} + diff --git a/hw6/llprograms/lfsr.ll b/hw6/llprograms/lfsr.ll new file mode 100644 index 0000000..679bd44 --- /dev/null +++ b/hw6/llprograms/lfsr.ll @@ -0,0 +1,29 @@ +define i64 @one_iteration(i64 %n) { + %1 = shl i64 %n, 1 + %2 = xor i64 %n, %1 + %3 = shl i64 %1, 2 + %4 = xor i64 %2, %3 + %5 = shl i64 %3, 1 + %6 = xor i64 %4, %5 + %7 = lshr i64 %6, 63 + %8 = and i64 %7, 1 + %9 = or i64 %6, %8 + ret i64 %9 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %ctr = alloca i64 + store i64 1, i64* %ctr + %1 = add i64 12, 0 + br i1 1, label %loop, label %loop +loop: + %2 = load i64, i64* %ctr + %3 = add i64 %2, 1 + store i64 %3, i64* %ctr + %4 = call i64 @one_iteration(i64 %2) + %cmp = icmp eq i64 %3, 5 + br i1 %cmp, label %end, label %loop +end: + ret i64 %4 +} + diff --git a/hw6/llprograms/linear_search.ll b/hw6/llprograms/linear_search.ll new file mode 100644 index 0000000..3411abe --- /dev/null +++ b/hw6/llprograms/linear_search.ll @@ -0,0 +1,28 @@ +@glist = global [5 x i64] [ i64 1, i64 2, i64 3, i64 4, i64 5 ] + +define i64 @search(i64 %x, [5 x i64]* %list) { + %i = alloca i64 + store i64 0, i64* %i + br label %loop +loop: + %count = load i64, i64* %i + %cmp1 = icmp eq i64 %count, 5 + br i1 %cmp1, label %false, label %check +check: + %ptr = getelementptr [5 x i64], [5 x i64]* %list, i32 0, i64 %count + %val = load i64, i64* %ptr + %cmp2 = icmp eq i64 %x, %val + %a = add i64 1, %count + store i64 %a, i64* %i + br i1 %cmp2, label %true, label %loop +true: + ret i64 1 +false: + ret i64 0 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %r = call i64 @search(i64 3, [5 x i64]* @glist) + ret i64 %r +} + diff --git a/hw6/llprograms/list1.ll b/hw6/llprograms/list1.ll new file mode 100644 index 0000000..0931924 --- /dev/null +++ b/hw6/llprograms/list1.ll @@ -0,0 +1,18 @@ +%node = type { i64, %node* } + +@hd = global %node { i64 1, %node* @md } +@md = global %node { i64 2, %node* @tl } +@tl = global %node { i64 3, %node* null } + +define i64 @main(i64 %argc, i8** %arcv) { + %head = getelementptr %node, %node* @hd, i32 0, i32 0 + %link = getelementptr %node, %node* @hd, i32 0, i32 1 + %next = load %node*, %node** %link + %val = getelementptr %node, %node* %next, i32 0, i32 0 + %link2 = getelementptr %node, %node* %next, i32 0, i32 1 + %next2 = load %node*, %node** %link2 + %val2 = getelementptr %node, %node* %next2, i32 0, i32 0 + %1 = load i64, i64* %val2 + ret i64 %1 +} + diff --git a/hw6/llprograms/lshr.ll b/hw6/llprograms/lshr.ll new file mode 100644 index 0000000..7a95ad0 --- /dev/null +++ b/hw6/llprograms/lshr.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = lshr i64 42, 2 + ret i64 %1 +} + diff --git a/hw6/llprograms/matmul.ll b/hw6/llprograms/matmul.ll new file mode 100644 index 0000000..e50f98a --- /dev/null +++ b/hw6/llprograms/matmul.ll @@ -0,0 +1,110 @@ +%vec = type [2 x i64] +%mat = type [2 x %vec] + +@mat1 = global %mat [ %vec [ i64 1, i64 2 ], %vec [ i64 3, i64 4 ] ] +@mat2 = global %mat [ %vec [ i64 5, i64 6 ], %vec [ i64 7, i64 8 ] ] +@mat3 = global %mat [ %vec [ i64 19, i64 22 ], %vec [ i64 43, i64 50 ] ] +@matr = global %mat [ %vec [ i64 0, i64 0 ], %vec [ i64 0, i64 0 ] ] + +define i64 @main(i64 %argc, i8** %argv) { + %cnt = alloca i64 + store i64 10000000, i64* %cnt + br label %loop + +loop: + %tmp = load i64, i64* %cnt + %b = icmp eq i64 %tmp, 0 + br i1 %b, label %exit, label %body + +body: + call void @matmul(%mat* @mat1, %mat* @mat2, %mat* @matr) + %ans = call i64 @mateq(%mat* @mat3, %mat* @matr) + %tmp2 = load i64, i64* %cnt + %tmp3 = sub i64 %tmp2, 1 + store i64 %tmp3, i64* %cnt + br label %loop + +exit: + ret i64 0 +} + +define void @matmul(%mat* %a, %mat* %b, %mat* %c) { + %i = alloca i64 + %j = alloca i64 + store i64 0, i64* %i + br label %starti +starti: + %iv = load i64, i64* %i + %ic = icmp slt i64 %iv, 2 + br i1 %ic, label %theni, label %endi +theni: + store i64 0, i64* %j + br label %startj +startj: + %jv = load i64, i64* %j + %jc = icmp slt i64 %jv, 2 + br i1 %jc, label %thenj, label %endj +thenj: + %r = getelementptr %mat, %mat* %c, i32 0, i64 %iv, i64 %jv + %a1 = getelementptr %mat, %mat* %a, i32 0, i64 %iv, i32 0 + %b1 = getelementptr %mat, %mat* %b, i32 0, i32 0, i64 %jv + %a2 = getelementptr %mat, %mat* %a, i32 0, i64 %iv, i32 1 + %b2 = getelementptr %mat, %mat* %b, i32 0, i32 1, i64 %jv + %a1v = load i64, i64* %a1 + %b1v = load i64, i64* %b1 + %a2v = load i64, i64* %a2 + %b2v = load i64, i64* %b2 + %ab1 = mul i64 %a1v, %b1v + %ab2 = mul i64 %a2v, %b2v + %ab = add i64 %ab1, %ab2 + store i64 %ab, i64* %r + %jinc = add i64 %jv, 1 + store i64 %jinc, i64* %j + br label %startj +endj: + %iinc = add i64 %iv, 1 + store i64 %iinc, i64* %i + br label %starti +endi: + ret void +} + +define i64 @mateq(%mat* %ma, %mat* %mb) { + %r = alloca i64 + store i64 0, i64* %r + %i = alloca i64 + %j = alloca i64 + store i64 0, i64* %i + br label %starti1 +starti1: + %iv = load i64, i64* %i + %ic = icmp slt i64 %iv, 2 + br i1 %ic, label %theni1, label %endi1 +theni1: + store i64 0, i64* %j + br label %startj1 +startj1: + %jv = load i64, i64* %j + %jc = icmp slt i64 %jv, 2 + br i1 %jc, label %thenj1, label %endj1 +thenj1: + %a = getelementptr %mat, %mat* %ma, i32 0, i64 %iv, i64 %jv + %b = getelementptr %mat, %mat* %mb, i32 0, i64 %iv, i64 %jv + %av = load i64, i64* %a + %bv = load i64, i64* %b + %cmp = xor i64 %av, %bv + %rv = load i64, i64* %r + %tmp = or i64 %cmp, %rv + store i64 %tmp, i64* %r + %jinc = add i64 %jv, 1 + store i64 %jinc, i64* %j + br label %startj1 +endj1: + %iinc = add i64 %iv, 1 + store i64 %iinc, i64* %i + br label %starti1 +endi1: + %rv1 = load i64, i64* %r + ret i64 %rv1 +} + diff --git a/hw6/llprograms/max_thomas_test.ll b/hw6/llprograms/max_thomas_test.ll new file mode 100644 index 0000000..3437726 --- /dev/null +++ b/hw6/llprograms/max_thomas_test.ll @@ -0,0 +1,22 @@ +define i64 @main(i64 %argc, i8** %argv) { + %a = alloca i64 + store i64 1, i64* %a + %b = alloca i64* + store i64* %a, i64** %b + %c = alloca i64** + store i64** %b, i64*** %c + %d = alloca i64*** + store i64*** %c, i64**** %d + %e = alloca i64**** + store i64**** %d, i64***** %e + %f = alloca i64***** + store i64***** %e, i64****** %f + %g = alloca i64****** + store i64****** %f, i64******* %g + %h = alloca i64******* + store i64******* %g, i64******** %h + %i = alloca i64******** + store i64******** %h, i64********* %i + ret i64 120 +} + diff --git a/hw6/llprograms/max_thomas_test_opt.ll b/hw6/llprograms/max_thomas_test_opt.ll new file mode 100644 index 0000000..1b5b7e8 --- /dev/null +++ b/hw6/llprograms/max_thomas_test_opt.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %argv) { + ret i64 120 +} + diff --git a/hw6/llprograms/mul.ll b/hw6/llprograms/mul.ll new file mode 100644 index 0000000..a3c6f49 --- /dev/null +++ b/hw6/llprograms/mul.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = mul i64 5, 9 + ret i64 %1 +} + diff --git a/hw6/llprograms/naive_factor_nonprime.ll b/hw6/llprograms/naive_factor_nonprime.ll new file mode 100644 index 0000000..a504f02 --- /dev/null +++ b/hw6/llprograms/naive_factor_nonprime.ll @@ -0,0 +1,44 @@ +define i64 @naive_mod(i64 %top, i64 %bottom) { + %product_sum = alloca i64 + store i64 0, i64* %product_sum + br label %start +start: + %1 = load i64, i64* %product_sum + %plus = add i64 %bottom, %1 + store i64 %plus, i64* %product_sum + %exceeded = icmp sgt i64 %plus, %top + br i1 %exceeded, label %final, label %start +final: + %2 = load i64, i64* %product_sum + %un_exceeded = sub i64 %2, %bottom + %out = sub i64 %top, %un_exceeded + ret i64 %out +} + +define i64 @naive_prime(i64 %n) { + %factor_attempt = alloca i64 + store i64 2, i64* %factor_attempt + br label %loop +loop: + %1 = load i64, i64* %factor_attempt + %sqr = mul i64 %1, %1 + %exceed_cap = icmp sgt i64 %sqr, %n + br i1 %exceed_cap, label %final_true, label %inc +inc: + %2 = load i64, i64* %factor_attempt + %plus = add i64 1, %1 + store i64 %plus, i64* %factor_attempt + %mod_result = call i64 @naive_mod(i64 %n, i64 %2) + %is_composite = icmp eq i64 0, %mod_result + br i1 %is_composite, label %final_false, label %loop +final_false: + ret i64 0 +final_true: + ret i64 1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %result = call i64 @naive_prime(i64 100) + ret i64 %result +} + diff --git a/hw6/llprograms/naive_factor_prime.ll b/hw6/llprograms/naive_factor_prime.ll new file mode 100644 index 0000000..395379e --- /dev/null +++ b/hw6/llprograms/naive_factor_prime.ll @@ -0,0 +1,44 @@ +define i64 @naive_mod(i64 %top, i64 %bottom) { + %product_sum = alloca i64 + store i64 0, i64* %product_sum + br label %start +start: + %1 = load i64, i64* %product_sum + %plus = add i64 %bottom, %1 + store i64 %plus, i64* %product_sum + %exceeded = icmp sgt i64 %plus, %top + br i1 %exceeded, label %final, label %start +final: + %2 = load i64, i64* %product_sum + %un_exceeded = sub i64 %2, %bottom + %out = sub i64 %top, %un_exceeded + ret i64 %out +} + +define i64 @naive_prime(i64 %n) { + %factor_attempt = alloca i64 + store i64 2, i64* %factor_attempt + br label %loop +loop: + %1 = load i64, i64* %factor_attempt + %sqr = mul i64 %1, %1 + %exceed_cap = icmp sgt i64 %sqr, %n + br i1 %exceed_cap, label %final_true, label %inc +inc: + %2 = load i64, i64* %factor_attempt + %plus = add i64 1, %1 + store i64 %plus, i64* %factor_attempt + %mod_result = call i64 @naive_mod(i64 %n, i64 %2) + %is_composite = icmp eq i64 0, %mod_result + br i1 %is_composite, label %final_false, label %loop +final_false: + ret i64 0 +final_true: + ret i64 1 +} + +define i64 @main(i64 %argc, i8** %arcv) { + %result = call i64 @naive_prime(i64 19) + ret i64 %result +} + diff --git a/hw6/llprograms/opt_cbr_test1.ll b/hw6/llprograms/opt_cbr_test1.ll new file mode 100644 index 0000000..ceb5fb7 --- /dev/null +++ b/hw6/llprograms/opt_cbr_test1.ll @@ -0,0 +1,19 @@ +define i64 @program(i64 %argc, i8** %arcv) { + %1 = add i64 0, 64 + %2 = alloca i64 + store i64 %1, i64* %2 + %3 = load i64, i64* %2 + %4 = mul i64 4, 12 + %5 = icmp sgt i64 %4, 52 + br i1 %5, label %then, label %else +then: + store i64 8, i64* %2 + br label %merge +else: + store i64 0, i64* %2 + br label %merge +merge: + %6 = load i64, i64* %2 + ret i64 %6 +} + diff --git a/hw6/llprograms/opt_globals_test1.ll b/hw6/llprograms/opt_globals_test1.ll new file mode 100644 index 0000000..36d30a3 --- /dev/null +++ b/hw6/llprograms/opt_globals_test1.ll @@ -0,0 +1,12 @@ +@x = global i64 1 +@y = global i64 2 + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = load i64, i64* @x + %2 = mul i64 %1, 7 + %3 = load i64, i64* @y + %4 = add i64 %3, 1 + store i64 %4, i64* @y + ret i64 %1 +} + diff --git a/hw6/llprograms/opt_globals_test1_soln.ll b/hw6/llprograms/opt_globals_test1_soln.ll new file mode 100644 index 0000000..615b2a8 --- /dev/null +++ b/hw6/llprograms/opt_globals_test1_soln.ll @@ -0,0 +1,8 @@ +@x = global i64 1 +@y = global i64 2 + +define i64 @program(i64 %argc, i8** %arcv) { + %1 = load i64, i64* @x + ret i64 %1 +} + diff --git a/hw6/llprograms/or.ll b/hw6/llprograms/or.ll new file mode 100644 index 0000000..5b11be5 --- /dev/null +++ b/hw6/llprograms/or.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = or i64 1, 0 + ret i64 %1 +} + diff --git a/hw6/llprograms/puts.ll b/hw6/llprograms/puts.ll new file mode 100644 index 0000000..3665036 --- /dev/null +++ b/hw6/llprograms/puts.ll @@ -0,0 +1,20 @@ +define i64 @main(i64 %argc, i8** %argv) { + %p1 = getelementptr i8*, i8** %argv, i32 1 + %a1 = load i8*, i8** %p1 + %p2 = getelementptr i8*, i8** %argv, i32 2 + %a2 = load i8*, i8** %p2 + %r = call i8* @strcat(i8* %a1, i8* %a2) + ret i64 0 +} + +define i8* @strcat(i8* %s1, i8* %s2) { + %l1 = call i64 @ll_strlen(i8* %s1) + %l2 = call i64 @ll_strlen(i8* %s2) + %l3 = add i64 %l1, %l2 + %p = call i8* @ll_malloc(i64 %l3) + %r1 = call i8* @ll_strncpy(i8* %p, i8* %s1, i64 0) + %r2 = call i8* @ll_strncpy(i8* %p, i8* %s2, i64 %l1) + call void @ll_puts(i8* %p) + ret i8* %p +} + diff --git a/hw6/llprograms/qtree.ll b/hw6/llprograms/qtree.ll new file mode 100644 index 0000000..81fdc74 --- /dev/null +++ b/hw6/llprograms/qtree.ll @@ -0,0 +1,13 @@ +%vec = type [2 x i64] +%centroid = type { i64, %vec } +%qtree = type { %centroid, [4 x %qtree*] } +%qtrees = type [1 x %qtree] + +@gbl = global %qtrees [ %qtree { %centroid { i64 1, %vec [ i64 2, i64 3 ] }, [4 x %qtree*] [ %qtree* null, %qtree* null, %qtree* null, %qtree* null ] } ] + +define i64 @main(i64 %argc, i8** %argv) { + %1 = getelementptr %qtrees, %qtrees* @gbl, i32 0, i32 0, i32 0, i32 1, i32 1 + %2 = load i64, i64* %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/reed_nate_opt.ll b/hw6/llprograms/reed_nate_opt.ll new file mode 100644 index 0000000..cd467c5 --- /dev/null +++ b/hw6/llprograms/reed_nate_opt.ll @@ -0,0 +1,10 @@ +define i64 @program(i64 %argc, i8** %arcv) { + br i1 0, label %l1, label %l2 +l1: + br i1 1, label %l2, label %l3 +l2: + ret i64 2500 +l3: + ret i64 0 +} + diff --git a/hw6/llprograms/regtest1.ll b/hw6/llprograms/regtest1.ll new file mode 100644 index 0000000..4d776b3 --- /dev/null +++ b/hw6/llprograms/regtest1.ll @@ -0,0 +1,10 @@ +define i64 @foo(i64 %x, i64 %y) { + %z = add i64 %x, %y + ret i64 %z +} + +define i64 @main(i64 %argc, i8** %arcv) { + %v = add i64 341, 42 + %ans = call i64 @foo(i64 %v, i64 %v) + ret i64 %ans +} diff --git a/hw6/llprograms/return.ll b/hw6/llprograms/return.ll new file mode 100644 index 0000000..f3bab9d --- /dev/null +++ b/hw6/llprograms/return.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + ret i64 0 +} + diff --git a/hw6/llprograms/return42.ll b/hw6/llprograms/return42.ll new file mode 100644 index 0000000..0ddd39b --- /dev/null +++ b/hw6/llprograms/return42.ll @@ -0,0 +1,6 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = alloca i64 + store i64 0, i64* %1 + ret i64 42 +} + diff --git a/hw6/llprograms/return_intermediate.ll b/hw6/llprograms/return_intermediate.ll new file mode 100644 index 0000000..72202fc --- /dev/null +++ b/hw6/llprograms/return_intermediate.ll @@ -0,0 +1,7 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = mul i64 3, 6 + %3 = sub i64 %2, %1 + ret i64 %2 +} + diff --git a/hw6/llprograms/return_intermediate_dce.ll b/hw6/llprograms/return_intermediate_dce.ll new file mode 100644 index 0000000..85fa6d2 --- /dev/null +++ b/hw6/llprograms/return_intermediate_dce.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + ret i64 18 +} + diff --git a/hw6/llprograms/return_intermediate_fold.ll b/hw6/llprograms/return_intermediate_fold.ll new file mode 100644 index 0000000..5f68f1f --- /dev/null +++ b/hw6/llprograms/return_intermediate_fold.ll @@ -0,0 +1,6 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = add i64 5, 9 + %2 = mul i64 3, 6 + ret i64 18 +} + diff --git a/hw6/llprograms/returnvoid.ll b/hw6/llprograms/returnvoid.ll new file mode 100644 index 0000000..9f1681e --- /dev/null +++ b/hw6/llprograms/returnvoid.ll @@ -0,0 +1,4 @@ +define void @main(i64 %argc, i8** %arcv) { + ret void +} + diff --git a/hw6/llprograms/rsa.ll b/hw6/llprograms/rsa.ll new file mode 100644 index 0000000..6a231a7 --- /dev/null +++ b/hw6/llprograms/rsa.ll @@ -0,0 +1,55 @@ +define i64 @rsa_decrypt(i64 %c) { + %p = add i64 56807, 0 + %q = add i64 51683, 0 + %n = mul i64 %p, %q + %d = add i64 1409083253, 0 + %e = add i64 65537, 0 + %_b__3 = alloca i64 + store i64 %c, i64* %_b__3 + %_e__1 = alloca i64 + store i64 %d, i64* %_e__1 + %_res__5 = alloca i64 + store i64 1, i64* %_res__5 + %_i__7 = alloca i64 + store i64 0, i64* %_i__7 + br label %_cond__14 +_cond__14: + %_val___9 = load i64, i64* %_i__7 + %_val___10 = load i64, i64* %_e__1 + %_bop___11 = icmp slt i64 %_val___9, %_val___10 + br i1 %_bop___11, label %_body__13, label %_post__12 +_body__13: + %_val___15 = load i64, i64* %_res__5 + %_val___16 = load i64, i64* %_b__3 + %_bop___17 = mul i64 %_val___15, %_val___16 + store i64 %_bop___17, i64* %_res__5 + %_val___19 = load i64, i64* %_i__7 + %_bop___20 = add i64 %_val___19, 1 + store i64 %_bop___20, i64* %_i__7 + br label %_cond__14 +_post__12: + %_pow_res = load i64, i64* %_res__5 + %_x__25 = alloca i64 + store i64 %_pow_res, i64* %_x__25 + %_y__23 = alloca i64 + store i64 %n, i64* %_y__23 + %_val___27 = load i64, i64* %_x__25 + %_res__28 = alloca i64 + store i64 %_val___27, i64* %_res__28 + br label %_cond__35 +_cond__35: + %_val___30 = load i64, i64* %_res__28 + %_val___31 = load i64, i64* %_y__23 + %_bop___32 = icmp sge i64 %_val___30, %_val___31 + br i1 %_bop___32, label %_body__34, label %_post__33 +_body__34: + %_val___36 = load i64, i64* %_res__28 + %_val___37 = load i64, i64* %_y__23 + %_bop___38 = sub i64 %_val___36, %_val___37 + store i64 %_bop___38, i64* %_res__28 + br label %_cond__35 +_post__33: + %m = load i64, i64* %_res__28 + ret i64 %m +} + diff --git a/hw6/llprograms/rsaopt.ll b/hw6/llprograms/rsaopt.ll new file mode 100644 index 0000000..f0be90b --- /dev/null +++ b/hw6/llprograms/rsaopt.ll @@ -0,0 +1,50 @@ +define i64 @rsa_decrypt(i64 %c) { + %_b__3 = alloca i64 + store i64 %c, i64* %_b__3 + %_e__1 = alloca i64 + store i64 1409083253, i64* %_e__1 + %_res__5 = alloca i64 + store i64 1, i64* %_res__5 + %_i__7 = alloca i64 + store i64 0, i64* %_i__7 + br label %_cond__14 +_body__13: + %_val___15 = load i64, i64* %_res__5 + %_val___16 = load i64, i64* %_b__3 + %_bop___17 = mul i64 %_val___15, %_val___16 + store i64 %_bop___17, i64* %_res__5 + %_val___19 = load i64, i64* %_i__7 + %_bop___20 = add i64 %_val___19, 1 + store i64 %_bop___20, i64* %_i__7 + br label %_cond__14 +_body__34: + %_val___36 = load i64, i64* %_res__28 + %_val___37 = load i64, i64* %_y__23 + %_bop___38 = sub i64 %_val___36, %_val___37 + store i64 %_bop___38, i64* %_res__28 + br label %_cond__35 +_cond__14: + %_val___9 = load i64, i64* %_i__7 + %_val___10 = load i64, i64* %_e__1 + %_bop___11 = icmp slt i64 %_val___9, %_val___10 + br i1 %_bop___11, label %_body__13, label %_post__12 +_cond__35: + %_val___30 = load i64, i64* %_res__28 + %_val___31 = load i64, i64* %_y__23 + %_bop___32 = icmp sge i64 %_val___30, %_val___31 + br i1 %_bop___32, label %_body__34, label %_post__33 +_post__12: + %_pow_res = load i64, i64* %_res__5 + %_x__25 = alloca i64 + store i64 %_pow_res, i64* %_x__25 + %_y__23 = alloca i64 + store i64 2935956181, i64* %_y__23 + %_val___27 = load i64, i64* %_x__25 + %_res__28 = alloca i64 + store i64 %_val___27, i64* %_res__28 + br label %_cond__35 +_post__33: + %m = load i64, i64* %_res__28 + ret i64 %m +} + diff --git a/hw6/llprograms/shl.ll b/hw6/llprograms/shl.ll new file mode 100644 index 0000000..f2a42ef --- /dev/null +++ b/hw6/llprograms/shl.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = shl i64 42, 2 + ret i64 %1 +} + diff --git a/hw6/llprograms/sieve.ll b/hw6/llprograms/sieve.ll new file mode 100644 index 0000000..be6d4c4 --- /dev/null +++ b/hw6/llprograms/sieve.ll @@ -0,0 +1,70 @@ +define i64 @main(i64 %argc, i8** %argv) { + %1 = call i64 @is_prime(i64 347) + ret i64 %1 +} + +define i64 @is_prime(i64 %n) { + %sieve = call i64* @ll_malloc(i64 8, i64 10000) + %1 = getelementptr i64, i64* %sieve, i32 0 + store i64 0, i64* %1 + %2 = getelementptr i64, i64* %sieve, i32 1 + store i64 0, i64* %2 + br label %start1 +start1: + %i = alloca i64 + store i64 2, i64* %i + br label %cmp1 +cmp1: + %3 = load i64, i64* %i + %4 = icmp slt i64 %3, 10000 + br i1 %4, label %loop1, label %end1 +loop1: + %5 = load i64, i64* %i + %6 = getelementptr i64, i64* %sieve, i64 %5 + store i64 1, i64* %6 + %7 = add i64 %5, 1 + store i64 %7, i64* %i + br label %cmp1 +end1: + br label %start2 +start2: + store i64 2, i64* %i + br label %cmp2 +cmp2: + %8 = load i64, i64* %i + %9 = icmp slt i64 %8, 10000 + br i1 %9, label %loop2, label %end2 +loop2: + %10 = load i64, i64* %i + %11 = getelementptr i64, i64* %sieve, i64 %10 + %12 = load i64, i64* %11 + %13 = icmp eq i64 %12, 1 + br i1 %13, label %then1, label %else1 +then1: + %j = alloca i64 + %14 = add i64 %10, %10 + store i64 %14, i64* %j + br label %cmp3 +cmp3: + %15 = load i64, i64* %j + %16 = icmp slt i64 %15, 10000 + br i1 %16, label %loop3, label %end3 +loop3: + %17 = getelementptr i64, i64* %sieve, i64 %15 + store i64 0, i64* %17 + %18 = add i64 %15, %10 + store i64 %18, i64* %j + br label %cmp3 +end3: + br label %else1 +else1: + %19 = load i64, i64* %i + %20 = add i64 %19, 1 + store i64 %20, i64* %i + br label %cmp2 +end2: + %ptr = getelementptr i64, i64* %sieve, i64 %n + %r = load i64, i64* %ptr + ret i64 %r +} + diff --git a/hw6/llprograms/string1.ll b/hw6/llprograms/string1.ll new file mode 100644 index 0000000..4027d21 --- /dev/null +++ b/hw6/llprograms/string1.ll @@ -0,0 +1,12 @@ +declare void @ll_puts(i8*) +declare i8* @ll_strcat(i8*, i8*) + +@gstr = global [14 x i8] c"hello, world!\00" + +define i64 @main(i64 %argc, i8** %argv) { + %1 = getelementptr [14 x i8], [14 x i8]* @gstr, i32 0, i32 0 + %2 = call i8* @ll_strcat (i8* %1, i8* %1) + call void @ll_puts (i8* %2) + ret i64 0 +} + diff --git a/hw6/llprograms/sub.ll b/hw6/llprograms/sub.ll new file mode 100644 index 0000000..c90e1a8 --- /dev/null +++ b/hw6/llprograms/sub.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = sub i64 10, 9 + ret i64 %1 +} + diff --git a/hw6/llprograms/sub_neg.ll b/hw6/llprograms/sub_neg.ll new file mode 100644 index 0000000..ec1c5a5 --- /dev/null +++ b/hw6/llprograms/sub_neg.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = sub i64 9, 10 + ret i64 %1 +} + diff --git a/hw6/llprograms/sub_neg_dce.ll b/hw6/llprograms/sub_neg_dce.ll new file mode 100644 index 0000000..f29182f --- /dev/null +++ b/hw6/llprograms/sub_neg_dce.ll @@ -0,0 +1,4 @@ +define i64 @main(i64 %argc, i8** %arcv) { + ret i64 -1 +} + diff --git a/hw6/llprograms/sub_neg_fold.ll b/hw6/llprograms/sub_neg_fold.ll new file mode 100644 index 0000000..c2978f9 --- /dev/null +++ b/hw6/llprograms/sub_neg_fold.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = sub i64 9, 10 + ret i64 -1 +} + diff --git a/hw6/llprograms/sum_tree.ll b/hw6/llprograms/sum_tree.ll new file mode 100644 index 0000000..71cb882 --- /dev/null +++ b/hw6/llprograms/sum_tree.ll @@ -0,0 +1,31 @@ +%struct.Node = type { %struct.Node*, %struct.Node*, i64 } + +@test1 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 100 } +@test2 = global %struct.Node { %struct.Node* @test1, %struct.Node* null, i64 10 } +@test3 = global %struct.Node { %struct.Node* null, %struct.Node* null, i64 1 } +@test = global %struct.Node { %struct.Node* @test2, %struct.Node* @test3, i64 5 } + +define i64 @sum_tree(%struct.Node* %t) { + %1 = icmp eq %struct.Node* %t, null + br i1 %1, label %then, label %else +then: + ret i64 0 +else: + %2 = getelementptr %struct.Node, %struct.Node* %t, i32 0, i32 2 + %3 = load i64, i64* %2 + %4 = getelementptr %struct.Node, %struct.Node* %t, i32 0, i32 1 + %5 = load %struct.Node*, %struct.Node** %4 + %6 = call i64 @sum_tree(%struct.Node* %5) + %7 = add i64 %3, %6 + %8 = getelementptr %struct.Node, %struct.Node* %t, i32 0, i32 0 + %9 = load %struct.Node*, %struct.Node** %8 + %10 = call i64 @sum_tree(%struct.Node* %9) + %11 = add i64 %7, %10 + ret i64 %11 +} + +define i64 @main(i64 %argc, i8** %argv) { + %1 = call i64 @sum_tree(%struct.Node* @test) + ret i64 %1 +} + diff --git a/hw6/llprograms/vivekraj_jjlee.ll b/hw6/llprograms/vivekraj_jjlee.ll new file mode 100644 index 0000000..b31a6f5 --- /dev/null +++ b/hw6/llprograms/vivekraj_jjlee.ll @@ -0,0 +1,12 @@ +define i64 @program(i64 %argc, i8** %argv) { + %a = xor i64 1, 2 + %b = mul i64 -3, 31 + %c = add i64 %b, 99 + %d = icmp slt i64 %c, 0 + br i1 %d, label %then, label %else +then: + ret i64 0 +else: + ret i64 1 +} + diff --git a/hw6/llprograms/vivekraj_jjlee_opt.ll b/hw6/llprograms/vivekraj_jjlee_opt.ll new file mode 100644 index 0000000..c30b0d3 --- /dev/null +++ b/hw6/llprograms/vivekraj_jjlee_opt.ll @@ -0,0 +1,8 @@ +define i64 @program(i64 %argc, i8** %argv) { + br i1 0, label %then, label %else +then: + ret i64 0 +else: + ret i64 1 +} + diff --git a/hw6/llprograms/xor.ll b/hw6/llprograms/xor.ll new file mode 100644 index 0000000..ed62864 --- /dev/null +++ b/hw6/llprograms/xor.ll @@ -0,0 +1,5 @@ +define i64 @main(i64 %argc, i8** %arcv) { + %1 = xor i64 0, 0 + ret i64 %1 +} + diff --git a/hw6/main.ml b/hw6/main.ml new file mode 100644 index 0000000..15aa330 --- /dev/null +++ b/hw6/main.ml @@ -0,0 +1,49 @@ +open Ll +open Arg +open Assert +open Driver + +exception Ran_tests +let suite = ref (Gradedtests.graded_tests) + +let execute_tests () = + Platform.configure_os (); + let outcome = run_suite !suite in + Printf.printf "%s\n" (outcome_to_string outcome); + raise Ran_tests + +let args = + [ ("-linux", Set Platform.linux, "use linux-style name mangling [must preceed --test on linux]") + ; ("--test", Unit execute_tests, "run the test suite, ignoring other files inputs") + ; ("-op", Set_string Platform.output_path, "set the path to the output files directory [default='output']") + ; ("-o", Set_string executable_filename, "set the name of the resulting executable [default='a.out']") + ; ("-S", Clear assemble, "stop after generating .s files; do generate .o files") + ; ("-c", Clear link, "stop after generating .o files; do not generate executables") + ; ("--print-ll", Set print_ll_flag, "prints the program's LL code (after lowering to clang code if --clang-malloc is set)") + ; ("--print-x86", Set print_x86_flag, "prints the program's assembly code") + ; ("--clang", Set clang, "compiles to assembly using clang, not the Compiler Design backend (implies --clang-malloc)") + ; ("--execute-x86", Set execute_x86, "run the resulting executable file") + ; ("-v", Set Platform.verbose, "enables more verbose compilation output") + ; ("-O1", Set Opt.do_opt, "enable optimization") + ; ("--regalloc", Symbol (["none"; "greedy"; "better"], Backend.set_regalloc), " use the specified register allocator") + ; ("--liveness", Symbol (["trivial"; "dataflow"], Backend.set_liveness), " use the specified liveness analysis") + ; ("--print-regs", Set print_regs_flag, "prints the register usage statistics for x86 code") + ] + +let files = ref [] + +let _ = + Gc.set { (Gc.get()) with Gc.minor_heap_size = (1000448 * 32); + Gc.major_heap_increment = (1000448 * 64); }; + Platform.configure_os (); + Platform.create_output_dir (); + try + Arg.parse args (fun filename -> files := filename :: !files) + "Compiler Design main test harness\n\ + USAGE: ./main.native [options] \n\ + see README for details about using the compiler"; + Platform.configure_os (); + process_files !files + + with Ran_tests -> + () diff --git a/hw6/oatprograms/arrayargs.oat b/hw6/oatprograms/arrayargs.oat new file mode 100644 index 0000000..ef8be3e --- /dev/null +++ b/hw6/oatprograms/arrayargs.oat @@ -0,0 +1,20 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +int program (int argc, string[] argv) { + var x = new int[3]; + for (var i=0; i<3; i = i+1;) { + x[i] = i; + } + var y = new int[3]; + for (var i=0; i<3; i = i+1;) { + y[i] = i+3; + } + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw6/oatprograms/arrayargs1.oat b/hw6/oatprograms/arrayargs1.oat new file mode 100644 index 0000000..74ec125 --- /dev/null +++ b/hw6/oatprograms/arrayargs1.oat @@ -0,0 +1,16 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +global x = new int[]{1, 2, 3}; +global y = new int[]{4, 5, 6}; + + +int program (int argc, string[] argv) { + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw6/oatprograms/arrayargs2.oat b/hw6/oatprograms/arrayargs2.oat new file mode 100644 index 0000000..64c93f6 --- /dev/null +++ b/hw6/oatprograms/arrayargs2.oat @@ -0,0 +1,14 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +int program (int argc, string[] argv) { + var x = new int[3]{i -> 0}; + var y = new int[3]{i -> 0}; + f(x, y, true)[0] = 17; + return x[0]; +} diff --git a/hw6/oatprograms/arrayargs3.oat b/hw6/oatprograms/arrayargs3.oat new file mode 100644 index 0000000..b4e18a7 --- /dev/null +++ b/hw6/oatprograms/arrayargs3.oat @@ -0,0 +1,17 @@ +int[] f(int[] x, int[] y, bool b) { + if ( b ) { + return x; + } else { + return y; + } +} + +global x = new int[]{1, 2, 3}; +global y = new int[]{4, 5, 6}; + + +int program (int argc, string[] argv) { + f(x, y, true)[0] = 17; /* non-trivial lhs path */ + var z = f(x, y, true)[0] + f(y, x, false)[0]; /* non-trivial expression paths */ + return z; +} diff --git a/hw6/oatprograms/arrayargs4.oat b/hw6/oatprograms/arrayargs4.oat new file mode 100644 index 0000000..3a5cf10 --- /dev/null +++ b/hw6/oatprograms/arrayargs4.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = new int[3]{i -> 0}; + return 0; +} diff --git a/hw6/oatprograms/binary_gcd.oat b/hw6/oatprograms/binary_gcd.oat new file mode 100644 index 0000000..ea13088 --- /dev/null +++ b/hw6/oatprograms/binary_gcd.oat @@ -0,0 +1,26 @@ +int binary_gcd (int x, int y) { + if (x == y) { return x; } + if (x == 0) { return y; } + if (y == 0) { return x; } + if ((~x [&] 1) == 1) { + if ((y [&] 1) == 1) { + return binary_gcd(x >> 1, y); + } + else { + return binary_gcd(x >> 1, y >> 1) << 1; + } + } + if ((~y [&] 1) == 1) { + return binary_gcd(x, y >> 1); + } + if (x > y) { + return binary_gcd((x - y) >> 1, y); + } + return binary_gcd((y - x) >> 1, x); +} + +int program (int argc, string[] argv) { + var x = 21; + var y = 15; + return binary_gcd(x, y); +} diff --git a/hw6/oatprograms/binary_search.oat b/hw6/oatprograms/binary_search.oat new file mode 100644 index 0000000..7ab66db --- /dev/null +++ b/hw6/oatprograms/binary_search.oat @@ -0,0 +1,65 @@ +int euclid_division (int numerator, int denominator) { + if (denominator < 0) + { + return -(euclid_division(numerator, -(denominator))); + } + + var quotient = 0; + var remainder = numerator; + + if (numerator < 0) + { + remainder = -(numerator); + + while (remainder >= denominator) + { + quotient = quotient + 1; + remainder = remainder - denominator; + } + + if ( remainder == 0 ) { return -(quotient); } + else { + return -(quotient) - 1; + } + } + + while (remainder >= denominator) + { + quotient = quotient + 1; + remainder = remainder - denominator; + } + return quotient; +} + +bool binary_search (int[] input, int key, int min, int max) { + if (max < min) { + return false; + } + + var midpt = euclid_division((max + min), 2); + + if (input[midpt] > key) + { + return binary_search(input, key, min, (midpt - 1)); + } + if (input[midpt] < key) + { + return binary_search(input, key, (midpt + 1), max); + } else { + return true; + } +} + +int program (int argc, string[] argv) { + var test_array = new int[100]{i->0}; + for (var i=0; i < 100; i=i+1;) { test_array[i] = 2 * i + 1; } + var even = binary_search (test_array, 80, 0, 99); + var odd = binary_search (test_array, 81, 0, 99); + + if (!(even & odd) & (even | odd)) + { + print_string("Correct!"); + } + + return 0; +} \ No newline at end of file diff --git a/hw6/oatprograms/bsort.oat b/hw6/oatprograms/bsort.oat new file mode 100644 index 0000000..2123e08 --- /dev/null +++ b/hw6/oatprograms/bsort.oat @@ -0,0 +1,41 @@ +void bubble_sort(int[] numbers, int array_size) +{ + var temp=0; + var i = (array_size - 1); + + for (; i > 0; i=i-1;) + { + for (var j = 1; j <= i; j=j+1;) + { + if (numbers[j-1] > numbers[i]) + { + temp = numbers[j-1]; + numbers[j-1] = numbers[i]; + numbers[i] = temp; + } + } + } + + return; +} + +int program (int argc, string[] argv) { + var a = new int[8]{i -> 0}; + + a[0] = 121; + a[1] = 125; + a[2] = 120; + a[3] = 111; + a[4] = 116; + a[5] = 110; + a[6] = 117; + a[7] = 119; + + print_string (string_of_array (a)); + print_string (" "); + bubble_sort (a, 8); + print_string (string_of_array (a)); + + return -1; +} + diff --git a/hw6/oatprograms/bubble_sort.oat b/hw6/oatprograms/bubble_sort.oat new file mode 100644 index 0000000..1843ca8 --- /dev/null +++ b/hw6/oatprograms/bubble_sort.oat @@ -0,0 +1,30 @@ +void bubble_sort(int[] arr, int len) { + var swapped = true; + while(swapped) { + swapped = false; + for (var i = 0; i < len-1; i = i+1;) { + if (arr[i] > arr[i+1]) { + var temp = arr[i]; + arr[i] = arr[i+1]; + arr[i+1] = temp; + swapped = true; + } + } + } + return; +} + +int program (int argc, string[] argv) { + var arr = new int[][10]{i -> new int[10]{j-> 10*i-j}}; + var val = 0; + for (var i = 0; i < 10; i = i+1;) { + bubble_sort(arr[i], 10); + val = val + arr[i][i]; + } + + if (val == 405) { + return 1; + } else { + return 0; + } +} diff --git a/hw6/oatprograms/calculator.oat b/hw6/oatprograms/calculator.oat new file mode 100644 index 0000000..c4152cf --- /dev/null +++ b/hw6/oatprograms/calculator.oat @@ -0,0 +1,149 @@ +int[] new_stack() { + var s = new int[7]; + s[0] = 5; + s[1] = 0; /* current index of stack ptr (offset 2) */ + return s; +} + +int peek_stack(int[] s) { + var index = 1 + s[1]; + return s[index]; +} + +int[] pop_stack(int[] s) { + var cur_index = s[1]; + if(cur_index > 0) { + cur_index = cur_index - 1; + } + + s[1] = cur_index; + return maybe_new_stack(s); +} + +int[] push_stack(int[] s, int v) { + var cur_index = 2 + s[1]; + s[cur_index] = v; + s[1] = cur_index - 1; + + return maybe_new_stack(s); +} + +int[] maybe_new_stack(int[] s) { + /* if index of s > half the size, double the size of s */ + /* if index of s < quarter the size, half the size of s */ + + return s; + + var cur_index = s[1]; + var cur_size = s[0]; + + if(cur_size <= 5) { + /* min size is 5 */ + return s; + } + + if(cur_index > (cur_size << 1)) { + /* double size of s */ + var new_s = new int[2 + cur_size * 2]; + cur_size = cur_size * 2; + new_s[0] = cur_size; + new_s[1] = cur_index; + + /* copy over values */ + for(var i = 0; i <= cur_index; i = i + 1;) { + new_s[2 + i] = s[2 + i]; + } + + return new_s; + } else if(cur_index < ((cur_size << 1) << 1)) { + /* halve s */ + var new_s = new int[2 + cur_size << 1]; + cur_size = cur_size << 1; + new_s[0] = cur_size; + new_s[1] = cur_index; + + /* copy over values */ + for(var i = 0; i <= cur_index; i = i + 1;) { + new_s[2 + i] = s[2 + i]; + } + + return new_s; + } + + return s; +} + +int get_val(int i) { + /* turns a char_code i into a value v */ + return i - 48; +} + +int int_of_string(string s) { + var arr = array_of_string(s); + var len = length_of_string(s); + + var sum = 0; + for(var i = 0; i < len; i = i + 1;) { + sum = sum * 10; + var val = get_val(arr[i]); + sum = sum + val; + } + + return sum; +} + + + +int program (int argc, string[] argv) { + /* a stack based calculator. feed in input numbers and operands + and - */ + /* will calculate result. a reverse polish notation calculator */ + + var str = "\n"; + + var stack = new_stack(); + + for(var i = 1; i < argc; i = i + 1;) { + var current_item = argv[i]; + + var did_op = false; + + var len = length_of_string(current_item); + if(len == 1) { + var arr = array_of_string(current_item); + did_op = true; + if(arr[0] == 43) { + /* plus op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 + x2); + } else if(arr[0] == 45) { + /* minus op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 - x2); + } else if(arr[0] == 120) { + /* times op */ + var x1 = peek_stack(stack); + stack = pop_stack(stack); + var x2 = peek_stack(stack); + stack = pop_stack(stack); + stack = push_stack(stack, x1 * x2); + } else { + did_op = false; + } + } + + if(!did_op) { + /* didn't do op! we have a number maybe */ + var v = int_of_string(current_item); + stack = push_stack(stack, v); + } + } + + print_int(peek_stack(stack)); + return peek_stack(stack); +} diff --git a/hw6/oatprograms/conquest.oat b/hw6/oatprograms/conquest.oat new file mode 100644 index 0000000..275122d --- /dev/null +++ b/hw6/oatprograms/conquest.oat @@ -0,0 +1,135 @@ +global meaning_of_life = 42; +global kesha_to_fling = true; +global professor = "Zdancewic!"; +global global_arr = new int[]{1, 1, 2, 3, 5, 8, 13}; +global null_arr = int[] null; +global ideal_341_midterm_score = new int[]{100}; +global actual_341_midterm_score = new int[]{0}; + +int four () { + var hakuna_matata = "Meaning of Life"; + var what_is_the = meaning_of_life; + var what_rhymes_with_moore = meaning_of_life - global_arr[5] * global_arr[4] + global_arr[2]; + return 0 + what_rhymes_with_moore; +} + +int[] asian_brother_of_foo_named_fui (string s, bool b, int i) { + var fui = global_arr; + return fui; +} + +void dfs (int[][] arr, int[][] visited, int row, int col, int i, int j) { + if (i - 1 >= 0) { + if (visited[i - 1][j] != 1) { + visited[i - 1][j] = 1; + + if (arr[i - 1][j] == 1) { + dfs(arr, visited, row, col, i - 1, j); + } + } + } + + if (i + 1 < row) { + if (visited[i + 1][j] != 1) { + visited[i + 1][j] = 1; + + if (arr[i + 1][j] == 1) { + dfs(arr, visited, row, col, i + 1, j); + } + } + } + + if (j - 1 >= 0) { + if (visited[i][j - 1] != 1) { + visited[i][j - 1] = 1; + + if (arr[i][j - 1] == 1) { + dfs(arr, visited, row, col, i, j - 1); + } + } + } + + if (j + 1 < col) { + if (visited[i][j + 1] != 1) { + visited[i][j + 1] = 1; + + if (arr[i][j + 1] == 1) { + dfs(arr, visited, row, col, i, j + 1); + } + } + } + + return; +} + +int connected (int[][] arr, int row, int col) { + var visited = new int[][row]{i-> new int[col]{j->0}}; + var counter = 0; + + for (var i = 0; i < row; i = i + 1;) { + var j = 0; + + while (j < col) { + if (visited[i][j] == 0) { + visited[i][j] = 1; + + if (arr[i][j] == 1) { + counter = counter + 1; + + dfs(arr, visited, row, col, i, j); + } + } + + j = j + 1; + } + } + + return counter; +} + +int program (int argc, string[] argv) { + var territory_a = new int[][]{new int[]{1, 0, 1, 0}, + new int[]{1, 1, 0, 1}, + new int[]{1, 0, 1, 1}, + new int[]{0, 1, 1, 0}}; + var territory_b = new int[][]{new int[]{0, 0, 1, 0, 1}, + new int[]{0, 1, 1, 0, 1}, + new int[]{1, 1, 1, 1, 1}}; + var territory_c = new int[][]{new int[]{1, 0, 1}, + new int[]{0, 1, 0}, + new int[]{1, 0, 1}}; + + var none_conquered = new int[][four()]{i-> new int[2]{j->actual_341_midterm_score[0]}}; + + var all_conquered = new int[][6]{i->new int[6]{j -> i*0+1}}; + + var island = new int[][] {new int[]{}}; + var emptyland = new int[][1]{i -> + new int[1]{ j -> + asian_brother_of_foo_named_fui(professor,kesha_to_fling,ideal_341_midterm_score[0])[1] + } + }; + + all_conquered = all_conquered; + var temp = island; + island = emptyland; + emptyland = temp; + + print_string("My name is Jeff...\n"); + + var a = connected(territory_a, 4, 4); + var b = connected(territory_b, 3, 5); + var c = connected(territory_c, 3, 3); + var none = connected(none_conquered, 4, 2); + var all = connected(all_conquered, 6, 6); + var i = connected(island, 1, 1); + var e = connected(emptyland, 0, 0); + + if (a == 3 & b == 1 & c == 5 & none == 0 & all == 1 & i == 1 & e == 0) { + print_string("Charizard is the BEST Pokemon ever!!!"); + } + + var sum = a + b + c + none + all + i + e; + + return sum; +} \ No newline at end of file diff --git a/hw6/oatprograms/count_sort.oat b/hw6/oatprograms/count_sort.oat new file mode 100644 index 0000000..e900df9 --- /dev/null +++ b/hw6/oatprograms/count_sort.oat @@ -0,0 +1,59 @@ + +int min(int[] arr, int len) { + var min = arr[0]; + for (var i = 0; i < len; i = i + 1;) { + if (arr[i] < min) { + min = arr[i]; + } + } + return min; +} + +int max(int[] arr, int len) { + var max = arr[0]; + for (var i = 0; i < len; i = i + 1;) { + if (arr[i] > max) { + max = arr[i]; + } + } + return max; +} + +int[] count_sort(int[] arr, int len) { + var min = min(arr, len); + var max = max(arr, len); + + var counts = new int[max - min + 1]{i->0}; + + for (var i = 0; i < len; i = i + 1;) { + counts[arr[i] - min] = counts[arr[i] - min] + 1; + } + + var i = min; + var j = 0; + + var out = new int[len]{i2->0}; + + while (i <= max) { + + if (counts[i - min] > 0) { + out[j] = i; + counts[i - min] = counts[i - min] - 1; + j = j + 1; + } else { + i = i + 1; + } + } + return out; +} + +int program(int argc, string[] argv) { + var arr = new int[]{65, 70, 72, 90, 65, 65, 69, 89, 67}; + var len = 9; + + print_string(string_of_array(arr)); + print_string("\n"); + var sorted = count_sort(arr, len); + print_string(string_of_array(sorted)); + return 0; +} diff --git a/hw6/oatprograms/determinant_size2.oat b/hw6/oatprograms/determinant_size2.oat new file mode 100644 index 0000000..b6733d9 --- /dev/null +++ b/hw6/oatprograms/determinant_size2.oat @@ -0,0 +1,31 @@ +int compute_determinant(int[][] matrix, int n) { + var sum = 0; + var multiplier = -1; + if (n == 1) { + sum = matrix[0][0]; + } + else { + for (var k = 0; k < n; k = k+1;) { + var len = n-1; + var b=new int[][len]{i-> new int[len]{j -> 1}}; + for (var l = 0; l < k; l=l+1;) { + for (var m = 0; m < n-1; m=m+1;) { + b[m][l] = matrix[m+1][l]; + } + } + for (var o = k; o < n-1; o=o+1;) { + for (var p = 0; p < n-1; p=p+1;) { + b[p][o] = matrix[p+1][o+1]; + } + } + multiplier = multiplier * -1; + sum = sum + multiplier * matrix[0][k] * compute_determinant(b, n-1); + } + } + return sum; +} + +int program (int argc, string[] argv) { + var matrix = new int[][]{new int[]{20,2},new int[]{3,5}}; + return compute_determinant(matrix, 2); +} diff --git a/hw6/oatprograms/easy_p1.oat b/hw6/oatprograms/easy_p1.oat new file mode 100644 index 0000000..3e77270 --- /dev/null +++ b/hw6/oatprograms/easy_p1.oat @@ -0,0 +1,4 @@ +int f ( ) { + return 0 ; +} + diff --git a/hw6/oatprograms/easy_p2.oat b/hw6/oatprograms/easy_p2.oat new file mode 100644 index 0000000..943c398 --- /dev/null +++ b/hw6/oatprograms/easy_p2.oat @@ -0,0 +1,5 @@ +int f ( int x ) { + var x = 0; + x = x + x - x * x >> x << x [|] x [&] -~x >>> x; + return x; +} diff --git a/hw6/oatprograms/easy_p3.oat b/hw6/oatprograms/easy_p3.oat new file mode 100644 index 0000000..530ced8 --- /dev/null +++ b/hw6/oatprograms/easy_p3.oat @@ -0,0 +1,22 @@ +string bar (int x, string y) { + var s = "This is a string"; + var array = new int[]{1, 3}; + var y = array[0]; + return s; +} + +void proc1 () { + proc2 ( ); + return; +} + +void proc2 ( ) { + proc1 ( ); + return; +} + +bool foo ( int x, int[] y ) { + var s = bar (x, "compilerdesign"); + proc1 (); + return true; +} diff --git a/hw6/oatprograms/easy_p4.oat b/hw6/oatprograms/easy_p4.oat new file mode 100644 index 0000000..c9e13e7 --- /dev/null +++ b/hw6/oatprograms/easy_p4.oat @@ -0,0 +1,40 @@ +/* This is a test case: level 0 + + /* level 1 */ + + + /* level 1 + /* level 2 */ + */ + + "This is a commented string." +*/ + +string f ( ) { + var s = + new string[][] + { + new string []{ + "s00:\n+\n=2*\n", + "s01:this is not a comment in string.*", + "s02:\"\\t\\n\\\\?\"" + }, + new string[]{ + "s10:\133\134", + "s11", + "s12" + } + }; + + return s[0][1]; +} + +int[][] g (int [][] x) { + var y = new int[][]{ new int[]{0, 1}, new int[]{2, 3} }; + var i = 0; + + x[0][0] = i + y[1][1]; /* + g(x)[1][0]; */ + i = -!~x[0][0] ; /* comments */ + + return x; +} diff --git a/hw6/oatprograms/easy_p5.oat b/hw6/oatprograms/easy_p5.oat new file mode 100644 index 0000000..1c9abf6 --- /dev/null +++ b/hw6/oatprograms/easy_p5.oat @@ -0,0 +1,14 @@ +global i = 19; +global b1 = true; +global b2 = false; +global str = "This is a string!"; +global arr1 = int[]{0,1,2}; +global arr2 = int[][]{ int[]{10,11}, int[]{20,21}, int[]{30,31}}; +global arr3 = string[]{"String1", "String2", "String3"}; + +global arr4 = string[][] + { + string[]{"String00","String01"}, + string[]{"String10","String11"}, + string[]{"String20","String21"} + }; diff --git a/hw6/oatprograms/easy_p6.oat b/hw6/oatprograms/easy_p6.oat new file mode 100644 index 0000000..b16eb74 --- /dev/null +++ b/hw6/oatprograms/easy_p6.oat @@ -0,0 +1,12 @@ +global y = 0; +global z = 0; + +void f (int x, int y) { + var x = 0; + return; +} + +void g (int x, int y) { + var z = 0; + return; +} diff --git a/hw6/oatprograms/easy_p7.oat b/hw6/oatprograms/easy_p7.oat new file mode 100644 index 0000000..ed330b1 --- /dev/null +++ b/hw6/oatprograms/easy_p7.oat @@ -0,0 +1,8 @@ +global j = int[]{1,2,3,4}; +int[] f () { + var a = new int[][]{1, 2}; + var i = new int[4]; + var arr1 = new int[3]; + var arr2 = new int[][3]; + return new int[2]; +} diff --git a/hw6/oatprograms/easyrun1.oat b/hw6/oatprograms/easyrun1.oat new file mode 100644 index 0000000..32327bc --- /dev/null +++ b/hw6/oatprograms/easyrun1.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 17; +} diff --git a/hw6/oatprograms/easyrun10.oat b/hw6/oatprograms/easyrun10.oat new file mode 100644 index 0000000..e94ae0b --- /dev/null +++ b/hw6/oatprograms/easyrun10.oat @@ -0,0 +1,19 @@ +int program (int argc, string[] argv) { + var x = new int[][]{new int[]{1}, + new int[]{2}, + new int[]{3}, + new int[]{4}}; + var ans = 0; + + for(var i=0;i<4;i=i+1;) { + ans = x[i][0] - ans; + } + + if((5 [&] ~5 [|] 0) != 0) { + return ans; + } else { + return -ans; + } + + return ans; +} diff --git a/hw6/oatprograms/easyrun2.oat b/hw6/oatprograms/easyrun2.oat new file mode 100644 index 0000000..d18f435 --- /dev/null +++ b/hw6/oatprograms/easyrun2.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 17 + 18; +} diff --git a/hw6/oatprograms/easyrun3.oat b/hw6/oatprograms/easyrun3.oat new file mode 100644 index 0000000..f57521a --- /dev/null +++ b/hw6/oatprograms/easyrun3.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var x = 0; + var i = 0; + + while (i < 10) { + x = (x + i) * i; + i = i + 1; + } + + return x; +} diff --git a/hw6/oatprograms/easyrun4.oat b/hw6/oatprograms/easyrun4.oat new file mode 100644 index 0000000..523f3b7 --- /dev/null +++ b/hw6/oatprograms/easyrun4.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + var x = 0; + for (var i=0; i<3; i = i+1;) { + x = x + 2; + } + return x; +} diff --git a/hw6/oatprograms/easyrun5.oat b/hw6/oatprograms/easyrun5.oat new file mode 100644 index 0000000..2ddb08f --- /dev/null +++ b/hw6/oatprograms/easyrun5.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var x = 100 >> 3; + var y = 100 << 3; + + if (x-y <= 0) { + return -x-y; + } else { + return x-y; + } + +} diff --git a/hw6/oatprograms/easyrun6.oat b/hw6/oatprograms/easyrun6.oat new file mode 100644 index 0000000..f2234cb --- /dev/null +++ b/hw6/oatprograms/easyrun6.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(!true | -4 + 5 > 0 & 6 * 4 < 25) { + return 9; + } else { + return 4; + } +} diff --git a/hw6/oatprograms/easyrun7.oat b/hw6/oatprograms/easyrun7.oat new file mode 100644 index 0000000..f6e053b --- /dev/null +++ b/hw6/oatprograms/easyrun7.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(((~5 [&] 6) >= (2 [|] 0))) { + return 23; + } else { + return 46; + } +} diff --git a/hw6/oatprograms/easyrun8.oat b/hw6/oatprograms/easyrun8.oat new file mode 100644 index 0000000..77245c0 --- /dev/null +++ b/hw6/oatprograms/easyrun8.oat @@ -0,0 +1,7 @@ +int program (int argc, string[] argv) { + if(6 != 5) { + return ~(5 >> -6 << 9 >>> 10) * 2 - 100 + 6; + } else { + return 2; + } +} diff --git a/hw6/oatprograms/easyrun9.oat b/hw6/oatprograms/easyrun9.oat new file mode 100644 index 0000000..282656f --- /dev/null +++ b/hw6/oatprograms/easyrun9.oat @@ -0,0 +1,10 @@ +int program (int argc, string[] argv) { + var x = new int[]{1,2,3,4}; + var ans = 0; + + for(var i=0;i<4;i=i+1;) { + ans = x[i] * ~x[i]; + } + + return ans; +} diff --git a/hw6/oatprograms/fac.oat b/hw6/oatprograms/fac.oat new file mode 100644 index 0000000..d162b63 --- /dev/null +++ b/hw6/oatprograms/fac.oat @@ -0,0 +1,13 @@ +int f(int i) { + var r = 0; + if (i == 0) { + r = 1; + } else { + r = i * f (i-1); + } + return r; +} + +int program (int argc, string[] argv) { + return f (5); +} diff --git a/hw6/oatprograms/fact.oat b/hw6/oatprograms/fact.oat new file mode 100644 index 0000000..cf1e754 --- /dev/null +++ b/hw6/oatprograms/fact.oat @@ -0,0 +1,14 @@ +int fact(int x) { + var acc = 1; + while (x > 0) { + acc = acc * x; + x = x - 1; + } + return acc; +} + +int program(int argc, string[] argv) { + print_string(string_of_int(fact(5))); + return 0; +} + diff --git a/hw6/oatprograms/fibo.oat b/hw6/oatprograms/fibo.oat new file mode 100644 index 0000000..e473097 --- /dev/null +++ b/hw6/oatprograms/fibo.oat @@ -0,0 +1,26 @@ +int fibR(int n) { + if(n == 0) {return 0;} + if(n == 1) {return 1;} + return fibR(n - 1) + fibR(n-2); +} + +int fibI(int n) { + var a = 0; + var b = 1; + if(n == 0) {return a;} + if(n == 1) {return b;} + while(n-2 > 0) { + var old = b; + b = b + a; + a = old; + n = n - 1; + } + return a + b; +} + +int program (int argc, string[] argv) +{ + var val = 1; + if(fibR(12) == 144 & fibI(12) == 144) {val = 0;} + return val; +} diff --git a/hw6/oatprograms/float_multiply.oat b/hw6/oatprograms/float_multiply.oat new file mode 100644 index 0000000..2548138 --- /dev/null +++ b/hw6/oatprograms/float_multiply.oat @@ -0,0 +1,52 @@ +global float_len = 2; +int[] determine_shift(int[] float) +{ + var dec = float[1]; + var count = 0; + while(dec > 0) + { + var temp = float[0]; + float[0] = temp << 1; + dec = dec >>> 1; + count = count + 1; + } + var list = new int[2]; + list[0] = float[0] + float[1]; + list[1] = count; + return list; +} + +int[] multiply_floats(int[] f1, int[] f2) +{ + var f1_shifted = determine_shift(f1); + var f2_shifted = determine_shift(f2); + var product = f1_shifted[0] * f2_shifted[0]; + var num_left_shifts = f1_shifted[1] + f2_shifted[1]; + var remainder = 0; + for(var i = 0; i < num_left_shifts; i=i+1;) + { + var lsb = product [&] 1; + var shifted_lsb = lsb << i; + product = product >>> 1; + remainder = remainder + shifted_lsb; + } + var ans = new int[2]; + ans[0] = product; + ans[1] = remainder; + return ans; +} + +int program(int argc, string[] argv) +{ + var pi = new int[2]; + pi[0] = 3; + pi[1] = 14159; + var diameter = new int[2]; + diameter[0] = 20; + diameter[1] = 17; + var prod = multiply_floats(pi, diameter); + print_int(prod[0]); + print_string("."); + print_int(prod[1]); + return 0; +} \ No newline at end of file diff --git a/hw6/oatprograms/gcd.oat b/hw6/oatprograms/gcd.oat new file mode 100644 index 0000000..31b9063 --- /dev/null +++ b/hw6/oatprograms/gcd.oat @@ -0,0 +1,26 @@ +int gcd(int a, int b) { + while (b != 0) { + var t = b; + b = mod(a, b); + a = t; + } + + return a; +} + +int mod (int a, int b) { + + var t = a; + while (t - b >= 0) { + t = t - b; + } + + return t; +} + +int program (int argc, string[] argv) { + var a = 64; + var b = 48; + + return gcd(a, b); +} \ No newline at end of file diff --git a/hw6/oatprograms/globals1.oat b/hw6/oatprograms/globals1.oat new file mode 100644 index 0000000..d6a8c21 --- /dev/null +++ b/hw6/oatprograms/globals1.oat @@ -0,0 +1,5 @@ +global x = 42; + +int program(int argc, string[] args) { + return x; +} diff --git a/hw6/oatprograms/globals2.oat b/hw6/oatprograms/globals2.oat new file mode 100644 index 0000000..8d2705c --- /dev/null +++ b/hw6/oatprograms/globals2.oat @@ -0,0 +1,8 @@ +global y = true; + +int program(int argc, string[] args) { + if (y) { + return 17; + } + return 15; +} diff --git a/hw6/oatprograms/globals3.oat b/hw6/oatprograms/globals3.oat new file mode 100644 index 0000000..f611f99 --- /dev/null +++ b/hw6/oatprograms/globals3.oat @@ -0,0 +1,5 @@ +global arr = int[] null; + +int program(int argc, string[] args) { + return 17; +} diff --git a/hw6/oatprograms/globals4.oat b/hw6/oatprograms/globals4.oat new file mode 100644 index 0000000..24ab285 --- /dev/null +++ b/hw6/oatprograms/globals4.oat @@ -0,0 +1,5 @@ +global arr = new int[]{1, 2, 3, 4}; + +int program(int argc, string[] args) { + return 5; +} diff --git a/hw6/oatprograms/globals5.oat b/hw6/oatprograms/globals5.oat new file mode 100644 index 0000000..0ab9fd5 --- /dev/null +++ b/hw6/oatprograms/globals5.oat @@ -0,0 +1,5 @@ +global s = "hello!"; + +int program(int argc, string[] args) { + return 17; +} diff --git a/hw6/oatprograms/globals6.oat b/hw6/oatprograms/globals6.oat new file mode 100644 index 0000000..58435e1 --- /dev/null +++ b/hw6/oatprograms/globals6.oat @@ -0,0 +1,4 @@ +int program(int argc, string[] args) { + var s = "hello!"; + return 15; +} diff --git a/hw6/oatprograms/gnomesort.oat b/hw6/oatprograms/gnomesort.oat new file mode 100644 index 0000000..039fc52 --- /dev/null +++ b/hw6/oatprograms/gnomesort.oat @@ -0,0 +1,35 @@ + +void gnomeSort(int[] a, int len) { + var i = 1; + var j = 2; + + while(i < len) { + if (a[i-1] <= a[i]) { + i = j; + j = j + 1; + } else { + var tmp = a[i-1]; + a[i-1] = a[i]; + a[i] = tmp; + i = i - 1; + + if (i == 0) { + i = j; + j = j + 1; + } + } + } + return; +} + +int program(int argc, string[] argv) { + var arr = new int[]{ 5, 200, 1, 65, 30, 99, 2, 0 }; + var len = 8; + + gnomeSort(arr, len); + for(var i=0; i<8; i=i+1;) { + print_int(arr[i]); + } + + return 0; +} \ No newline at end of file diff --git a/hw6/oatprograms/hashcode.oat b/hw6/oatprograms/hashcode.oat new file mode 100644 index 0000000..c0594fb --- /dev/null +++ b/hw6/oatprograms/hashcode.oat @@ -0,0 +1,25 @@ +/* Java string hash function */ +/* hash = s[0] * 31 ^ (n - 1) + s[1] * 31 ^(n - 2) + ... + s[n-1]*/ + +int program(int argc, string[] argv) { + var s = "aa"; + var h = hash(s); + print_int(h); + return 0; +} + +int hash(string s) { + var int_arr = array_of_string(s); + var length = length_of_string(s); + var hash = 0; + for(var i = 0; i < length; i= i+1;) { + var power = 1; + for(var j = length - i - 1; j > 0; j= j-1;) { + power = power * 31; + } + var char = int_arr[i]; + hash = hash + power * char; + + } + return hash; +} \ No newline at end of file diff --git a/hw6/oatprograms/heap.oat b/hw6/oatprograms/heap.oat new file mode 100644 index 0000000..bc7d8cf --- /dev/null +++ b/hw6/oatprograms/heap.oat @@ -0,0 +1,53 @@ +void min_heapify(int[] array, int i, int len) { + var l = i * 2; + var r = i + 1; + var tmp = 0; + var m = i; + + if (l < len) { + if (array[l] > array[m]) { + m = l; + } + } + + if (r < len) { + if (array[r] > array[m]) { + m = r; + } + } + + if (m != i) { + tmp = array[i]; + array[i] = array[m]; + array[m] = tmp; + + min_heapify(array, m, len); + } + + return; +} + +void make_min_heap(int[] array, int len) { + for (var i = len; i >= 1; i = i - 1;) { + min_heapify(array, i, len); + } + + return; +} + +int program(int argc, string[] argv) { + var array = new int[]{ 0, 9, 1, 2, 8, 10, 7, 3, 6, 4, 5 }; + var end_result = new int[]{ 0, 1, 4, 2, 8, 5, 7, 3, 6, 9, 10 }; + + make_min_heap(array, 10); + + var same = 0; + + for (var i = 0; i < 11; i = i + 1;) { + if (array[i] != end_result[i]) { + same = 1; + } + } + + return same; +} diff --git a/hw6/oatprograms/insertion_sort.oat b/hw6/oatprograms/insertion_sort.oat new file mode 100644 index 0000000..acbb6f4 --- /dev/null +++ b/hw6/oatprograms/insertion_sort.oat @@ -0,0 +1,38 @@ +int[] insert(int[] partial, int len, int insertee) { + var inserted = new int[len+1]{i->0}; + for (var i=0; i < len+1; i=i+1;) { inserted[i] = -1; } + var not_yet_inserted = true; + if (insertee < partial[0]) { + not_yet_inserted = false; + inserted[0] = insertee; + } + for (var i = 0; i < len; i = i + 1;) { + if (not_yet_inserted) { + if (insertee > partial[i]) { + not_yet_inserted = false; + inserted[i+1] = insertee; + inserted[i] = partial[i]; + } else { + inserted[i] = partial[i]; + } + } else { + inserted[i+1] = partial[i]; + } + } + return inserted; +} + +int[] insort(int[] unsorted, int len) { + var out = new int[]{0}; + out[0] = unsorted[0]; + for (var i = 1; i < len; i = i + 1;) { + out = insert(out, i, unsorted[i]); + } + return out; +} + +int program(int argc, string[] argv) { + var array = new int[]{13, 42, 32, 3, 2, 6}; + var result = insort(array, 6); + return result[5]; +} diff --git a/hw6/oatprograms/is_prime.oat b/hw6/oatprograms/is_prime.oat new file mode 100644 index 0000000..8826357 --- /dev/null +++ b/hw6/oatprograms/is_prime.oat @@ -0,0 +1,31 @@ +global list = int[] {3, 5, 7, 8, 11, 16, 17, 21}; + +bool isPrime (int n) { + if (n < 2) { + return false; + } + + for (var i = 2; i < n; i = i + 1;) + { + var cur_num = n; + while (cur_num >= i) { + cur_num = cur_num - i; + } + + if (cur_num == 0) { + return false; + } + } + return true; +} + +int program (int argc, string[] argv) { + var answer = 0; + for (var i = 0; i < 8; i = i + 1;) + { + if(isPrime(list[i])) { + answer = answer + 1; + } + } + return answer; +} diff --git a/hw6/oatprograms/josh_joyce_test.oat b/hw6/oatprograms/josh_joyce_test.oat new file mode 100644 index 0000000..19e1b49 --- /dev/null +++ b/hw6/oatprograms/josh_joyce_test.oat @@ -0,0 +1,20 @@ +global arr1 = new int[]{1,2,3,4}; +global arr2 = new int[]{1,2,3,5}; + +int arrcheck(int[] ar1, int[] ar2, int len){ + var val = 0; + for(var i =0; i < len; i= i+1;){ + if (ar1[i] != ar2[i]) { + val = 1; + } + } + return val; +} + +int program(int argc, string[] argv) { + + var val = 1; + if(arrcheck(arr1, arr2, 4) == 1) {val = 0;} + return val; + +} diff --git a/hw6/oatprograms/kmp.oat b/hw6/oatprograms/kmp.oat new file mode 100644 index 0000000..7716f51 --- /dev/null +++ b/hw6/oatprograms/kmp.oat @@ -0,0 +1,68 @@ +/* Paul Lou and Tanner Haldeman */ +/* References: Algorithms (Sedgewick), https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm */ + +int[] construct_table(string w) { + var length = length_of_string(w); + var arr_of_w = array_of_string(w); + var t = new int[length]; + var curr = 2; + var next = 0; + + t[0] = -1; + t[1] = 0; + while (curr < length) { + if (arr_of_w[curr-1] == arr_of_w[next]) { + t[curr] = next + 1; + next = next + 1; + curr = curr + 1; + } + else if (next > 0) { + next = t[next]; + } + else { + t[curr] = 0; + curr = curr + 1; + } + } + + return t; +} + + +int kmp(string str, string w) { + var str_idx = 0; + var word_idx = 0; + var word_length = length_of_string(w); + var word_arr = array_of_string(w); + var str_arr = array_of_string(str); + var t = construct_table(w); + + while (str_idx + word_idx < length_of_string(str)) { + if (word_arr[word_idx] == str_arr[str_idx + word_idx]) { + if (word_idx == word_length - 1) { + return str_idx; + } + word_idx = word_idx + 1; + } + else { + if (t[word_idx] > -1) { + str_idx = str_idx + word_idx - t[word_idx]; + word_idx = t[word_idx]; + } + else { + str_idx = str_idx + 1; + word_idx = 0; + } + } + } + + return -1; +} + +int program(int argc, string[] argv) { + var str = "abcdabcdabcdcbab"; + var word = "dabcdc"; + + var ret = kmp(str, word); + return ret; +} diff --git a/hw6/oatprograms/lcs.oat b/hw6/oatprograms/lcs.oat new file mode 100644 index 0000000..2bc752b --- /dev/null +++ b/hw6/oatprograms/lcs.oat @@ -0,0 +1,43 @@ +/** + * Computes longest common subsequence of two strings a and b. + */ +global buf = new int[]{0}; + +string lcs(int i, int j, string a, string b) { + if (i < 0 | j < 0) { + return ""; + } + + var a_chars = array_of_string(a); + var b_chars = array_of_string(b); + + var last_char_a = a_chars[i]; + var last_char_b = b_chars[j]; + + if (last_char_a == last_char_b) { + var prev_lcs = lcs(i - 1, j - 1, a, b); + buf[0] = a_chars[i]; + var next_char = string_of_array(buf); + return string_cat(prev_lcs, next_char); + } + + var left_lcs = lcs(i, j - 1, a, b); + var right_lcs = lcs(i - 1, j, a, b); + + var left_len = length_of_string(left_lcs); + var right_len = length_of_string(right_lcs); + + if (left_len < right_len) { + return right_lcs; + } else { + return left_lcs; + } +} + +int program(int argc, string[] argv) { + var tomato = "TOMATO"; + var orating = "ORATING"; + print_string(lcs(5, 6, tomato, orating)); + return 0; +} + diff --git a/hw6/oatprograms/leastsquare.oat b/hw6/oatprograms/leastsquare.oat new file mode 100644 index 0000000..bb97a72 --- /dev/null +++ b/hw6/oatprograms/leastsquare.oat @@ -0,0 +1,40 @@ + +int program(int argc, string[] argv) { + var n = 500; + return leastsquare(n); +} + +/*finds the least number of squares to sum up to n*/ + +int leastsquare(int n) { + var cache = new int[]{n+1}; + cache[0] = 0; + cache[1] = 1; + cache[2] = 2; + cache[3] = 3; + for (var i = 4; i < n + 1; i=i+1;) { + /*set to some arbitrary high number*/ + cache[i] = i; + + for (var k = 1; k < n; k = k + 1;) { + var temp = k*k; + if (temp > i) { + + } else { + cache[i] = min(cache[i], 1 + cache[i - temp]); + } + } + } + return cache[n]; +} + + + + +int min(int y, int x) { + if (x > y) { + return y; + } else { + return x; + } +} diff --git a/hw6/oatprograms/lfsr.oat b/hw6/oatprograms/lfsr.oat new file mode 100644 index 0000000..1320b2a --- /dev/null +++ b/hw6/oatprograms/lfsr.oat @@ -0,0 +1,44 @@ +global lfsr_iterations = 5; +global lfsr_length = 4; +global lfsr_init_values = new bool[]{true, false, true, false}; + +bool xor(bool x, bool y) { + return (x & !y) | (!x & y); +} + +string string_of_bool(bool b) { + if (b) { return "T"; } + else { return "F"; } +} + +void print_lfsr(bool[] lfsr_register, int len) { + for (var i = 0; i < len; i = i + 1;) { + print_string(string_of_bool(lfsr_register[i])); + } + return; +} + +int program(int argc, string[] argv) { + /* Initialize the working register */ + var lfsr_register = new bool[lfsr_length]{i->false}; + for (var i=0; i < lfsr_length; i=i+1;) { + lfsr_register[i] = lfsr_init_values[i]; + } + + /* Do the computations */ + for (var i = 0; i < lfsr_iterations; i = i + 1;) { + var new_first = + xor(lfsr_register[lfsr_length - 1], lfsr_register[lfsr_length - 2]); + for (var j = lfsr_length - 1; j > 0; j = j - 1;) { + lfsr_register[j] = lfsr_register[j - 1]; + } + lfsr_register[0] = new_first; + } + + /* Print the initial and final bool arrays with a space separator */ + print_lfsr(lfsr_init_values, lfsr_length); + print_string(" "); + print_lfsr(lfsr_register, lfsr_length); + + return 0; +} diff --git a/hw6/oatprograms/lfsr2.oat b/hw6/oatprograms/lfsr2.oat new file mode 100644 index 0000000..80d6484 --- /dev/null +++ b/hw6/oatprograms/lfsr2.oat @@ -0,0 +1,15 @@ +global lfsr_length = 4; +global lfsr_init_values = new bool[]{true, false, true, false}; + +void print_lfsr(bool[] lfsr_register, int len) { + for (var i = 0; i < len; i = i + 1;) { + var x = lfsr_register[i]; + } + return; +} + +int program(int argc, string[] argv) { + /* Print the initial and final bool arrays with a space separator */ + print_lfsr(lfsr_init_values, lfsr_length); + return 0; +} diff --git a/hw6/oatprograms/lib10.oat b/hw6/oatprograms/lib10.oat new file mode 100644 index 0000000..19f9cf3 --- /dev/null +++ b/hw6/oatprograms/lib10.oat @@ -0,0 +1,7 @@ +int my_length_of_string (string str) { + return length_of_array (array_of_string (str)); +} + +int program (int argc, string[] argv) { + return my_length_of_string ("Hello?"); +} diff --git a/hw6/oatprograms/lib11.oat b/hw6/oatprograms/lib11.oat new file mode 100644 index 0000000..e152db9 --- /dev/null +++ b/hw6/oatprograms/lib11.oat @@ -0,0 +1,13 @@ +int program (int argc, string[] argv) { + var arr = array_of_string("1234967890"); + var sum = 0; + + for (var i=0; i<10; i=i+1;) { + arr[i] = i; + } + for (var i=0; i<10; i=i+1;) { + sum = sum + arr[i]; + } + + return sum; +} diff --git a/hw6/oatprograms/lib12.oat b/hw6/oatprograms/lib12.oat new file mode 100644 index 0000000..a0d9775 --- /dev/null +++ b/hw6/oatprograms/lib12.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr = oat_alloc_array(10); + return arr[10]; +} + diff --git a/hw6/oatprograms/lib13.oat b/hw6/oatprograms/lib13.oat new file mode 100644 index 0000000..a6e0132 --- /dev/null +++ b/hw6/oatprograms/lib13.oat @@ -0,0 +1,25 @@ +global str1 = "Hello "; + +string string_concat (string str1, string str2) { + var arr1 = array_of_string (str1); + var arr2 = array_of_string (str2); + var len1 = length_of_array (arr1); + var len2 = length_of_array (arr2); + var arr3 = new int[len1+len2]; + var i = 0; + for(var j=0; j arr[i+start]}; + return string_of_array (r); +} + +int program (int argc, string [] argv) { + print_string (sub(argv[1], 3, 5)); + return 0; +} diff --git a/hw6/oatprograms/lib2.oat b/hw6/oatprograms/lib2.oat new file mode 100644 index 0000000..1fdfd84 --- /dev/null +++ b/hw6/oatprograms/lib2.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{0,0}, new int[]{1,1}, new int[]{2,2}, new int[]{3,3}}; + var len = length_of_array (arr[2]); + return len; +} diff --git a/hw6/oatprograms/lib3.oat b/hw6/oatprograms/lib3.oat new file mode 100644 index 0000000..fb0d642 --- /dev/null +++ b/hw6/oatprograms/lib3.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{0,0,0,0}, new int[]{1,1}, new int[]{2,2}, new int[]{3,3}}; + var len = length_of_array (arr[0]); + return len; +} diff --git a/hw6/oatprograms/lib4.oat b/hw6/oatprograms/lib4.oat new file mode 100644 index 0000000..d2beb1a --- /dev/null +++ b/hw6/oatprograms/lib4.oat @@ -0,0 +1,11 @@ +global str = "hello"; + +int program (int argc, string[] argv) { + var arr = array_of_string (str); + var s = 0; + for (var i=0; i<5; i=i+1;) { + s = s + arr[i]; + } + print_int(s); + return s; +} diff --git a/hw6/oatprograms/lib5.oat b/hw6/oatprograms/lib5.oat new file mode 100644 index 0000000..017c9ea --- /dev/null +++ b/hw6/oatprograms/lib5.oat @@ -0,0 +1,9 @@ +int program (int argc, string[] argv) { + var str = "hello"; + var arr = array_of_string (str); + var s = 0; + for (var i=0; i<5; i=i+1;) { + s = s + arr[i]; + } + return s; +} diff --git a/hw6/oatprograms/lib6.oat b/hw6/oatprograms/lib6.oat new file mode 100644 index 0000000..69aa763 --- /dev/null +++ b/hw6/oatprograms/lib6.oat @@ -0,0 +1,12 @@ +int program (int argc, string[] argv) { + var arr1 = new int[]{111,112,113,114,115}; + var str = string_of_array (arr1); + var arr2 = array_of_string (str); + var s = 0; + for (var i=0; i<5; i=i+1;) { + s = s + arr2[i]; + } + print_int(s); + return s; +} + diff --git a/hw6/oatprograms/lib7.oat b/hw6/oatprograms/lib7.oat new file mode 100644 index 0000000..bb012f2 --- /dev/null +++ b/hw6/oatprograms/lib7.oat @@ -0,0 +1,11 @@ +int program (int argc, string[] argv) { + var arr1 = new int[]{111,112,113,114,115}; + var str = string_of_array (arr1); + var arr2 = array_of_string (str); + var s = 0; + for (var i=0; i<5; i=i+1;) { + s = s + arr2[i]; + } + return s; +} + diff --git a/hw6/oatprograms/lib8.oat b/hw6/oatprograms/lib8.oat new file mode 100644 index 0000000..743daea --- /dev/null +++ b/hw6/oatprograms/lib8.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var str = "Hello world!"; + print_string (str); + return 0; +} diff --git a/hw6/oatprograms/lib9.oat b/hw6/oatprograms/lib9.oat new file mode 100644 index 0000000..2096cb8 --- /dev/null +++ b/hw6/oatprograms/lib9.oat @@ -0,0 +1,6 @@ +int program(int argc, string[] argv) { + for (var i=1; i= 0) & (j >= 0) & (i < len) & (j < len)) { + return count + board[i][j]; + } else { + return count; + } +} + +int val_at(int[][] board, int i, int j) { + var alive = board[i][j]; + var count = 0; + count = check(board, i-1, j-1, count); + count = check(board, i-1, j , count); + count = check(board, i-1, j+1, count); + + count = check(board, i , j-1, count); + count = check(board, i , j+1, count); + + count = check(board, i+1, j-1, count); + count = check(board, i+1, j , count); + count = check(board, i+1, j+1, count); + + if (alive == 1) { + if (count < 2) { + return 0; + } else if (count < 4) { + return 1; + } + return 0; + } + if (count == 3) { + return 1; + } else { + return 0; + } + return 0; +} + +int program (int argc, string[] argv) { + var board = new int[][]{ new int[]{0, 0, 0, 0}, + new int[]{0, 1, 1, 1}, + new int[]{1, 1, 1, 0}, + new int[]{0, 0, 0, 0} }; + + var new_board = new int[][4]; + for (var i=0; i < 4; i=i+1;) { + new_board[i] = new int[4]; + for (var j=0; j < 4; j=j+1;) { new_board[i][j] = val_at(board, i,j); } + } + + for (var i = 0; i < len; i = i+1;) { + for (var j = 0; j < len; j = j+1;) { + print_int(new_board[i][j]); + } + } + return 0; +} diff --git a/hw6/oatprograms/matrixmult.oat b/hw6/oatprograms/matrixmult.oat new file mode 100644 index 0000000..1560b5d --- /dev/null +++ b/hw6/oatprograms/matrixmult.oat @@ -0,0 +1,69 @@ + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +int program(int argc, string[] argv) +{ + var a = new int[][]{new int[]{1, 3, 4}, + new int[]{2, 0, 1}}; + var b = new int[][]{new int[]{1, 2, 3, 1}, + new int[]{2, 2, 2, 2}, + new int[]{3, 2, 1, 4}}; + var c = new int[][]{new int[]{0, 0, 0, 0}, + new int[]{0, 0, 0, 0}}; + + matrix_Mult(a, b, c); + prnNx4(c, 2); + + matrix_MultAlt(a, b, c); /* alternate form that calls dot3 */ + prnNx4(c, 2); + return 0; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void matrix_Mult(int[][] a1, int [][] a2, int [][] a3) +{ + for(var i = 0; i < 2; i=i+1;) { + for(var j = 0; j < 4; j=j+1;) { + for(var k = 0; k < 3; k=k+1;) { + a3[i][j] = a3[i][j] + a1[i][k] * a2[k][j]; + } + } + } + return; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void matrix_MultAlt(int[][] a1, int[][] a2, int[][] a3) +{ + for(var i = 0; i < 2; i=i+1;) { + for(var j = 0; j < 4; j=j+1;) { + a3[i][j] = dot3(a1, a2, i, j); + } + } + return; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +int dot3(int[][] a1, int[][] a2, int row, int col) +{ + var sum = 0; + for(var k = 0; k < 3; k=k+1;) { + sum = sum + a1[row][k] * a2[k][col]; + } + return sum; +} + +/* http://www.edcc.edu/faculty/paul.bladek/Cmpsc142/matmult.htm */ +void prnNx4 (int[][] ar, int n) +{ + for(var i = 0; i < n; i=i+1;) + { + for(var j = 0; j < 4; j=j+1;) + { + print_int(ar[i][j]); + print_string (" "); + } + print_string("\t"); + } + return; +} + diff --git a/hw6/oatprograms/maxsubsequence.oat b/hw6/oatprograms/maxsubsequence.oat new file mode 100644 index 0000000..31b8ca1 --- /dev/null +++ b/hw6/oatprograms/maxsubsequence.oat @@ -0,0 +1,26 @@ +int maxsum(int[] arr, int size) { + var maxarr = new int[size]{i->0}; + var maxs = 0; + maxarr[0] = arr[0]; + for(var i = 0; i < size; i = i+1;){ + for(var j = 0; j < i; j=j+1;){ + if(arr[i] > arr[j] & maxarr[i] < maxarr[j] + arr[i]){ + maxarr[i] = maxarr[j] + arr[i]; + } + } + if(maxs < maxarr[i]){ + maxs = maxarr[i]; + } + } + return maxs; +} + +int program (int argc, string[] argv) { + var array = new int[]{1,101,2,3,101,4,5}; + var max_ans = maxsum(array, 7); + return max_ans; +} + + + + diff --git a/hw6/oatprograms/msort.oat b/hw6/oatprograms/msort.oat new file mode 100644 index 0000000..7c576c6 --- /dev/null +++ b/hw6/oatprograms/msort.oat @@ -0,0 +1,68 @@ +int program (int argc, string[] argv) { + var i = 0; + var a = new int[]{126,125,124,123,122,121,120,119,118,117}; + print_string (string_of_array(a)); + oat_mergesort(a,0,9); + print_string (" "); + print_string (string_of_array(a)); + print_string (" "); + return i; +} + +void oat_mergesort(int[] a, int low, int high) +{ + var mid=0; + if(low>1; + oat_mergesort(a,low,mid); + oat_mergesort(a,mid+1,high); + merge(a,low,high,mid); + } + return; +} + +void merge(int[] a, int low, int high, int mid) +{ + var i=0; + var j=0; + var k=0; + var c=new int[50]{i1->0}; + i=low; + j=mid+1; + k=low; + while((i<=mid)&(j<=high)) + { + if(a[i]>1; + oat_mergesort(a,low,mid); + oat_mergesort(a,mid+1,high); + merge(a,low,high,mid); + } + return; +} + +void merge(int[] a, int low, int high, int mid) +{ + var i=0; + var j=0; + var k=0; + var c=new int[50]{i2->0}; + i=low; + j=mid+1; + k=low; + while((i<=mid)&(j<=high)) + { + if(a[i]= 0) { + t = t - b; + } + return t; +} + +int div (int a, int b) { + var result = 0; + var num = a; + var denom = b; + while (num > 0) { + num = num - denom; + result = result + 1; + } + return result; +} + +int no_of_factors(int n) { + var num_fact = 1; + var input = n; + for (var i = 2; i * i < input + 1; i=i+1;) { + var power = 0; + while (mod(n, i) == 0) { + n = div(n, i); + power = power + 1; + } + num_fact = num_fact * (power + 1); + } + if (n > 1) { + num_fact = num_fact * 2; + } + return num_fact; +} + +int program (int argc, string[] argv) { + return no_of_factors(6400); +} diff --git a/hw6/oatprograms/path1.oat b/hw6/oatprograms/path1.oat new file mode 100644 index 0000000..8de1752 --- /dev/null +++ b/hw6/oatprograms/path1.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var x = 17; + return x; +} diff --git a/hw6/oatprograms/path2.oat b/hw6/oatprograms/path2.oat new file mode 100644 index 0000000..c80300b --- /dev/null +++ b/hw6/oatprograms/path2.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var x = 17; + var y = 18; + return x + y; +} diff --git a/hw6/oatprograms/path3.oat b/hw6/oatprograms/path3.oat new file mode 100644 index 0000000..da7f0c9 --- /dev/null +++ b/hw6/oatprograms/path3.oat @@ -0,0 +1,5 @@ +global arr = new int[]{1, 2, 3, 4}; + +int program(int argc, string[] args) { + return arr[2]; +} diff --git a/hw6/oatprograms/phase2_1.oat b/hw6/oatprograms/phase2_1.oat new file mode 100644 index 0000000..d3c10cb --- /dev/null +++ b/hw6/oatprograms/phase2_1.oat @@ -0,0 +1,7 @@ +int x = 3; +string y = "hello"; + +int program(int argc, string[] argv) { + print_string(y); + return 0; +} diff --git a/hw6/oatprograms/qs_bs.oat b/hw6/oatprograms/qs_bs.oat new file mode 100644 index 0000000..3a42712 --- /dev/null +++ b/hw6/oatprograms/qs_bs.oat @@ -0,0 +1,52 @@ +int partition(int[] a, int low_ind, int hi_ind) { + var pivot = a[hi_ind]; + var i = low_ind - 1; + for (var j = low_ind; j < hi_ind; j=j+1;) { + if (a[j] <= pivot) { + i = i + 1; + var atemp1 = a[i]; + a[i] = a[j]; + a[j] = atemp1; + } + } + var atemp2 = a[i+1]; + a[i+1] = a[hi_ind]; + a[hi_ind] = atemp2; + return i+1; +} + +void quicksort(int[] a, int low_ind, int hi_ind) { + if (low_ind < hi_ind) { + var p = partition(a, low_ind, hi_ind); + quicksort(a, low_ind, p-1); + quicksort(a, p+1, hi_ind); + } + return ; +} + +int int_division (int a, int b) { + var btemp = 0; + var i = 0; + while (a > btemp) { + btemp = btemp + b; + i = i + 1; + } + return i; +} + +int binary_search (int[] a, int e, int max, int min) { + var mid = min + int_division (max - min, 2); + if (a[mid] == e) { + return mid; + } + if (a[mid] > e) { + return binary_search (a, e, mid - 1, min); + } + return binary_search (a, e, max, mid + 1); +} + +int program (int argc, string[] argv) { + var a = new int[] {5, 9, 6, 4, 2, 7, 10, 100, 1000, 99, 55, 999, 33, 4, 20}; + quicksort (a, 0, 14); + return binary_search (a, 10, 14, 0) + 7 * binary_search (a, 4, 14, 0) + 23 * binary_search (a, 999, 14, 0); +} \ No newline at end of file diff --git a/hw6/oatprograms/qsort.oat b/hw6/oatprograms/qsort.oat new file mode 100644 index 0000000..f3f439f --- /dev/null +++ b/hw6/oatprograms/qsort.oat @@ -0,0 +1,53 @@ + +void quick_sort( int[] a, int l, int r) +{ + var j=0; + + if( l < r ) + { + /* divide and conquer */ + j = partition( a, l, r); + quick_sort( a, l, j-1); + quick_sort( a, j+1, r); + } + + return; +} + +int partition( int[] a, int l, int r) { + var pivot=a[l]; + var i =l; + var j = r+1; + var t=0; + var done = 0; + + while(done==0) + { + i = i + 1; + while( a[i] <= pivot & i <= r ) { + i = i + 1; + } + j = j - 1; + while( a[j] > pivot ) { + j = j - 1; + } + if( i >= j ) { done=1; } + if (done==0) { + t = a[i]; a[i] = a[j]; a[j] = t; + } + } + t = a[l]; a[l] = a[j]; a[j] = t; + return j; +} + +int program (int argc, string[] argv) { + + var a = new int[]{ 107, 112, 121, 102, 123, 115, 104, 111, 109}; + + print_string (string_of_array (a)); + quick_sort( a, 0, 8); + print_string (string_of_array (a)); + + return 255; +} + diff --git a/hw6/oatprograms/regalloctest.oat b/hw6/oatprograms/regalloctest.oat new file mode 100644 index 0000000..46f2d2b --- /dev/null +++ b/hw6/oatprograms/regalloctest.oat @@ -0,0 +1,24 @@ +int program(int argc, string[] argv) { + var x = 0; + for (var i = 0; i < 10000000; i = i + 1;) { + var a = 0; + var b = a + i; + var c = b + i; + var d = c + i; + var e = d + i; + var f = e + i; + var g = f + i; + var h = g + i; + var j = h + i; + var k = j + i; + var l = k + i; + var m = l + i; + var n = m + i; + var o = n + i; + var p = o + i; + var q = p + i; + var r = q + i; + x = x + r; + } + return x; +} diff --git a/hw6/oatprograms/regalloctest2.oat b/hw6/oatprograms/regalloctest2.oat new file mode 100644 index 0000000..990c425 --- /dev/null +++ b/hw6/oatprograms/regalloctest2.oat @@ -0,0 +1,34 @@ +int foo(int x, int y, int z) { + var a = x + y; + var b = y + z; + return a + b; +} + +int program(int argc, string[] argv) { + var x = 0; + for (var i = 0; i < 10000000; i = i + 1;) { + var a = 0; + var b = a + i; + var c = b + i; + var d = c + i; + d = d + foo(a, b, c); + var e = d + i; + var f = e + i; + var g = f + i; + var h = g + i; + var j = h + i; + j = j + foo(f, g, h); + var k = j + i; + var l = k + i; + var m = l + i; + var n = m + i; + n = n + foo(k, l, m); + var o = n + i; + var p = o + i; + var q = p + i; + var r = q + i; + x = x + r; + } + print_int(x); + return 0; +} diff --git a/hw6/oatprograms/regex.oat b/hw6/oatprograms/regex.oat new file mode 100644 index 0000000..5364401 --- /dev/null +++ b/hw6/oatprograms/regex.oat @@ -0,0 +1,34 @@ +int reg_match(int[] str, int[] reg, int p1, int p2, int last) { + if (str[p1] == 0 & reg[p2] == 0) { + return 1; + } + if (str[p1] == 0 & reg[p2] != 0) { + return 0; + } + if (str[p1] != 0 & reg[p2] == 0) { + return 0; + } + if (reg[p2+1] == 42) { + return reg_match(str, reg, p1, p2+1, reg[p2]); + } + if (reg[p2] == 42) { + var result = reg_match(str, reg, p1, p2+1, 0); + if (result == 1) { + return 1; + } + if (str[p1] == last | last == 46) { + return reg_match(str, reg, p1+1, p2, last); + } + return 0; + } + if (str[p1] == reg[p2] | reg[p2] == 46) { + return reg_match(str, reg, p1+1, p2+1, 0); + } + return 0; +} + +int program(int argc, string[] argv) { + var str = new int[]{97, 98, 99, 99, 99, 99, 99, 100, 101, 102, 0}; + var reg = new int[]{97, 103, 42, 46, 99, 42, 99, 42, 100, 101, 42, 102, 0}; + return reg_match(str, reg, 0, 0, 0); +} diff --git a/hw6/oatprograms/reverse.oat b/hw6/oatprograms/reverse.oat new file mode 100644 index 0000000..d7ab3f9 --- /dev/null +++ b/hw6/oatprograms/reverse.oat @@ -0,0 +1,31 @@ +int mod_ten (int n) { + if (n < 10) { + return n; + } + + return mod_ten (n - 10); +} + +int div_ten (int n) { + var c = 0; + while (n >= 10) { + n = n - 10; + c = c + 1; + } + return c; +} + +int reversed (int n) { + var r = 0; + while (n != 0) { + var n_mod_ten = mod_ten(n); + r = (r * 10) + n_mod_ten; + n = div_ten(n); + } + return r; +} + +int program (int argc, string[] argv) { + var n = 321; + return reversed(n); +} \ No newline at end of file diff --git a/hw6/oatprograms/rod_cutting.oat b/hw6/oatprograms/rod_cutting.oat new file mode 100644 index 0000000..dfe09b6 --- /dev/null +++ b/hw6/oatprograms/rod_cutting.oat @@ -0,0 +1,62 @@ +bool arr_eq(int[] arr1, int[] arr2, int n) { + var flag = true; + for(var i = 0; i < n; i = i + 1;) { + flag = flag & (arr1[i] == arr2[i]); + } + return flag; +} + +void clear_arr(int[] arr, int length) { + for (var i = 0; i < length; i = i + 1;) { arr[i] = 0; } + return; +} + +/* Adapted from CLRS */ +int optimal_cuts (int[] prices, int length, int[] choices) { + var max_price = new int[length + 1]; + max_price[0] = 0; + var first_cut = new int[length + 1]; + clear_arr(first_cut, length + 1); + + for (var j = 1; j <= length; j = j+1;) { + var max_j = 0; + for (var i = 1; i <= j; i = i+1;) { + var new_soln = prices[i] + max_price[j - i]; + if (new_soln > max_j) { + max_j = new_soln; + first_cut[j] = i; + } + } + max_price[j] = max_j; + } + + var n = length; + /* First cut stores the largest optimal cut that can be made */ + /* We can recurse downwards to construct the final answer */ + while (n > 0) { + var cut = first_cut[n]; + choices[cut] = choices[cut] + 1; + n = n - cut; + } + + return max_price[length]; +} + +int program (int argc, string[] argv) { + var prices = new int[] {0, 1, 5, 11, 13, 15, 17, 17, 20, 24, 30}; + var length = 10; + var cuts = new int[length + 1]; + clear_arr(cuts, length + 1); + + var max_price = optimal_cuts(prices, length, cuts); + + var expected_max_price = 35; + var expected_cuts = new int[]{0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0}; + + if (expected_max_price == max_price & + arr_eq(expected_cuts, cuts, length + 1)) { + return max_price; + } else { + return 0; + } +} diff --git a/hw6/oatprograms/run1.oat b/hw6/oatprograms/run1.oat new file mode 100644 index 0000000..a1162e2 --- /dev/null +++ b/hw6/oatprograms/run1.oat @@ -0,0 +1,21 @@ +global i = 42; + +int f(int x) { + return x; +} + +int g(int[] y) { + return y[2]; +} + +int program (int argc, string[] argv) { + var garr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + var arr = new int[]{1, 2, 3, 4}; + var p=0; + + for (var j=0; j<100; j=j+1; ) { + p=p+1; + } + + return g(arr) + f(i) + f(arr[3]) + f(garr[1][1]) + f(p); +} diff --git a/hw6/oatprograms/run10.oat b/hw6/oatprograms/run10.oat new file mode 100644 index 0000000..9b83d8d --- /dev/null +++ b/hw6/oatprograms/run10.oat @@ -0,0 +1,9 @@ +int[] f (int[] arr) { + return arr; +} + +int program (int argc, string[] argv) { + var garr = new int[][] {new int[]{1, 2, 3}, new int[]{4, 5, 6}}; + var arr = f(garr[1]); + return arr[1]; +} diff --git a/hw6/oatprograms/run11.oat b/hw6/oatprograms/run11.oat new file mode 100644 index 0000000..55ade43 --- /dev/null +++ b/hw6/oatprograms/run11.oat @@ -0,0 +1,28 @@ +global i = 1; + +int f(int[] arr) { + return arr[3]; +} + +int[] g() { + var arr = new int[] {99, 1, 99, 99}; + return arr; +} + +int program (int argc, string[] argv) { + var arr1 = new int[] {99, 1, 99}; + var arr2 = new int[][] {new int[]{99,99,99}, + new int[]{99,1,99}, + new int[]{99,99,99}}; + + var c = 1; + var arr4 = g(); + var arr3 = new int[] {99, 99, 99, 1}; + c = c + i; + c = c + arr1[1]; + c = c + arr2[1][1]; + c = c + arr3[3]; + c = c + f(arr3); + c = c + arr4[1]; + return c; +} diff --git a/hw6/oatprograms/run13.oat b/hw6/oatprograms/run13.oat new file mode 100644 index 0000000..ddec733 --- /dev/null +++ b/hw6/oatprograms/run13.oat @@ -0,0 +1,7 @@ +int f(int x, int y) { + return x; +} + +int program (int argc, string[] argv) { + return f(1, 2); +} diff --git a/hw6/oatprograms/run14.oat b/hw6/oatprograms/run14.oat new file mode 100644 index 0000000..d556347 --- /dev/null +++ b/hw6/oatprograms/run14.oat @@ -0,0 +1,19 @@ +int f(int[] a) { + return a[1]; +} + +int g(int x) { + var arr = new int[3]{i->0}; + for (var i = 0; i < 3; i=i+1;) { arr[i] = x; } + return arr[1]; +} + +int program (int argc, string[] argv) { + var a = new int[3]{i->0}; + for (var i=0; i < 3; i=i+1;) { a[i] = i; } + var arr = new int[4]{i->0}; + for (var i=0; i < 4; i=i+1;) { arr[i] = i*i; } + var arr0 = new int[3]{i->0}; + for (var i=0; i < 3; i=i+1;) { arr0[i] = 2*i; } + return arr[3] + a[1] + f(arr0) + g(4); +} diff --git a/hw6/oatprograms/run15.oat b/hw6/oatprograms/run15.oat new file mode 100644 index 0000000..9d96465 --- /dev/null +++ b/hw6/oatprograms/run15.oat @@ -0,0 +1,15 @@ +int f(int[][] a) { + return a[1][1]; +} + +int g(int x) { + var arr = new int[][3]{i-> new int[3]{j -> x}}; + return arr[1][1]; +} + +int program (int argc, string[] argv) { + var a = new int[][3]{i -> new int[3]{j -> j}}; + var arr = new int[][4]{i -> new int[5]{j -> i*j }}; + var arr0 = new int[][3]{i -> new int[3]{j -> i*j}}; + return arr[3][4] + a[1][2] + f(arr0) + g(4); +} diff --git a/hw6/oatprograms/run16.oat b/hw6/oatprograms/run16.oat new file mode 100644 index 0000000..9c0049b --- /dev/null +++ b/hw6/oatprograms/run16.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var x = 10; + var a = new int[][3]{i -> new int[3]{j -> x+i+j}}; + var b = a; + return b[2][1]; +} diff --git a/hw6/oatprograms/run17.oat b/hw6/oatprograms/run17.oat new file mode 100644 index 0000000..1a5ee03 --- /dev/null +++ b/hw6/oatprograms/run17.oat @@ -0,0 +1,12 @@ +int program (int argc, string[] argv) { + var x = 10; + var a = new int[][3]; + for (var i = 0; i<3; i = i+1;) { + a[i] = new int[3]; + for (var j = 0; j<3; j=j+1;) { + a[i][j] = x+i+j; + } + } + var b = a; + return b[2][2]; +} diff --git a/hw6/oatprograms/run18.oat b/hw6/oatprograms/run18.oat new file mode 100644 index 0000000..793af78 --- /dev/null +++ b/hw6/oatprograms/run18.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{1, 100, 999}; + return a[2]; +} diff --git a/hw6/oatprograms/run19.oat b/hw6/oatprograms/run19.oat new file mode 100644 index 0000000..9c76a76 --- /dev/null +++ b/hw6/oatprograms/run19.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var i=999; + var a = new int[]{1, 100, 999}; + return a[2]; +} diff --git a/hw6/oatprograms/run2.oat b/hw6/oatprograms/run2.oat new file mode 100644 index 0000000..8a2fd49 --- /dev/null +++ b/hw6/oatprograms/run2.oat @@ -0,0 +1,18 @@ +global i=0; + +int f(int x, int y) { + var r = 0; + if (x >= 1) { + r = 1 + f (x-1, y); + } else { + r = x + y; + } + return r; +} + +int program (int argc, string[] argv) { + var x = 3; + var y = 3; + + return f(x, y)+i; +} diff --git a/hw6/oatprograms/run20.oat b/hw6/oatprograms/run20.oat new file mode 100644 index 0000000..6978566 --- /dev/null +++ b/hw6/oatprograms/run20.oat @@ -0,0 +1,6 @@ +int f() {return 19;} + +int program (int argc, string[] argv) { + var a = new int[]{1, 100, 19}; + return a[2]; +} diff --git a/hw6/oatprograms/run21.oat b/hw6/oatprograms/run21.oat new file mode 100644 index 0000000..58bfb4a --- /dev/null +++ b/hw6/oatprograms/run21.oat @@ -0,0 +1,5 @@ + +int program (int argc, string[] argv) { + var i= new int[]{99,0}; + return i[0]; +} diff --git a/hw6/oatprograms/run22.oat b/hw6/oatprograms/run22.oat new file mode 100644 index 0000000..1e4c461 --- /dev/null +++ b/hw6/oatprograms/run22.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var strs = new string[]{"abc", "def"}; + print_string (strs[0]); + return 0; +} diff --git a/hw6/oatprograms/run23.oat b/hw6/oatprograms/run23.oat new file mode 100644 index 0000000..7aa00e6 --- /dev/null +++ b/hw6/oatprograms/run23.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var strs = new string[][]{new string[]{"abc", "def"}, + new string[]{"789", "123"}}; + print_string (strs[1][1]); + return 0; +} diff --git a/hw6/oatprograms/run24.oat b/hw6/oatprograms/run24.oat new file mode 100644 index 0000000..a373076 --- /dev/null +++ b/hw6/oatprograms/run24.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{}; + return 0; +} diff --git a/hw6/oatprograms/run25.oat b/hw6/oatprograms/run25.oat new file mode 100644 index 0000000..3d54e9e --- /dev/null +++ b/hw6/oatprograms/run25.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var a = new int[3]{i -> 110}; + var str = string_of_array (a); + print_string (str); + return 0; +} diff --git a/hw6/oatprograms/run26.oat b/hw6/oatprograms/run26.oat new file mode 100644 index 0000000..4e1f768 --- /dev/null +++ b/hw6/oatprograms/run26.oat @@ -0,0 +1,3 @@ +int program (int argc, string[] argv) { + return 0; +} diff --git a/hw6/oatprograms/run27.oat b/hw6/oatprograms/run27.oat new file mode 100644 index 0000000..ad9574f --- /dev/null +++ b/hw6/oatprograms/run27.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var i=99; + return i; +} diff --git a/hw6/oatprograms/run28.oat b/hw6/oatprograms/run28.oat new file mode 100644 index 0000000..25d5676 --- /dev/null +++ b/hw6/oatprograms/run28.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var i=9; + var j=i+i; + return i+i*i-j>>2<<2>>>2; +} diff --git a/hw6/oatprograms/run29.oat b/hw6/oatprograms/run29.oat new file mode 100644 index 0000000..6fb41b6 --- /dev/null +++ b/hw6/oatprograms/run29.oat @@ -0,0 +1,6 @@ +global b=true; +int program (int argc, string[] argv) { + var i=0; + if (b) { i=1; } + return i; +} diff --git a/hw6/oatprograms/run3.oat b/hw6/oatprograms/run3.oat new file mode 100644 index 0000000..3484306 --- /dev/null +++ b/hw6/oatprograms/run3.oat @@ -0,0 +1,6 @@ +global arr = int[] null; + +int program (int argc, string[] argv) { + arr = new int[] {1,2}; + return arr[1]; +} diff --git a/hw6/oatprograms/run30.oat b/hw6/oatprograms/run30.oat new file mode 100644 index 0000000..cb9983f --- /dev/null +++ b/hw6/oatprograms/run30.oat @@ -0,0 +1,4 @@ +global i=9; +int program (int argc, string[] argv) { + return i; +} diff --git a/hw6/oatprograms/run31.oat b/hw6/oatprograms/run31.oat new file mode 100644 index 0000000..c358275 --- /dev/null +++ b/hw6/oatprograms/run31.oat @@ -0,0 +1,5 @@ +global i=9; +int program (int argc, string[] argv) { + var j = i; + return j; +} diff --git a/hw6/oatprograms/run32.oat b/hw6/oatprograms/run32.oat new file mode 100644 index 0000000..ade21f7 --- /dev/null +++ b/hw6/oatprograms/run32.oat @@ -0,0 +1,12 @@ +global i=11; +int f () { + var i=12; + return i; +} +int g() { + var i=10; + return i; +} +int program (int argc, string[] argv) { + return f() + g() + i; +} diff --git a/hw6/oatprograms/run33.oat b/hw6/oatprograms/run33.oat new file mode 100644 index 0000000..7fe7413 --- /dev/null +++ b/hw6/oatprograms/run33.oat @@ -0,0 +1,6 @@ +int program (int argc, string[] argv) { + var b = new bool[]{true, false}; + var i = 0; + if (b[0]) { i = 1; } + return i; +} diff --git a/hw6/oatprograms/run34.oat b/hw6/oatprograms/run34.oat new file mode 100644 index 0000000..7b187f5 --- /dev/null +++ b/hw6/oatprograms/run34.oat @@ -0,0 +1,12 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{0,1,2,3}, + new int[]{4,5,6,7}, + new int[]{8,9,10,11}}; + var s=0; + for(var i=0; i<3; i=i+1;) { + for(var j=0; j<4; j=j+1;) { + s=s+a[i][j]; + } + } + return s; +} diff --git a/hw6/oatprograms/run35.oat b/hw6/oatprograms/run35.oat new file mode 100644 index 0000000..8462f77 --- /dev/null +++ b/hw6/oatprograms/run35.oat @@ -0,0 +1,14 @@ +global a= int[][] null; + +int program (int argc, string[] argv) { + a = new int[][]{new int[]{0,1,2,3}, + new int[]{4,5,6,7}, + new int[]{8,9,10,11}}; + var s=0; + for(var i=0; i<3; i=i+1;) { + for(var j=0; j<4; j=j+1;) { + s=s+a[i][j]; + } + } + return s; +} diff --git a/hw6/oatprograms/run36.oat b/hw6/oatprograms/run36.oat new file mode 100644 index 0000000..3058e90 --- /dev/null +++ b/hw6/oatprograms/run36.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{0,0}; + return a[1]; +} diff --git a/hw6/oatprograms/run37.oat b/hw6/oatprograms/run37.oat new file mode 100644 index 0000000..221d5c6 --- /dev/null +++ b/hw6/oatprograms/run37.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return a[0][1]; +} diff --git a/hw6/oatprograms/run38.oat b/hw6/oatprograms/run38.oat new file mode 100644 index 0000000..5739949 --- /dev/null +++ b/hw6/oatprograms/run38.oat @@ -0,0 +1,12 @@ +int f1() { return f2(); } +int f2() { return f3(); } +int f3() { return f4(); } +int f4() { return f5(); } +int f5() { return f6(); } +int f6() { return f7(); } +int f7() { return f8(); } +int f8() { return f9(); } +int f9() { return 31; } +int program (int argc, string[] argv) { + return f1(); +} diff --git a/hw6/oatprograms/run39.oat b/hw6/oatprograms/run39.oat new file mode 100644 index 0000000..397da9c --- /dev/null +++ b/hw6/oatprograms/run39.oat @@ -0,0 +1,12 @@ +int f1(int i) { return f2(i); } +int f2(int i) { return f3(i); } +int f3(int i) { return f4(i); } +int f4(int i) { return f5(i); } +int f5(int i) { return f6(i); } +int f6(int i) { return f7(i); } +int f7(int i) { return f8(i); } +int f8(int i) { return f9(i); } +int f9(int i) { return i; } +int program (int argc, string[] argv) { + return f1(argc); +} diff --git a/hw6/oatprograms/run4.oat b/hw6/oatprograms/run4.oat new file mode 100644 index 0000000..77c9593 --- /dev/null +++ b/hw6/oatprograms/run4.oat @@ -0,0 +1,6 @@ +global arr = int[] null; + +int program (int argc, string[] argv) { + arr = new int[]{17,42}; + return arr[1]; +} diff --git a/hw6/oatprograms/run40.oat b/hw6/oatprograms/run40.oat new file mode 100644 index 0000000..0af7b53 --- /dev/null +++ b/hw6/oatprograms/run40.oat @@ -0,0 +1,10 @@ +global i=8; +int f() { + var j=0; + j=g(); + return j; +} +int g() {return i;} +int program(int argc, string[] argv) { + return f(); +} diff --git a/hw6/oatprograms/run41.oat b/hw6/oatprograms/run41.oat new file mode 100644 index 0000000..ce3c276 --- /dev/null +++ b/hw6/oatprograms/run41.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5+x6+x7+x8; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw6/oatprograms/run42.oat b/hw6/oatprograms/run42.oat new file mode 100644 index 0000000..b1164ce --- /dev/null +++ b/hw6/oatprograms/run42.oat @@ -0,0 +1,16 @@ +int program(int argc, string[] argv) { + var a1=new int[][3]{i->new int[1]{j->0}}; + var a2=new int[][3]{i->new int[1]{j->0}}; + var a3=new int[][3]{i->new int[1]{j->0}}; + var a4=new int[][3]{i->new int[1]{j->0}}; + var a5=new int[3]{i->i}; + a2[0] = a5; + a2[0][0] = 2; + a1 = a2; + a3 = a1; + a1 = a4; + a2 = a3; + a4 = a2; + a3 = a4; + return a3[0][0]; +} diff --git a/hw6/oatprograms/run43.oat b/hw6/oatprograms/run43.oat new file mode 100644 index 0000000..04e74a7 --- /dev/null +++ b/hw6/oatprograms/run43.oat @@ -0,0 +1,35 @@ +global a = int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] null; + +int program (int argc, string[] argv) { + a = new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][][]{ + new int[][][][][][][][][][][][]{ + new int[][][][][][][][][][][]{ + new int[][][][][][][][][][]{ + new int[][][][][][][][][]{ + new int[][][][][][][][]{ + new int[][][][][][][]{ + new int[][][][][][]{ + new int[][][][][]{ + new int[][][][]{ + new int[][][]{ + new int[][]{ + new int[]{42}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + return a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]; +} diff --git a/hw6/oatprograms/run44.oat b/hw6/oatprograms/run44.oat new file mode 100644 index 0000000..3e3ecc6 --- /dev/null +++ b/hw6/oatprograms/run44.oat @@ -0,0 +1,18 @@ +global str = string[][][][][][][][][][] null; + +int program (int argc, string[] argv) { + str = new string[][][][][][][][][][1]{i1 -> + new string[][][][][][][][][1]{i2 -> + new string[][][][][][][][1]{i3 -> + new string[][][][][][][1]{i4 -> + new string[][][][][][1]{i5 -> + new string[][][][][1]{i6 -> + new string[][][][1]{i7 -> + new string[][][1]{i8 -> + new string[][1]{i9 -> + new string[1]{i10 -> "hello"}}}}}}}}}}; + + print_string (str[0][0][0][0][0][0][0][0][0][0]); + return 0; +} + diff --git a/hw6/oatprograms/run45.oat b/hw6/oatprograms/run45.oat new file mode 100644 index 0000000..02eade4 --- /dev/null +++ b/hw6/oatprograms/run45.oat @@ -0,0 +1,37 @@ +global a = string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] null; + + +int program (int argc, string[] argv) { + a = new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][]{ + new string[][][][][][][][][][][]{ + new string[][][][][][][][][][]{ + new string[][][][][][][][][]{ + new string[][][][][][][][]{ + new string[][][][][][][]{ + new string[][][][][][]{ + new string[][][][][]{ + new string[][][][]{ + new string[][][]{ + new string[][]{ + new string[]{"42"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + print_string (a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]); + return 0; +} diff --git a/hw6/oatprograms/run46.oat b/hw6/oatprograms/run46.oat new file mode 100644 index 0000000..12dcdf0 --- /dev/null +++ b/hw6/oatprograms/run46.oat @@ -0,0 +1,37 @@ + +int program (int argc, string[] argv) { +var a = + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][][]{ + new string[][][][][][][][][][][][]{ + new string[][][][][][][][][][][]{ + new string[][][][][][][][][][]{ + new string[][][][][][][][][]{ + new string[][][][][][][][]{ + new string[][][][][][][]{ + new string[][][][][][]{ + new string[][][][][]{ + new string[][][][]{ + new string[][][]{ + new string[][]{ + new string[]{"42"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; + + print_string (a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]); + return 0; +} diff --git a/hw6/oatprograms/run47.oat b/hw6/oatprograms/run47.oat new file mode 100644 index 0000000..c2b1032 --- /dev/null +++ b/hw6/oatprograms/run47.oat @@ -0,0 +1,11 @@ +global a = 1; + +int f() { + a = a + 1; + return a; +} + +int program (int argc, string[] argv) { + var b = new int[f()]{i -> i}; + return a + b[0] + b[1]; +} diff --git a/hw6/oatprograms/run48.oat b/hw6/oatprograms/run48.oat new file mode 100644 index 0000000..789d22a --- /dev/null +++ b/hw6/oatprograms/run48.oat @@ -0,0 +1,11 @@ +global a = 1; + +int f() { + a = a + 1; + return a; +} + +int program (int argc, string[] argv) { + var b = new int[f()]{i -> f()}; + return a + b[0] + b[1]; +} diff --git a/hw6/oatprograms/run49.oat b/hw6/oatprograms/run49.oat new file mode 100644 index 0000000..b53b94f --- /dev/null +++ b/hw6/oatprograms/run49.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + print_string ("abc"); + return 0; +} diff --git a/hw6/oatprograms/run5.oat b/hw6/oatprograms/run5.oat new file mode 100644 index 0000000..2dfbfec --- /dev/null +++ b/hw6/oatprograms/run5.oat @@ -0,0 +1,6 @@ +global arr= int[][] null; + +int program (int argc, string[] argv) { + arr = new int[][] {new int[]{1,2}, new int[]{3,4}}; + return arr[1][1]; +} diff --git a/hw6/oatprograms/run50.oat b/hw6/oatprograms/run50.oat new file mode 100644 index 0000000..3f26739 --- /dev/null +++ b/hw6/oatprograms/run50.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + print_string ("abcde"); + return 0; +} diff --git a/hw6/oatprograms/run51.oat b/hw6/oatprograms/run51.oat new file mode 100644 index 0000000..19af8e5 --- /dev/null +++ b/hw6/oatprograms/run51.oat @@ -0,0 +1,8 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5+x6+x7+x8; +} +int program (int argc, string[] argv) { + var x = f(1,2,3,4,5,-5,-4,-3); + print_int(x); + return 41; +} diff --git a/hw6/oatprograms/run52.oat b/hw6/oatprograms/run52.oat new file mode 100644 index 0000000..8347c0c --- /dev/null +++ b/hw6/oatprograms/run52.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4+x5; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw6/oatprograms/run53.oat b/hw6/oatprograms/run53.oat new file mode 100644 index 0000000..5e9a98d --- /dev/null +++ b/hw6/oatprograms/run53.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var str = string_of_array (new int[]{110, 110, 110}); + print_string (str); + return 0; +} diff --git a/hw6/oatprograms/run54.oat b/hw6/oatprograms/run54.oat new file mode 100644 index 0000000..238febe --- /dev/null +++ b/hw6/oatprograms/run54.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3+x4; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw6/oatprograms/run55.oat b/hw6/oatprograms/run55.oat new file mode 100644 index 0000000..34c756c --- /dev/null +++ b/hw6/oatprograms/run55.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x3; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw6/oatprograms/run56.oat b/hw6/oatprograms/run56.oat new file mode 100644 index 0000000..8c9daa5 --- /dev/null +++ b/hw6/oatprograms/run56.oat @@ -0,0 +1,6 @@ +int f(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8) { + return x1+x2+x4; +} +int program (int argc, string[] argv) { + return f(1,2,3,4,5,-5,-4,-3); +} diff --git a/hw6/oatprograms/run6.oat b/hw6/oatprograms/run6.oat new file mode 100644 index 0000000..d30dd17 --- /dev/null +++ b/hw6/oatprograms/run6.oat @@ -0,0 +1,6 @@ +global arr= int[][] null; + +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return arr[0][0]; +} diff --git a/hw6/oatprograms/run60.oat b/hw6/oatprograms/run60.oat new file mode 100644 index 0000000..3b2d0ae --- /dev/null +++ b/hw6/oatprograms/run60.oat @@ -0,0 +1,6 @@ +global i = 3; + +int program(int argc, string[] argv) { + i = 341; + return i; +} diff --git a/hw6/oatprograms/run61.oat b/hw6/oatprograms/run61.oat new file mode 100644 index 0000000..b6b7947 --- /dev/null +++ b/hw6/oatprograms/run61.oat @@ -0,0 +1,6 @@ +global s = "341"; + +int program(int argc, string[] argv) { + print_string(s); + return 0; +} diff --git a/hw6/oatprograms/run7.oat b/hw6/oatprograms/run7.oat new file mode 100644 index 0000000..3c7afe2 --- /dev/null +++ b/hw6/oatprograms/run7.oat @@ -0,0 +1,6 @@ +global arr = int[][][] null; + +int program (int argc, string[] argv) { + arr = new int[][][]{new int[][]{new int[]{1,2}, new int[]{3,4}}, new int[][]{new int[]{5}}, new int[][]{new int[]{10,20}, new int[]{30,40}}}; + return arr[2][0][1]; +} diff --git a/hw6/oatprograms/run8.oat b/hw6/oatprograms/run8.oat new file mode 100644 index 0000000..548ca08 --- /dev/null +++ b/hw6/oatprograms/run8.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr= new int[] {1,2}; + + return arr[1]; +} diff --git a/hw6/oatprograms/run9.oat b/hw6/oatprograms/run9.oat new file mode 100644 index 0000000..197f527 --- /dev/null +++ b/hw6/oatprograms/run9.oat @@ -0,0 +1,5 @@ +int program (int argc, string[] argv) { + var arr=new int[][] {new int []{1,2}, new int[]{3,4}}; + + return arr[1][1]; +} diff --git a/hw6/oatprograms/runtime-fail1.oat b/hw6/oatprograms/runtime-fail1.oat new file mode 100644 index 0000000..a0cdc50 --- /dev/null +++ b/hw6/oatprograms/runtime-fail1.oat @@ -0,0 +1,6 @@ +global arr = int[][] null; + +int program (int argc, string[] argv) { + var arr = new int[][]{new int[]{1,2}, new int[]{3,4}}; + return arr[1][3]; +} diff --git a/hw6/oatprograms/runtime-fail2.oat b/hw6/oatprograms/runtime-fail2.oat new file mode 100644 index 0000000..4d54f38 --- /dev/null +++ b/hw6/oatprograms/runtime-fail2.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{}; + return a[0]; +} diff --git a/hw6/oatprograms/runtime-fail3.oat b/hw6/oatprograms/runtime-fail3.oat new file mode 100644 index 0000000..2ad327c --- /dev/null +++ b/hw6/oatprograms/runtime-fail3.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{0,0}; + return a[-1]; +} diff --git a/hw6/oatprograms/runtime-fail4.oat b/hw6/oatprograms/runtime-fail4.oat new file mode 100644 index 0000000..5e27495 --- /dev/null +++ b/hw6/oatprograms/runtime-fail4.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[][]{new int[]{0,0}, new int[]{0,0}}; + return a[1][3]; +} diff --git a/hw6/oatprograms/selectionsort.oat b/hw6/oatprograms/selectionsort.oat new file mode 100644 index 0000000..71b9252 --- /dev/null +++ b/hw6/oatprograms/selectionsort.oat @@ -0,0 +1,38 @@ +int getminindex(int[] a, int s, int b) +{ + var i=s; + var min=a[s]; + var mi=s; + for(; i < b; i=i+1;) + { + if ( a[i] < min ) { min = a[i]; mi = i; } + } + return mi; +} + +void selectionsort(int[] a, int s) +{ + var t=0; + var mi=0; + for(var i=0; i= w | j >= h) { + return 100; + } + if (i == w-1 & j == h-1) { + dp[i][j] = matrix[i][j]; + return dp[i][j]; + } + if (dp[i][j] != 0) { + return dp[i][j]; + } + var go_down_val = shortest_path_dp(matrix, dp, i, j+1, w, h); + var go_right_val = shortest_path_dp(matrix, dp, i+1, j, w, h); + if (go_down_val < go_right_val) { + dp[i][j] = go_down_val + matrix[i][j]; + } else { + dp[i][j] = go_right_val + matrix[i][j]; + } + return dp[i][j]; +} + +int program(int argc, string[] argv) { + var matrix = new int[][5]; + for (var i = 0; i < 5; i=i+1;) { + matrix[i] = new int[5]; + } + for (var i = 0; i < 5; i=i+1;) { + for (var j = 0; j < 5; j=j+1;) { + matrix[i][j] = 2*(i+1) + (j+1); + } + } + matrix[0][4] = 50; + matrix[1][3] = 50; + matrix[2][2] = 50; + return shortest_path(matrix, 5, 5); +} \ No newline at end of file diff --git a/hw6/oatprograms/sieve.oat b/hw6/oatprograms/sieve.oat new file mode 100644 index 0000000..9f1673b --- /dev/null +++ b/hw6/oatprograms/sieve.oat @@ -0,0 +1,30 @@ +int sieve(int n) { + var arr = new bool[n]{i->false}; + for (var i=0; i < n; i=i+1;) { arr[i] = true; } + + arr[0] = false; + arr[1] = false; + + for(var i = 0; i < n; i=i+1;) { + if(arr[i]){ + for(var j = i * 2; j < n; j=j+i;){ + arr[j] = false; + } + } + } + +var count = 0; + for(var i = 0; i < n; i=i+1;){ + if(arr[i]) { + count = count + 1; + } + } + + return count; + +} + +int program(int argc, string[] argv) { + var n = 100; + return sieve(n); +} diff --git a/hw6/oatprograms/sqrt.oat b/hw6/oatprograms/sqrt.oat new file mode 100644 index 0000000..9eed049 --- /dev/null +++ b/hw6/oatprograms/sqrt.oat @@ -0,0 +1,44 @@ +global l2 = int[]{8, 9, 10, 11, 12, 13, 14, 15}; + +int sqrt (int n) { + if (n < 0) { + return 0; + } + + var s = 0; + while (n > 0) { + var d = s * s; + if (d > n) { + n = -1; + } else { + s = s + 1; + } + } + return s - 1; +} + +int sum (int[] l) { + var sum = 0; + for (var i = 0; i < 8; i = i + 1;) { + sum = sum + l[i]; + } + return sum; +} + +int program (int argc, string[] argv) { + var l1 = new int[8]; + l1[0] = 0; + l1[1] = 1; + l1[2] = 2; + l1[3] = 3; + l1[4] = 4; + l1[5] = 5; + l1[6] = 6; + l1[7] = 7; + + var s1 = sum(l1); + var s2 = sum(l2); + var s = s1 + s2; + var rt = sqrt(s); + return rt; +} \ No newline at end of file diff --git a/hw6/oatprograms/tc1.oat b/hw6/oatprograms/tc1.oat new file mode 100644 index 0000000..7d1dd22 --- /dev/null +++ b/hw6/oatprograms/tc1.oat @@ -0,0 +1 @@ +global i = true; diff --git a/hw6/oatprograms/tc10.oat b/hw6/oatprograms/tc10.oat new file mode 100644 index 0000000..82952d5 --- /dev/null +++ b/hw6/oatprograms/tc10.oat @@ -0,0 +1,3 @@ +bool f(int[] a){ + return !a; +} diff --git a/hw6/oatprograms/tc11.oat b/hw6/oatprograms/tc11.oat new file mode 100644 index 0000000..9892ac1 --- /dev/null +++ b/hw6/oatprograms/tc11.oat @@ -0,0 +1,3 @@ +int f() { + return !0; +} diff --git a/hw6/oatprograms/tc12.oat b/hw6/oatprograms/tc12.oat new file mode 100644 index 0000000..1cb5a9c --- /dev/null +++ b/hw6/oatprograms/tc12.oat @@ -0,0 +1,5 @@ +void f() {return;} +void g() { + int i = f(); + return; +} diff --git a/hw6/oatprograms/tc13.oat b/hw6/oatprograms/tc13.oat new file mode 100644 index 0000000..2cb74ea --- /dev/null +++ b/hw6/oatprograms/tc13.oat @@ -0,0 +1,6 @@ +int f() {return 0;} + +int g() { + f(); + return 0; +} diff --git a/hw6/oatprograms/tc14.oat b/hw6/oatprograms/tc14.oat new file mode 100644 index 0000000..f81d7eb --- /dev/null +++ b/hw6/oatprograms/tc14.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new int[]{"hello"}; + return 0; +} diff --git a/hw6/oatprograms/tc15.oat b/hw6/oatprograms/tc15.oat new file mode 100644 index 0000000..63751e7 --- /dev/null +++ b/hw6/oatprograms/tc15.oat @@ -0,0 +1,4 @@ +int program (int argc, string[] argv) { + var a = new string[]{1}; + return 0; +} diff --git a/hw6/oatprograms/tc16.oat b/hw6/oatprograms/tc16.oat new file mode 100644 index 0000000..0a9ee44 --- /dev/null +++ b/hw6/oatprograms/tc16.oat @@ -0,0 +1,5 @@ +int f ( int x ) { + var x = 0; + x = x + x - x * x >> x << x | x & -~!x >>> x; + return x; +} diff --git a/hw6/oatprograms/tc17.oat b/hw6/oatprograms/tc17.oat new file mode 100644 index 0000000..deb1c95 --- /dev/null +++ b/hw6/oatprograms/tc17.oat @@ -0,0 +1,4 @@ +void f() { + var x = length_of_array(3); + return; +} diff --git a/hw6/oatprograms/tc18.oat b/hw6/oatprograms/tc18.oat new file mode 100644 index 0000000..815a7ab --- /dev/null +++ b/hw6/oatprograms/tc18.oat @@ -0,0 +1,3 @@ +int g() { + return f(); +} diff --git a/hw6/oatprograms/tc19.oat b/hw6/oatprograms/tc19.oat new file mode 100644 index 0000000..92fd7f4 --- /dev/null +++ b/hw6/oatprograms/tc19.oat @@ -0,0 +1,4 @@ +int f(int x, int y) {return 0;} +int g() { + return f(0); +} diff --git a/hw6/oatprograms/tc2.oat b/hw6/oatprograms/tc2.oat new file mode 100644 index 0000000..9e21e6c --- /dev/null +++ b/hw6/oatprograms/tc2.oat @@ -0,0 +1 @@ +global a = int[] null; diff --git a/hw6/oatprograms/tc20.oat b/hw6/oatprograms/tc20.oat new file mode 100644 index 0000000..39cdb24 --- /dev/null +++ b/hw6/oatprograms/tc20.oat @@ -0,0 +1,5 @@ +void f(int x, int y) {return;} +int g() { + f(0,1,2); + return 0; +} diff --git a/hw6/oatprograms/tc3.oat b/hw6/oatprograms/tc3.oat new file mode 100644 index 0000000..eb88f43 --- /dev/null +++ b/hw6/oatprograms/tc3.oat @@ -0,0 +1,5 @@ +bool f(int a) { + var b = true; + if (a) { b=true; } else { b=false; } + return b; +} diff --git a/hw6/oatprograms/tc4.oat b/hw6/oatprograms/tc4.oat new file mode 100644 index 0000000..2aa04a5 --- /dev/null +++ b/hw6/oatprograms/tc4.oat @@ -0,0 +1,3 @@ +int f() { + return false + 1; +} diff --git a/hw6/oatprograms/tc5.oat b/hw6/oatprograms/tc5.oat new file mode 100644 index 0000000..200f638 --- /dev/null +++ b/hw6/oatprograms/tc5.oat @@ -0,0 +1,3 @@ +int f() { + return (false * true); +} diff --git a/hw6/oatprograms/tc6.oat b/hw6/oatprograms/tc6.oat new file mode 100644 index 0000000..5bf7f21 --- /dev/null +++ b/hw6/oatprograms/tc6.oat @@ -0,0 +1,3 @@ +int f(int i) {return i;} + +int g(int j) {return g(true);} diff --git a/hw6/oatprograms/tc7.oat b/hw6/oatprograms/tc7.oat new file mode 100644 index 0000000..fbf91fa --- /dev/null +++ b/hw6/oatprograms/tc7.oat @@ -0,0 +1,6 @@ +int f() {return 0;} + +int g() { + for(; f(); ){} + return 0; +} diff --git a/hw6/oatprograms/tc8.oat b/hw6/oatprograms/tc8.oat new file mode 100644 index 0000000..c290fc6 --- /dev/null +++ b/hw6/oatprograms/tc8.oat @@ -0,0 +1,5 @@ +void f() { + var a = int[]{1}; + while (a) {} + return; +} diff --git a/hw6/oatprograms/tc9.oat b/hw6/oatprograms/tc9.oat new file mode 100644 index 0000000..cfd5675 --- /dev/null +++ b/hw6/oatprograms/tc9.oat @@ -0,0 +1,4 @@ +int f() { + var a = 1; + return; +} diff --git a/hw6/oatprograms/tc_ok1.oat b/hw6/oatprograms/tc_ok1.oat new file mode 100644 index 0000000..b1642b8 --- /dev/null +++ b/hw6/oatprograms/tc_ok1.oat @@ -0,0 +1 @@ +int f (int f) {return f;} diff --git a/hw6/oatprograms/tc_ok2.oat b/hw6/oatprograms/tc_ok2.oat new file mode 100644 index 0000000..aaa2314 --- /dev/null +++ b/hw6/oatprograms/tc_ok2.oat @@ -0,0 +1 @@ +int f() {var f=0; return f;} diff --git a/hw6/oatprograms/tc_ok4.oat b/hw6/oatprograms/tc_ok4.oat new file mode 100644 index 0000000..1b7a1d3 --- /dev/null +++ b/hw6/oatprograms/tc_ok4.oat @@ -0,0 +1,5 @@ +int f() { + var i = 0; + var arr = new int[3]{j -> 0}; + return i; +} diff --git a/hw6/oatprograms/tc_ok5.oat b/hw6/oatprograms/tc_ok5.oat new file mode 100644 index 0000000..bf9c71a --- /dev/null +++ b/hw6/oatprograms/tc_ok5.oat @@ -0,0 +1,6 @@ +global i = true; + +int f() { + var i = 0; + return i; +} diff --git a/hw6/oatprograms/tc_ok6.oat b/hw6/oatprograms/tc_ok6.oat new file mode 100644 index 0000000..29b6aa2 --- /dev/null +++ b/hw6/oatprograms/tc_ok6.oat @@ -0,0 +1,27 @@ +int f() { + var i1 = 3 + 4; + var i2 = 3 * 4; + var i3 = 3 - 4; + + var b1 = 3 == 4; + var b2 = 3 != 4; + var b6 = 3 < 4; + var b7 = 3 <= 4; + var b8 = 3 > 4; + var b9 = 3 >= 4; + + var i4 = 3 [&] 4; + var b10 = true & false; + + var i5 = 3 [|] 4; + var b11 = true | false; + + var i6 = 3 << 4; + var i7 = 3 >> 4; + var i8 = 3 >>> 4; + + var i9 = - 3; + var i10 = ~ 4; + var b12 = !false; + return 0; +} diff --git a/hw6/oatprograms/tc_ok7.oat b/hw6/oatprograms/tc_ok7.oat new file mode 100644 index 0000000..40fbba1 --- /dev/null +++ b/hw6/oatprograms/tc_ok7.oat @@ -0,0 +1,7 @@ +int f() { + return g(); +} + +int g() { + return f(); +} diff --git a/hw6/oatprograms/tc_ok8.oat b/hw6/oatprograms/tc_ok8.oat new file mode 100644 index 0000000..73e78f1 --- /dev/null +++ b/hw6/oatprograms/tc_ok8.oat @@ -0,0 +1,10 @@ +int f() { + var a1 = new int[]{1, 2, 3}; + var b = new string[]{"a", "b", "c", "d"}; + var s = string_of_array(a1); + var a2 = array_of_string("abc"); + print_string("hello"); + print_int(3); + print_bool(true); + return 0; +} diff --git a/hw6/oatprograms/toascii.oat b/hw6/oatprograms/toascii.oat new file mode 100644 index 0000000..57478c2 --- /dev/null +++ b/hw6/oatprograms/toascii.oat @@ -0,0 +1,67 @@ +/* +Takes a .gim graphics file; +prints a simple ascii representation of the colors. +Optimized for light-text-on-dark-background terminals +(inverts the colors), and subsamples the height by .5 +to better maintain aspect ratio of square files. +*/ + +int program (int argc, string[] argv) { + var s = argv[1]; + var width = get_width(s); + var height = get_height(s); + var bytes = load_image(s); + print_string(string_of_int(width)); + print_string("x"); + print_string(string_of_int(height)); + print_string("\n"); + var rowlen = 0; + var row = new int[width]; + var off = 1; + for (var i=0; i < width*height; i=i+1;) { + /*print_string(string_of_int(i)); + print_string("x"); + print_string(string_of_int(rowlen)); + print_string("x"); + print_string(string_of_int(width)); + print_string("x"); + print_string(string_of_int(bytes[i])); + print_string("\n");*/ + if (bytes[i] > 230) { + row[rowlen] = 64; /* @ */ + } else if (bytes[i] > 204) { + row[rowlen] = 37; /* % */ + } else if (bytes[i] > 179) { + row[rowlen] = 35; /* # */ + } else if (bytes[i] > 153) { + row[rowlen] = 42; /* * */ + } else if (bytes[i] > 128) { + row[rowlen] = 43; /* + */ + } else if (bytes[i] > 102) { + row[rowlen] = 61; /* = */ + } else if (bytes[i] > 77) { + row[rowlen] = 58; /* : */ + } else if (bytes[i] > 51) { + row[rowlen] = 45; /* - */ + } else if (bytes[i] > 26) { + row[rowlen] = 46; /* . */ + } else { + row[rowlen] = 32; /* */ + } + if (rowlen == width-1) { + var test = off [&] 1; + if (test == 1) { + print_string(string_of_array(row)); + print_string("\n"); + off = 0; + + } else { + off = 1; + } + rowlen = 0; + } else { + rowlen = rowlen + 1; + } + } + return 0; +} diff --git a/hw6/oatprograms/toposort.oat b/hw6/oatprograms/toposort.oat new file mode 100644 index 0000000..94ecac0 --- /dev/null +++ b/hw6/oatprograms/toposort.oat @@ -0,0 +1,51 @@ +/* 0 is white, 1 is gray, 2 is black */ +global color = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global startTimes = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global finishTimes = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global topoSort = int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +global numVertices = 16; +global index = 15; + +void dfs(int[][] adj) { + + for (var i = 0; i < numVertices; i=i+1;) { + if (color[i] == 0) { + dfsHelper(adj, i, 0); + } + } + return; +} + +void dfsHelper(int[][] adj, int s, int t) { + color[s] = 1; + startTimes[s] = t; + + var stringRep = string_of_array(adj[s]); + var length = length_of_string(stringRep); + + for (var i = 0; i < length; i=i+1;) { + var neighbor = adj[s][i]; + if (color[neighbor] == 0) { + dfsHelper(adj, neighbor, t + 1); + } + } + + color[s] = 2; + finishTimes[s] = t + 1; + topoSort[index] = s; + index = index - 1; + + return; +} + +int program(int argc, string[] argv) { + /* Graph taken from https://i.stack.imgur.com/zuLmn.png */ + var adjList = new int[][]{new int[]{7, 10, 13, 14}, new int[]{2, 9, 13}, new int[]{10, 12, 13, 14}, new int[]{6, 8, 9, 11}, new int[]{7}, new int[]{6, 7, 9, 10}, new int[]{15}, new int[]{14}, new int[]{15}, new int[]{11, 14}, new int[]{14}, new int[]{}, new int[]{}, new int[]{}, new int[]{}, new int[]{}}; + dfs(adjList); + for (var i = 0; i < numVertices; i=i+1;) { + print_int(topoSort[i]); + print_string (" "); + } + print_string ("-"); + return 0; +} diff --git a/hw6/oatprograms/union_find.oat b/hw6/oatprograms/union_find.oat new file mode 100644 index 0000000..c550a9e --- /dev/null +++ b/hw6/oatprograms/union_find.oat @@ -0,0 +1,58 @@ +int[] create_ufind(int len) +{ + var arr = new int[len]; + for(var i = 0; i < len; i = i + 1;) + { + arr[i] = i; + } + return arr; + +} + +void union(int[] comps, int u, int v) +{ + var cU = find(comps, u); + var cV = find(comps, v); + + if(cU == cV) + { + return; + } + + comps[cU] = cV; + return; +} + +int find(int[] comps, int u) +{ + var root = u; + while(root != comps[root]) + { + root = comps[root]; + } + + while(u != root) + { + var parent = comps[u]; + comps[u] = root; + u = parent; + + } + + return root; + +} + +int program (int argc, string[] argv) { + var uf = create_ufind(8); + union(uf, 0, 7); + union(uf, 1, 6); + union(uf, 2, 5); + union(uf, 5, 0); + + for(var i = 0; i < 8; i = i + 1;){ + print_int(find(uf, i)); + print_string(" "); + } + return 0; +} diff --git a/hw6/oatprograms/xor_bool.oat b/hw6/oatprograms/xor_bool.oat new file mode 100644 index 0000000..d8b6b5c --- /dev/null +++ b/hw6/oatprograms/xor_bool.oat @@ -0,0 +1,17 @@ +bool xor(bool x, bool y) { + return (x & !y) | (!x & y); +} + +int to_int(bool b) { + if (b) { + return 1; + } else { + return 0; + } +} + +int program(int argc, string[] argv) { + var t = true; + var f = false; + return to_int(xor(t, t)); +} \ No newline at end of file diff --git a/hw6/oatprograms/xor_shift.oat b/hw6/oatprograms/xor_shift.oat new file mode 100644 index 0000000..7d08dae --- /dev/null +++ b/hw6/oatprograms/xor_shift.oat @@ -0,0 +1,27 @@ +int xor (int x, int y) { + return ~(x [&] y) [&] (x [|] y); +} + +int xor_shift_plus (int[] s) { + var x = s[0]; + var y = s[1]; + + s[0] = y; + x = xor(x, x << 23); + x = xor(x, x >> 17); + x = xor(x, xor(y, y >> 26)); + s[1] = x; + + return x + y; +} + +int program (int argc, string[] argv) { + var seed = new int[2]{i->0}; + for (var i=0; i < 2; i=i+1;) { seed[i] = 100 * (i + 1); } + + print_int(xor_shift_plus(seed)); + print_string("\n"); + print_int(xor_shift_plus(seed)); + + return 0; +} \ No newline at end of file diff --git a/hw6/opt.ml b/hw6/opt.ml new file mode 100644 index 0000000..3cc8481 --- /dev/null +++ b/hw6/opt.ml @@ -0,0 +1,39 @@ +(** Optimizer *) +open Ll + +(* dead code elimination ---------------------------------------------------- *) +let dce (g:Cfg.t) : Cfg.t = + let ag = Alias.analyze g in + let lg = Liveness.analyze g in + Dce.run lg ag g + +(* constant propagation ----------------------------------------------------- *) +let cp (g:Cfg.t) : Cfg.t = + let cg = Constprop.analyze g in + Constprop.run cg g + +(* "full" optimization: n rounds of (dce followed by constant) propagation -- *) +let rec pass n (g:Cfg.t) = + if n <= 0 + then g + else pass (n - 1) (g |> dce |> cp) + +(* optimize an fdecl -------------------------------------------------------- *) +(* runs (two) passes of dce followed by constant propagation on the supplied + LL IR fdecl. *) +let opt_fdecl (gid,fdecl:Ll.gid * Ll.fdecl) : Ll.gid * Ll.fdecl = + let g = pass 2 (Cfg.of_ast fdecl) in + gid, Cfg.to_ast g + +(* flag for the main compiler driver *) +let do_opt = ref false + +(* optimize each fdecl in the program *) +let optimize (p:Ll.prog) : Ll.prog = + if !do_opt + then begin + Platform.verb @@ Printf.sprintf "..optimizing"; + { p with Ll.fdecls = List.map opt_fdecl p.Ll.fdecls } + end + else p + diff --git a/hw6/parser.mly b/hw6/parser.mly new file mode 100644 index 0000000..4fc45dd --- /dev/null +++ b/hw6/parser.mly @@ -0,0 +1,241 @@ +%{ +open Ast + +let loc (startpos:Lexing.position) (endpos:Lexing.position) (elt:'a) : 'a node = + { elt ; loc=Range.mk_lex_range startpos endpos } + +%} + +/* Declare your tokens here. */ +%token EOF +%token INT +%token NULL +%token STRING +%token IDENT +%token UIDENT + +%token TINT /* int */ +%token TVOID /* void */ +%token TSTRING /* string */ +%token IF /* if */ +%token IFQ /* if? */ +%token ELSE /* else */ +%token WHILE /* while */ +%token RETURN /* return */ +%token VAR /* var */ +%token STRUCT /* struct */ +%token SEMI /* ; */ +%token COMMA /* , */ +%token LBRACE /* { */ +%token RBRACE /* } */ +%token PLUS /* + */ +%token DASH /* - */ +%token STAR /* * */ +%token EQEQ /* == */ +%token EQ /* = */ +%token LPAREN /* ( */ +%token RPAREN /* ) */ +%token LBRACKET /* [ */ +%token RBRACKET /* ] */ +%token TILDE /* ~ */ +%token BANG /* ! */ +%token GLOBAL /* global */ +%token FOR /* for */ +%token TBOOL /* bool */ +%token LENGTH +%token TRUE +%token FALSE +%token DOT /* . */ +%token NEW /* new */ +%token GT /* > */ +%token GTEQ /* >= */ +%token LT /* < */ +%token LTEQ /* <= */ +%token BANGEQ /* != */ +%token BAR /* | */ +%token AMPER /* & */ +%token IOR /* [|] */ +%token IAND /* [&] */ +%token LTLT /* << */ +%token GTGT /* >> */ +%token GTGTGT /* >>> */ +%token ARROW /* -> */ +%token QUESTION /* ? */ + +%left IOR +%left IAND +%left BAR +%left AMPER +%left EQEQ BANGEQ +%left LT LTEQ GT GTEQ +%left LTLT GTGTGT GTGT +%left PLUS DASH +%left STAR +%left DOT +%nonassoc LOW +%nonassoc QUESTION +%nonassoc BANG +%nonassoc TILDE +%nonassoc LBRACKET +%nonassoc LPAREN + +/* ---------------------------------------------------------------------- */ + +%start prog +%start exp_top +%start stmt_top +%type exp_top +%type stmt_top + +%type prog +%type exp +%type stmt +%type block +%type ty +%% + +exp_top: + | e=exp EOF { e } + +stmt_top: + | s=stmt EOF { s } + +prog: + | p=list(decl) EOF { p } + +decl: + | GLOBAL name=IDENT EQ init=gexp SEMI + { Gvdecl (loc $startpos $endpos { name; init }) } + | frtyp=ret_ty fname=IDENT LPAREN args=arglist RPAREN body=block + { Gfdecl (loc $startpos $endpos { frtyp; fname; args; body }) } + | STRUCT name=UIDENT LBRACE fs=separated_list(SEMI, decl_field) RBRACE + { Gtdecl (loc $startpos $endpos (name, fs)) } + +decl_field: + | t=ty id=IDENT { { fieldName=id; ftyp=t } } + +arglist: + | l=separated_list(COMMA, pair(ty,IDENT)) { l } + +ty: + | TINT { TInt } + | r=rtyp { TRef r } %prec LOW + | r=rtyp QUESTION { TNullRef r } + | LPAREN t=ty RPAREN { t } + | TBOOL { TBool } + +%inline ret_ty: + | TVOID { RetVoid } + | t=ty { RetVal t } + +%inline rtyp: + | TSTRING { RString } + | t=ty LBRACKET RBRACKET { RArray t } + | id=UIDENT { RStruct id } + | LPAREN RPAREN ARROW ret=ret_ty { RFun ([], ret) } + | LPAREN t=ty RPAREN ARROW ret=ret_ty { RFun ([t], ret) } + | LPAREN t=ty COMMA l=separated_list(COMMA, ty) RPAREN ARROW ret=ret_ty + { RFun (t :: l, ret) } + +%inline bop: + | PLUS { Add } + | DASH { Sub } + | STAR { Mul } + | EQEQ { Eq } + | BANGEQ { Neq } + | LT { Lt } + | LTEQ { Lte } + | GT { Gt } + | GTEQ { Gte } + | AMPER { And } + | BAR { Or } + | IAND { IAnd } + | IOR { IOr } + | LTLT { Shl } + | GTGT { Shr } + | GTGTGT { Sar } + +%inline uop: + | DASH { Neg } + | BANG { Lognot } + | TILDE { Bitnot } + +gexp: + | r=rtyp NULL{ loc $startpos $endpos @@ CNull r } + | TRUE { loc $startpos $endpos @@ CBool true } + | FALSE { loc $startpos $endpos @@ CBool false } + | i=INT { loc $startpos $endpos @@ CInt i } + | s=STRING { loc $startpos $endpos @@ CStr s } + | NEW t=ty LBRACKET RBRACKET LBRACE cs=separated_list(COMMA, gexp) RBRACE + { loc $startpos $endpos @@ CArr (t, cs) } + | NEW i=UIDENT LBRACE fs=separated_list(SEMI, gfield) RBRACE + { loc $startpos $endpos @@ CStruct (i, fs) } + | id=IDENT {loc $startpos $endpos @@ Id id } + +gfield: + | id=IDENT EQ e=gexp { (id, e) } + +lhs: + | id=IDENT { loc $startpos $endpos @@ Id id } + | e=exp LBRACKET i=exp RBRACKET + { loc $startpos $endpos @@ Index (e, i) } + | e=exp DOT id=IDENT { loc $startpos $endpos @@ Proj (e, id) } + +exp: + | r=rtyp NULL { loc $startpos $endpos @@ CNull r } + | TRUE { loc $startpos $endpos @@ CBool true } + | FALSE { loc $startpos $endpos @@ CBool false } + | i=INT { loc $startpos $endpos @@ CInt i } + | s=STRING { loc $startpos $endpos @@ CStr s } + | NEW t=ty LBRACKET RBRACKET LBRACE cs=separated_list(COMMA, exp) RBRACE + { loc $startpos $endpos @@ CArr (t, cs) } + | NEW t=ty LBRACKET e1=exp RBRACKET + { loc $startpos $endpos @@ NewArr(t, e1) } + | NEW t=UIDENT LBRACE cs=separated_list(SEMI, field) RBRACE + { loc $startpos $endpos @@ CStruct(t, cs) } + | e=exp DOT id=IDENT { loc $startpos $endpos @@ Proj(e, id) } + | NEW t=ty LBRACKET e1=exp RBRACKET LBRACE u=IDENT ARROW e2=exp RBRACE + { loc $startpos $endpos @@ NewArrInit(t, e1, u, e2) } + | id=IDENT { loc $startpos $endpos @@ Id id } + | e=exp LBRACKET i=exp RBRACKET + { loc $startpos $endpos @@ Index (e, i) } + | e=exp LPAREN es=separated_list(COMMA, exp) RPAREN + { loc $startpos $endpos @@ Call (e,es) } + | e1=exp b=bop e2=exp { loc $startpos $endpos @@ Bop (b, e1, e2) } + | u=uop e=exp { loc $startpos $endpos @@ Uop (u, e) } + | LENGTH LPAREN e=exp RPAREN + { loc $startpos $endpos @@ Length(e) } + | LPAREN e=exp RPAREN { e } + +field: + | id=IDENT EQ e=exp { (id, e) } + +vdecl: + | VAR id=IDENT EQ init=exp { (id, init) } + +stmt: + | d=vdecl SEMI { loc $startpos $endpos @@ Decl(d) } + | p=lhs EQ e=exp SEMI { loc $startpos $endpos @@ Assn(p,e) } + | e=exp LPAREN es=separated_list(COMMA, exp) RPAREN SEMI + { loc $startpos $endpos @@ SCall (e, es) } + | ifs=if_stmt { ifs } + | RETURN SEMI { loc $startpos $endpos @@ Ret(None) } + | RETURN e=exp SEMI { loc $startpos $endpos @@ Ret(Some e) } + | WHILE LPAREN e=exp RPAREN b=block + { loc $startpos $endpos @@ While(e, b) } + | FOR LPAREN ds=separated_list(COMMA, vdecl) SEMI e=exp? SEMI s=stmt? RPAREN b=block + { loc $startpos $endpos @@ For(ds,e,s,b) } + +block: + | LBRACE stmts=list(stmt) RBRACE { stmts } + +if_stmt: + | IF LPAREN e=exp RPAREN b1=block b2=else_stmt + { loc $startpos $endpos @@ If(e,b1,b2) } + | IFQ LPAREN r=rtyp id=IDENT EQ e=exp RPAREN b1=block b2=else_stmt + { loc $startpos $endpos @@ Cast(r, id, e, b1, b2) } + +else_stmt: + | (* empty *) { [] } + | ELSE b=block { b } + | ELSE ifs=if_stmt { [ ifs ] } diff --git a/hw6/printanalysis.ml b/hw6/printanalysis.ml new file mode 100644 index 0000000..9e365f7 --- /dev/null +++ b/hw6/printanalysis.ml @@ -0,0 +1,65 @@ +open Ll +open Datastructures + +let do_live = ref false +let do_cp = ref false +let do_alias = ref false + +let print_live args (cfg:Cfg.t) : string = + Liveness.Graph.to_string @@ Liveness.analyze cfg + +let print_cp args (cfg:Cfg.t) : string = + Constprop.Graph.to_string @@ Constprop.analyze cfg + +let print_alias args (cfg:Cfg.t) : string = + Alias.Graph.to_string @@ Alias.analyze cfg + + +let files = ref [] + +let args = let open Arg in + [ "-live", Set do_live, "print liveness" + ; "-cp", Set do_cp, "print constant prop" + ; "-alias", Set do_alias, "print alias" + ] + + + +let do_file fname print_fn = + let ll_prog = Driver.parse_ll_file fname in + ll_prog.fdecls + |> List.iter @@ fun (g,f) -> + let string_of_arg (t,u) = Printf.sprintf "%s %%%s" (Llutil.sot t) u in + let ts, t = f.f_ty in + Printf.printf "define %s @%s(%s) {\n%s\n}\n" + (Llutil.sot t) g + (String.concat ", " @@ List.map string_of_arg List.(combine ts f.f_param)) + (print_fn (List.combine ts f.f_param) (Cfg.of_ast f)) + +let opt_file opt fname = + let opt_fdecl (gid,fdecl) = + let og = opt (Cfg.of_ast fdecl) in + gid, Cfg.to_ast og + in + + let p = Driver.parse_ll_file fname in + + let op = { p with fdecls = List.map opt_fdecl p.fdecls } in + + print_endline @@ Llutil.string_of_prog op + + + +let () = + if not !Sys.interactive then begin + Arg.parse args (fun f -> files := f::!files) "Usage"; + (if !do_live then List.iter (fun f -> do_file f print_live) !files); + (if !do_cp then List.iter (fun f -> do_file f print_cp) !files); + (if !do_alias then List.iter (fun f -> do_file f print_alias) !files); + + end + + + + + diff --git a/hw6/registers.ml b/hw6/registers.ml new file mode 100644 index 0000000..218011e --- /dev/null +++ b/hw6/registers.ml @@ -0,0 +1,94 @@ +;; open X86 + +(* Provides code to compute a histrogram of register usage for an x86 program.*) + +type histogram = int array + +let regs = + [Rax ; Rbx ; Rcx ; Rdx ; Rsi ; Rdi ; Rbp ; Rsp + ; R08 ; R09 ; R10 ; R11 ; R12 ; R13 ; R14 ; R15 ; Rip ] + +let idx_of_reg = function + | Rax -> 0 + | Rbx -> 1 + | Rcx -> 2 + | Rdx -> 3 + | Rsi -> 4 + | Rdi -> 5 + | Rbp -> 6 + | Rsp -> 7 + | R08 -> 8 + | R09 -> 9 + | R10 -> 10 + | R11 -> 11 + | R12 -> 12 + | R13 -> 13 + | R14 -> 14 + | R15 -> 15 + | Rip -> 16 + +let mk_empty () = Array.make 17 0 + +let r_incr (h:histogram) (r:reg) : unit = + let idx = idx_of_reg r in + h.(idx) <- h.(idx) + 1 + +let histogram_of_prog (p:prog) : histogram * int = + let h = mk_empty () in + let size = ref 0 in + + let h_opnd = function + | Reg r | Ind2 r | Ind3 (_, r) -> r_incr h r + | Imm _ | Ind1 _ -> () + in + + let h_ins (_, ops) = incr size; (List.iter h_opnd ops) in + + let h_elem {lbl; global; asm} = + match asm with + | Text insns -> List.iter h_ins insns + | Data _ -> () + in + let _ = List.iter h_elem p in + h, !size + +let memop_of_prog (p:prog) : int = + let count = ref 0 in + + let m_opnd = function + | Ind2 r | Ind3 (_, r) -> incr count + | Reg _ | Imm _ | Ind1 _ -> () + in + + let m_opcode = function + | Pushq | Popq -> incr count + | Movq | Leaq + | Incq | Decq | Negq | Notq + | Addq | Subq | Imulq | Xorq | Orq | Andq + | Shlq | Sarq | Shrq + | Jmp | J _ + | Cmpq | Set _ + | Callq | Retq -> () + in + let h_ins (oc, ops) = + m_opcode oc; + List.iter m_opnd ops + in + + let h_elem {lbl; global; asm} = + match asm with + | Text insns -> List.iter h_ins insns + | Data _ -> () + in + let _ = List.iter h_elem p in + !count + + +let string_of_histogram (h:histogram) : string = + String.concat "| " (List.mapi (fun i r -> Printf.sprintf "%s %d " (string_of_reg r) h.(i)) regs) + +(* Computes a "summary" of the histogram, which is just the count of registers used + except that %rbp counts negatively, since it is used for stack slot access. *) +let summary (h:histogram) : int = + (Array.fold_left (+) 0 h) - 2 * (h.(idx_of_reg Rbp)) + diff --git a/hw6/runtime.c b/hw6/runtime.c new file mode 100644 index 0000000..d1b32af --- /dev/null +++ b/hw6/runtime.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include + +/* Oat Internal Functions --------------------------------------------------- */ + +int64_t* oat_malloc(int64_t size) { + return (int64_t*)calloc(size, sizeof(char)); +} + +int64_t* oat_alloc_array (int64_t size) { + assert (size >= 0); + int64_t *arr = (int64_t*)malloc(sizeof(int64_t) * (size+1)); + arr[0] = size; + return arr; +} + +void oat_assert_not_null (int8_t* ptr) { + if (ptr == NULL) { + fprintf(stderr, "Attempted to dereference null pointer"); + exit(1); + } +} + +void oat_assert_array_length (int64_t *array, int64_t ind) { + if (array == NULL) { + fprintf(stderr, "Attempted to index null array"); + exit(1); + } else if ((ind < 0) || (*array <= ind)) { + fprintf(stderr, "Out of bounds index %ld for array length %ld", + (long)ind, (long)*array); + exit(1); + } +} + + +/* Oat Builtin Functions ---------------------------------------------------- */ + +int64_t* array_of_string (char *str) { + int64_t len, i, *arr; + + assert (NULL != str); + + len = strlen(str); + assert (len >= 0); + + arr = (int64_t*)malloc(sizeof(int64_t) * (len+1)); + arr[0] = len; + for (i=0; i= 0); + + str = malloc(sizeof(char) * (len+1)); + + for (i=0; i node -> NodeS.t + val succs : t -> node -> NodeS.t + val nodes : t -> NodeS.t + + (* the flow function: + given a graph node and input fact, compute the resulting fact on the + output edge of the node + *) + val flow : t -> node -> fact -> fact + + (* lookup / modify the dataflow annotations associated with a node *) + val out : t -> node -> fact + val add_fact : node -> fact -> t -> t + + (* printing *) + val to_string : t -> string + val printer : Format.formatter -> t -> unit + end + +(* abstract dataflow lattice signature -------------------------------------- *) +(* The general algorithm works over a generic lattice of abstract "facts". + - facts can be combined (this is the 'join' operation) + - facts can be compared *) +module type FACT = + sig + type t + val combine : t list -> t + val compare : t -> t -> int + val to_string : t -> string + end + + +(* generic iterative dataflow solver ---------------------------------------- *) +(* This functor takes two modules: + Fact - the implementation of the lattice + Graph - the dataflow anlaysis graph + + It produces a module that has a single function 'solve', which + implements the iterative dataflow analysis described in lecture. + - using a worklist (or workset) nodes + [initialized with the set of all nodes] + + - process the worklist until empty: + . choose a node from the worklist + . find the node's predecessors and combine their flow facts + . apply the flow function to the combined input to find the new + output + . if the output has changed, update the graph and add the node's + successors to the worklist + + TASK: complete the [solve] function, which implements the above algorithm. +*) +module Make (Fact : FACT) (Graph : DFA_GRAPH with type fact := Fact.t) = + struct + + let solve (g:Graph.t) : Graph.t = + failwith "TODO HW6: Solver.solve unimplemented" + end + diff --git a/hw6/tctxt.ml b/hw6/tctxt.ml new file mode 100644 index 0000000..6d373e6 --- /dev/null +++ b/hw6/tctxt.ml @@ -0,0 +1,72 @@ + +open Ast + +type fty = Ast.ty list * Ast.ret_ty + +(* typing contexts *) +type local_ctxt = (Ast.id * Ast.ty) list +type global_ctxt = (Ast.id * Ast.ty) list +type fun_ctxt = (Ast.id * fty) list +type struct_ctxt = (Ast.id * Ast.field list) list + +(* bundled together *) +type t = { + locals : local_ctxt; + globals : global_ctxt; + functions : fun_ctxt; + structs : struct_ctxt; +} + +let empty = { locals = []; globals = []; functions = []; structs = [] } + +(* locals ------------------------------------------------------------------- *) +let add_local (c:t) (id:id) (bnd : Ast.ty) : t = {c with locals = (id, bnd)::c.locals} +let lookup_local (id : Ast.id) (c : t) : Ast.ty = List.assoc id c.locals +let lookup_local_option id c : Ast.ty option = + try Some (List.assoc id c.locals) with Not_found -> None + +(* globals ------------------------------------------------------------------ *) +let add_global (c:t) (id:id) (bnd:Ast.ty) : t = {c with globals = (id, bnd)::c.globals} +let lookup_global (id : Ast.id) (c : t) : Ast.ty = List.assoc id c.globals +let lookup_global_option id c : Ast.ty option = + try Some (List.assoc id c.globals) with Not_found -> None + +(* functions ---------------------------------------------------------------- *) +let add_function (c:t) (id:id) (bnd : fty) : t = {c with functions = (id, bnd)::c.functions} +let lookup_function (id : Ast.id) (c : t) : fty = List.assoc id c.functions +let lookup_function_option id c : fty option = + try Some (List.assoc id c.functions) with Not_found -> None + + +(* general-purpose lookup: for local _or_ global: note function ids aren't considered *) +let lookup id c : Ast.ty = + match lookup_local_option id c with + | None -> lookup_global id c + | Some x -> x + +let lookup_option id c : Ast.ty option = + match lookup_local_option id c with + | None -> lookup_global_option id c + | Some x -> Some x + + +(* structures --------------------------------------------------------------- *) +let add_struct c id bnd = {c with structs=(id, bnd)::c.structs} +let lookup_struct id c = List.assoc id c.structs + +let lookup_struct_option id c = + try Some (lookup_struct id c) with Not_found -> None + +let lookup_field_option st_name f_name c = + let rec lookup_field_aux f_name l = + match l with + | [] -> None + | h :: t -> if h.fieldName = f_name then Some h.ftyp else lookup_field_aux f_name t in + match lookup_struct_option st_name c with + | None -> None + | Some x -> lookup_field_aux f_name x + +let lookup_field st_name f_name c = + match lookup_field_option st_name f_name c with + | None -> failwith "StructCtxt.lookup_field: Not found" + | Some x -> x diff --git a/hw6/team.txt b/hw6/team.txt new file mode 100644 index 0000000..e69de29 diff --git a/hw6/typechecker.ml b/hw6/typechecker.ml new file mode 100644 index 0000000..e1c70fa --- /dev/null +++ b/hw6/typechecker.ml @@ -0,0 +1,511 @@ +open Ast +open Astlib +open Tctxt + +(* Error Reporting ---------------------------------------------------------- *) +(* NOTE: Use type_error to report error messages for ill-typed programs. *) + +exception TypeError of string + +let type_error (l : 'a node) err = + let (_, (s, e), _) = l.loc in + raise (TypeError (Printf.sprintf "[%d, %d] %s" s e err)) + + +(* initial context: G0 ------------------------------------------------------ *) +(* The Oat types of the Oat built-in functions *) +let builtins = + [ "array_of_string", ([TRef RString], RetVal (TRef(RArray TInt))) + ; "string_of_array", ([TRef(RArray TInt)], RetVal (TRef RString)) + ; "length_of_string", ([TRef RString], RetVal TInt) + ; "string_of_int", ([TInt], RetVal (TRef RString)) + ; "string_cat", ([TRef RString; TRef RString], RetVal (TRef RString)) + ; "print_string", ([TRef RString], RetVoid) + ; "print_int", ([TInt], RetVoid) + ; "print_bool", ([TBool], RetVoid) + ] + +(* binary operation types --------------------------------------------------- *) +let typ_of_binop : Ast.binop -> Ast.ty * Ast.ty * Ast.ty = function + | Add | Mul | Sub | Shl | Shr | Sar | IAnd | IOr -> (TInt, TInt, TInt) + | Lt | Lte | Gt | Gte -> (TInt, TInt, TBool) + | And | Or -> (TBool, TBool, TBool) + | Eq | Neq -> failwith "typ_of_binop called on polymorphic == or !=" + +(* unary operation types ---------------------------------------------------- *) +let typ_of_unop : Ast.unop -> Ast.ty * Ast.ty = function + | Neg | Bitnot -> (TInt, TInt) + | Lognot -> (TBool, TBool) + +(* subtyping ---------------------------------------------------------------- *) +(* Decides whether H |- t1 <: t2 + - assumes that H contains the declarations of all the possible struct types + + - you will want to introduce addition (possibly mutually recursive) + helper functions to implement the different judgments of the subtyping + relation. We have included a template for subtype_ref to get you started. + (Don't forget about OCaml's 'and' keyword.) +*) +let rec subtype (c : Tctxt.t) (t1 : Ast.ty) (t2 : Ast.ty) : bool = + match t1, t2 with + | TInt, TInt -> true + | TBool, TBool -> true + | TNullRef x, TNullRef y + | TRef x, TNullRef y + | TRef x, TRef y -> subtype_ref c x y + | _, _ -> false + +(* Decides whether H |-r ref1 <: ref2 *) +and subtype_ref (c : Tctxt.t) (t1 : Ast.rty) (t2 : Ast.rty) : bool = + match t1, t2 with + | RString, RString -> true + | RArray at1, RArray at2 -> at1 = at2 + | RFun (ts1, rt1), RFun (ts2, rt2) -> subtype_list c ts2 ts1 && subtype_ret c rt1 rt2 + | RStruct id1, RStruct id2 -> id1 = id2 || subtype_fields c id1 id2 + | _, _ -> false + +and subtype_ret (c : Tctxt.t) (t1 : Ast.ret_ty) (t2 : Ast.ret_ty) : bool = + match t1, t2 with + | RetVoid, RetVoid -> true + | RetVal v1, RetVal v2 -> subtype c v1 v2 + | _, _ -> false + +and subtype_list c l1 l2 : bool = + if List.length l1 != List.length l2 then false + else List.fold_left2 (fun a x y -> a && subtype c x y) true l1 l2 + +(* fields n1 are a subtype of n2 if n2 is a prefix of n1 *) +and subtype_fields c n1 n2 : bool = + let fields1 = Tctxt.lookup_struct n1 c in + let fields2 = Tctxt.lookup_struct n2 c in + let rec helper l1 l2 = + match (l1, l2) with + | _, [] -> true + | [], _ -> false + | f1::t1, f2::t2 -> f1.fieldName = f2.fieldName && f1.ftyp = f2.ftyp + && helper t1 t2 in + helper fields1 fields2 + +(* well-formed types -------------------------------------------------------- *) +(* Implement a (set of) functions that check that types are well formed according + to the H |- t and related inference rules + + - the function should succeed by returning () if the type is well-formed + according to the rules + + - the function should fail using the "type_error" helper function if the + type is not well formed + + - l is just an ast node that provides source location information for + generating error messages (it's only needed for the type_error generation) + + - tc contains the structure definition context + *) +let rec typecheck_ty (l : 'a Ast.node) (tc : Tctxt.t) (t : Ast.ty) : unit = + begin match t with + | TBool -> () + | TInt -> () + | TNullRef r + | TRef r -> typecheck_ref l tc r + end + +and typecheck_ref l tc (r:Ast.rty) : unit = + begin match r with + | RString -> () + | RStruct id -> + if Tctxt.lookup_struct_option id tc = None + then type_error l "Unbound struct type" else () + + | RArray t -> typecheck_ty l tc t + | RFun (tl, rt) -> (typecheck_ret l tc rt); List.iter (typecheck_ty l tc) tl + end + +and typecheck_ret l tc (rt:Ast.ret_ty) : unit = + begin match (rt:Ast.ret_ty) with + | RetVoid -> () + | RetVal t -> typecheck_ty l tc t + end + +(* typechecking expressions ------------------------------------------------- *) +(* Typechecks an expression in the typing context c, returns the type of the + expression. This function should implement the inference rules given in the + oat.pdf specification. There, they are written: + + H; G; L |- exp : t + + See tctxt.ml for the implementation of the context c, which represents the + four typing contexts: H - for structure definitions G - for global + identifiers L - for local identifiers + + Returns the (most precise) type for the expression, if it is type correct + according to the inference rules. + + Uses the type_error function to indicate a (useful!) error message if the + expression is not type correct. The exact wording of the error message is + not important, but the fact that the error is raised, is important. (Our + tests also do not check the location information associated with the error.) + + Notes: - Structure values permit the programmer to write the fields in any + order (compared with the structure definition). This means that, given the + declaration struct T { a:int; b:int; c:int } The expression new T {b=3; c=4; + a=1} is well typed. (You should sort the fields to compare them.) + +*) +let rec typecheck_exp (c : Tctxt.t) (e : Ast.exp node) : Ast.ty = + match e.elt with + | CNull r -> TNullRef r + | CBool b -> TBool + | CInt i -> TInt + | CStr s -> TRef RString + | Id i -> + begin match Tctxt.lookup_option i c with + | Some x -> x + | None -> type_error e ("Unbound identifier " ^ i) + end + | CArr (t, l) -> + typecheck_ty e c t; + let types_of = List.map (typecheck_exp c) l in + if List.for_all (fun u -> subtype c u t) types_of then TRef (RArray t) + else type_error e "Mismatched array type" + + | NewArr(t, e1) -> + begin match t with + | TBool | TInt | TNullRef _ -> () + | TRef _ -> type_error e "Non-null types cannot be used with default-initialized arrays" + end; + let size_type = typecheck_exp c e1 in + if size_type = TInt then + TRef (RArray t) + else type_error e "Array size not an int" + + | NewArrInit (t, e1, id, e2) -> + typecheck_ty e c t; + let size_type = typecheck_exp c e1 in + if size_type = TInt then + let tc' = + if List.exists (fun x -> fst x = id) c.locals + then type_error e1 "Cannot redeclare variable" + else Tctxt.add_local c id TInt + in + let t' = typecheck_exp tc' e2 in + if subtype c t' t then TRef (RArray t) + else type_error e2 "Initializer has incorrect type" + else type_error e1 "Array size not an int" + | Bop (b, l, r) -> + let ltyp = typecheck_exp c l in + let rtyp = typecheck_exp c r in + begin match b with + | Eq | Neq -> if (subtype c ltyp rtyp) && (subtype c rtyp ltyp) then TBool else + type_error e "== or != used with non type-compatible arguments" + | _ -> + let (bl, br, bres) = typ_of_binop b in + if bl = ltyp then + if br = rtyp then bres + else type_error r "Incorrect type in binary expression" + else type_error l "Incorrect type in binary expression" + end + | Uop (u, e) -> + let t = typecheck_exp c e in + let (us, ures) = typ_of_unop u in + if us = t then ures else type_error e "Incorrect type for unary operator" + | Index (e1, e2) -> + let arr_t = typecheck_exp c e1 in + let ind_t = typecheck_exp c e2 in + if ind_t = TInt then + match arr_t with + | TRef (RArray t) -> t + | _ -> type_error e1 ("Tried to compute index into type " + ^ (Astlib.string_of_ty arr_t)) + else type_error e2 "Index of array index operator not an int" + | Proj (s, id) -> + let str_t = typecheck_exp c s in + (match str_t with + | TRef (RStruct sn) -> + (match Tctxt.lookup_field_option sn id c with + | None -> type_error e (id ^ " not member of struct " ^ sn) + | Some t -> t) + | _ -> type_error s "Cannot project from non-struct") + | CStruct (id, l) -> + (match Tctxt.lookup_struct_option id c with + | None -> type_error e (id ^ "not a struct type") + | Some x -> + let tc_field (id, node) = id, typecheck_exp c node in + let field_types = List.map tc_field l in + let struct_names = List.sort compare (List.map (fun x -> x.fieldName) x) in + let local_names = List.sort compare (List.map fst field_types) in + if struct_names <> local_names + then type_error e "Mismatch of fields between struct definition and local declaration"; + List.iter (fun (id, ft) -> + let t = (List.find (fun i -> i.fieldName = id) x).ftyp in + if not (subtype c ft t) then type_error e (id ^ " field of struct incorrect") + else ()) field_types; + TRef (RStruct id)) + | Length l -> + let t = typecheck_exp c l in + (match t with + | TRef (RArray t) -> TInt + | _ -> type_error l "Cannot take length of non-array") + | Call (f, args) -> + let argtyps = List.map (typecheck_exp c) args in + match (typecheck_exp c f) with + | TRef (RFun (l, RetVal r)) -> + if List.length l <> List.length argtyps + then type_error e "Incorrect number of arguments" + else List.iter2 + (fun arg l -> + if not (subtype c arg l) + then type_error e "Incorrect type of argument") + argtyps l; + r + | _ -> type_error e "Need function argument for function call" + +(* statements --------------------------------------------------------------- *) + +(* Typecheck a statement + This function should implement the statment typechecking rules from oat.pdf. + + Inputs: + - tc: the type context + - s: the statement node + - to_ret: the desired return type (from the function declaration) + + Returns: + - the new type context (which includes newly declared variables in scope + after this statement) + + - A boolean indicating the return behavior of a statement: + false: might not return + true: definitely returns + + in the branching statements, the return behavior of the branching + statement is the conjunction of the return behavior of the two + branches: both both branches must definitely return in order for + the whole statement to definitely return. + + Intuitively: if one of the two branches of a conditional does not + contain a return statement, then the entire conditional statement might + not return. + + looping constructs never definitely return + + Uses the type_error function to indicate a (useful!) error message if the + statement is not type correct. The exact wording of the error message is + not important, but the fact that the error is raised, is important. (Our + tests also do not check the location information associated with the error.) + + - You will probably find it convenient to add a helper function that implements the + block typecheck rules. +*) +let rec typecheck_stmt (tc : Tctxt.t) (s:Ast.stmt node) (to_ret:ret_ty) : Tctxt.t * bool = + match s.elt with + | Assn (e1, e2) -> + let () = begin match e1.elt with + | Id x -> + begin match Tctxt.lookup_local_option x tc with + | Some _ -> () + | None -> + begin match Tctxt.lookup_global_option x tc with + | Some TRef (RFun _) -> + type_error s ("cannot assign to global function " ^ x) + | _ -> () + end + end + | _ -> () + end + in + let assn_to = typecheck_exp tc e1 in + let assn_from = typecheck_exp tc e2 in + if subtype tc assn_from assn_to + then tc, false + else type_error s "Mismatched types in assignment" + + | Decl (id, exp) -> + let exp_type = typecheck_exp tc exp in + if List.exists (fun x -> fst x = id) tc.locals + then type_error s "Cannot redeclare variable" + else Tctxt.add_local tc id exp_type, false + + | Ret r -> + (match r, to_ret with + | None, RetVoid -> tc, true + | Some r, RetVal to_ret -> + let t = typecheck_exp tc r in + if subtype tc t to_ret then tc, true + else type_error s "Returned incorrect type" + | None, RetVal to_ret -> type_error s "Returned void in non-void function" + | Some r, RetVoid -> type_error s "Returned non-void in void function") + + | SCall (f, args) -> + let argtyps = List.map (typecheck_exp tc) args in + (match (typecheck_exp tc f) with + | TNullRef (RFun (l, RetVoid)) | TRef (RFun (l, RetVoid)) -> + if List.length l <> List.length argtyps + then type_error s "Incorrect number of arguments" + else List.iter2 + (fun arg l -> if not (subtype tc arg l) + then type_error s "Incorrect type of argument") + argtyps l; + tc, false + | _ -> type_error s "Need function argument for function call") + + | If (e, b1, b2) -> + let guard_type = typecheck_exp tc e in + if guard_type <> TBool then type_error e "Incorrect type for guard" + else + let lft_ret = typecheck_block tc b1 to_ret in + let rgt_ret = typecheck_block tc b2 to_ret in + tc, lft_ret && rgt_ret + + | Cast (r, id, exp, b1, b2) -> + let exp_type = typecheck_exp tc exp in + begin match exp_type with + | TNullRef r' -> + if subtype_ref tc r' r then + let lft_ret = typecheck_block (Tctxt.add_local tc id (TRef r)) b1 to_ret in + let rgt_ret = typecheck_block tc b2 to_ret in + tc, lft_ret && rgt_ret + else + type_error exp "if? expression not a subtype of declared type" + | _ -> type_error exp "if? expression has non-? type" + end + | While (b, bl) -> + let guard_type = typecheck_exp tc b in + if guard_type <> TBool then type_error b "Incorrect type for guard" + else + let _ = typecheck_block tc bl to_ret in + tc, false + + | For (vs, guard, s, b) -> + let updated_context = + List.fold_left (fun c (id, e) -> + let t = typecheck_exp c e in + Tctxt.add_local c id t) tc vs in + let _ = + begin match guard with + | None -> () + | Some b -> + if TBool <> typecheck_exp updated_context b + then type_error b "Incorrect type for guard" + else () + end in + let _ = + begin match s with + | None -> () + | Some s -> + let (nc, rt) = typecheck_stmt updated_context s to_ret in + if rt then type_error s "Cannot return in for loop increment" + end in + let _ = typecheck_block updated_context b to_ret in + tc, false + +and typecheck_block (tc : Tctxt.t) (b : Ast.block) (to_ret : Ast.ret_ty) : bool = + match b with + | [] -> false + | [h] -> + let c, r = typecheck_stmt tc h to_ret in r + | h1 :: h2 :: t -> + let new_context, r = typecheck_stmt tc h1 to_ret in + if r then type_error h2 "Dead code" + else typecheck_block new_context (h2 :: t) to_ret + +(* struct type declarations ------------------------------------------------- *) +(* Here is an example of how to implement the TYP_TDECLOK rule, which is + is needed elswhere in the type system. + *) + +(* Helper function to look for duplicate field names *) +let rec check_dups fs = + match fs with + | [] -> false + | h :: t -> (List.exists (fun x -> x.fieldName = h.fieldName) t) || check_dups t + +let typecheck_tdecl (tc : Tctxt.t) id fs (l : 'a Ast.node) : unit = + if check_dups fs + then type_error l ("Repeated fields in " ^ id) + else List.iter (fun f -> typecheck_ty l tc f.ftyp) fs + +(* function declarations ---------------------------------------------------- *) +(* typecheck a function declaration + - extends the local context with the types of the formal parameters to the + function + - typechecks the body of the function (passing in the expected return type + - checks that the function actually returns +*) +let typecheck_fdecl (tc : Tctxt.t) (f : Ast.fdecl) (l : 'a Ast.node) : unit = + let updated = List.fold_left (fun c (t, i) -> Tctxt.add_local c i t) tc f.args in + let returned = typecheck_block updated f.body f.frtyp in + if not returned then type_error l "Need return statement" + +(* creating the typchecking context ----------------------------------------- *) + +(* The following functions correspond to the + judgments that create the global typechecking context. + + create_struct_ctxt: - adds all the struct types to the struct 'S' + context (checking to see that there are no duplicate fields + + H |-s prog ==> H' + + + create_function_ctxt: - adds the the function identifiers and their + types to the 'G' context (ensuring that there are no redeclared + function identifiers) + + H ; G1 |-f prog ==> G2 + + + create_global_ctxt: - typechecks the global initializers and adds + their identifiers to the 'G' global context + + H ; G1 |-g prog ==> G2 + + + NOTE: global initializers may mention function identifiers as + constants, but can mention only other global values that were declared earlier +*) + +let create_struct_ctxt (p:Ast.prog) : Tctxt.t = + List.fold_left (fun c d -> + match d with + | Gtdecl ({elt=(id, fs)} as l) -> + if List.exists (fun x -> id = fst x) c.structs then + type_error l ("Redeclaration of struct " ^ id) + else Tctxt.add_struct c id fs + | _ -> c) Tctxt.empty p + +let create_function_ctxt (tc:Tctxt.t) (p:Ast.prog) : Tctxt.t = + let builtins_context = + List.fold_left + (fun c (id, (args, ret)) -> Tctxt.add_global c id (TRef (RFun(args,ret)))) + tc builtins + in + List.fold_left (fun c d -> + match d with + | Gfdecl ({elt=f} as l) -> + if List.exists (fun x -> fst x = f.fname) c.globals + then type_error l ("Redeclaration of " ^ f.fname) + else Tctxt.add_global c f.fname (TRef (RFun(List.map fst f.args, f.frtyp))) + | _ -> c) builtins_context p + +let create_global_ctxt (tc:Tctxt.t) (p:Ast.prog) : Tctxt.t = + List.fold_left (fun c d -> + match d with + | Gvdecl ({elt=decl} as l) -> + let e = typecheck_exp c decl.init in + if List.exists (fun x -> fst x = decl.name) c.globals + then type_error l ("Redeclaration of " ^ decl.name) + else Tctxt.add_global c decl.name e + | _ -> c) tc p + +(* This function implements the |- prog and the H ; G |- prog + rules of the oat.pdf specification. +*) +let typecheck_program (p:Ast.prog) : unit = + let sc = create_struct_ctxt p in + let fc = create_function_ctxt sc p in + let tc = create_global_ctxt fc p in + List.iter (fun p -> + match p with + | Gfdecl ({elt=f} as l) -> typecheck_fdecl tc f l + | Gtdecl ({elt=(id, fs)} as l) -> typecheck_tdecl tc id fs l + | _ -> ()) p diff --git a/hw6/util/assert.ml b/hw6/util/assert.ml new file mode 100644 index 0000000..6789b43 --- /dev/null +++ b/hw6/util/assert.ml @@ -0,0 +1,160 @@ +(* This code is mostly based on a course held at *) +(* University of Pennsylvania (CIS341) by Steve Zdancewic. *) + +(* Author: Steve Zdancewic *) +(* Modified by: Manuel Rigger *) +(* Modified by: Yann Girsberger *) + +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + + + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = (unit -> unit) + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = (assertion test) list + + +(**************) +(* Assertions *) +exception Timeout + +let timeout_assert (time : int) (a : assertion) : assertion = + fun () -> + let handler = Sys.Signal_handle (fun _ -> raise Timeout) in + let old = Sys.signal Sys.sigalrm handler in + let reset_sigalrm () = Sys.set_signal Sys.sigalrm old in + ignore (Unix.alarm time); + try begin a (); reset_sigalrm () end + with Timeout -> reset_sigalrm (); failwith @@ Printf.sprintf "Timed out after %d seconds" time + | exc -> reset_sigalrm (); raise exc + +let timeout_test (time : int) (t : assertion test) : assertion test = + let map_timeout l = List.map (fun (i, a) -> (i, timeout_assert time a)) l in + match t with + | GradedTest (s, i, ls) -> GradedTest (s, i, map_timeout ls) + | Test (s, ls) -> Test (s, map_timeout ls) + +let timeout_suite (time : int) (s : suite) : suite = + List.map (timeout_test time) s + +let timeout_assert_const (a: assertion) : assertion = + timeout_assert 10 a + +let assert_eq v1 v2 : assertion = + timeout_assert_const (fun () -> if v1 <> v2 then failwith "not equal" else ()) + +let assert_eqf f v2 : assertion = + timeout_assert_const (fun () -> if (f ()) <> v2 then failwith "not equal" else ()) + +let assert_eqfs f v2 : assertion = + timeout_assert_const (fun () -> + let s1 = f () in + if s1 <> v2 then failwith @@ Printf.sprintf "not equal\n\texpected:%s\n\tgot:%s\n" v2 s1 + else ()) + + +let assert_fail : assertion = fun () -> failwith "assert fail" + + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = (result test) list + +let run_assertion (f:assertion) : result = + try + f (); + Pass + with + | Failure m -> Fail m + | e -> Fail ("test threw exception: " ^ (Printexc.to_string e)) + +let run_test (t:assertion test) : result test = + let run_case (cn, f) = (cn, run_assertion f) in + begin match t with + | GradedTest (n,s,cases) -> + Printf.eprintf "Running test %s\n%!" n; + GradedTest(n,s,List.map run_case cases) + + | Test (n, cases) -> + Printf.eprintf "Running test %s\n%!" n; + Test(n, List.map run_case cases) + end + +let run_suite (s:suite):outcome = + List.map run_test s + + + + + +(***********************) +(* Reporting functions *) + +let result_test_to_string (name_pts:string) (r:result test): string = + let string_of_case (name, res) = + begin match res with + | Pass -> "passed - " ^ name + | Fail msg -> "FAILED - " ^ name ^ ": " ^ msg + end + in + begin match r with + | GradedTest (_, _, cases) + | Test (_, cases) -> + name_pts ^ + (List.fold_left (fun rest -> fun case -> rest ^ "\n" ^ (string_of_case case)) "" cases) + end + +(* returns (name_pts, passed, failed, total, points_earned, max_given, max_hidden) *) +let get_results (t:result test) = + let num_passed cases = + List.fold_left (fun cnt (_,r) -> match r with Pass -> cnt + 1 | _ -> cnt) 0 cases in + let num_failed cases = + List.fold_left (fun cnt (_,r) -> match r with Fail _ -> cnt + 1 | _ -> cnt) 0 cases in + begin match t with + | GradedTest (name,pts,cases) -> + let passed = num_passed cases in + let failed = num_failed cases in + let total = List.length cases in + if total > 0 then + let points_earned = ((float_of_int passed) /. (float_of_int total)) *. (float_of_int pts) in + let name_pts = Printf.sprintf "%s (%1.f/%d points)" name points_earned pts in + (name_pts, passed, failed, total, points_earned, pts, 0) + else + let name_pts = Printf.sprintf "%s (?/%d points)" name pts in + (name_pts, passed, failed, total, 0.0, 0, pts) + | Test(name, cases) -> + let total = List.length cases in + let passed = num_passed cases in + let failed = num_failed cases in + (name, passed, failed, total, 0.0, 0, 0) + end + +let outcome_to_string (o:outcome):string = + let sep = "\n---------------------------------------------------\n" in + let helper (passed, failed, total, pts, maxg, maxh, str) (t:result test) = + let (name_pts, p, f, tot, s, mg, mh) = get_results t in + (passed + p, failed + f, total + tot, s +. pts, maxg + mg, maxh + mh, + str ^ "\n" ^ ( + if f > 0 then (result_test_to_string name_pts t) else + if tot > 0 then (name_pts ^ ":\n OK") else + (name_pts ^ ":\n Hidden") + ) + ) in + let (p,f,tot,pts,maxg, maxh,str) = List.fold_left helper (0,0,0,0.0,0,0,"") o in + str ^ sep ^ (Printf.sprintf "Passed: %d/%d\nFailed: %d/%d\nScore: %1.f/%d (given)\n ?/%d (hidden)" p tot f tot pts maxg maxh) + + + + diff --git a/hw6/util/assert.mli b/hw6/util/assert.mli new file mode 100644 index 0000000..21337ae --- /dev/null +++ b/hw6/util/assert.mli @@ -0,0 +1,48 @@ +(* Do NOT modify this file -- we will overwrite it *) +(* with our own version when testing your code. *) + +exception Timeout + +(* An assertion is just a unit->unit function that either *) +(* succeeds silently or throws an Failure exception. *) +type assertion = (unit -> unit) + +type 'a test = + | GradedTest of string * int * (string * 'a) list + | Test of string * (string * 'a) list + +type suite = (assertion test) list + + +(**************) +(* Assertions *) + +val assert_eq : 'a -> 'a -> assertion +val assert_eqf : (unit -> 'a) -> 'a -> assertion +val assert_eqfs : (unit -> string) -> string -> assertion +val assert_fail : assertion + +val timeout_assert : int -> assertion -> assertion +val timeout_test : int -> assertion test -> assertion test +val timeout_suite : int -> suite -> suite + +(***************************) +(* Generating Test Results *) + +type result = + | Pass + | Fail of string + +type outcome = (result test) list + +val run_assertion : assertion -> result +val run_test : assertion test -> result test +val run_suite : suite -> outcome + +(***********************) +(* Reporting functions *) + +val result_test_to_string : string -> result test -> string + +(* val get_results result test -> (string * int * int * int * float * int * int) *) +val outcome_to_string :outcome -> string diff --git a/hw6/util/platform.ml b/hw6/util/platform.ml new file mode 100644 index 0000000..59d1774 --- /dev/null +++ b/hw6/util/platform.ml @@ -0,0 +1,156 @@ +(* -------------------------------------------------------------------------- *) +(** Assembling and linking for X86. Depends on the underlying OS platform *) + + +open Printf +open Unix + +exception PlatformError of string * string + + +(* paths -------------------------------------------------------------------- *) +let path_sep = "/" +let dot_path = "./" +let output_path = ref "output" +let libs = ref [] +let lib_paths = ref [] +let lib_search_paths = ref [] +let include_paths = ref [] +let executable_name = ref "a.out" + +(* unix utility scripts ----------------------------------------------------- *) +let pp_cmd = ref "cpp -E " +let rm_cmd = ref "rm -rf " + + +(* -------------------------------------------------------------------------- *) +(* Platform specific configuration: Unix/Linux vs. Mac OS X *) + +let os = + let ic = Unix.open_process_in "uname -s" in + let uname = input_line ic in + let () = close_in ic in + uname (* One of "Darwin" or "Linux" *) + + +let linux = ref false +let mangle name = if !linux then name else ("_" ^ name) + +let osx_target_triple = "x86_64-apple-macosx10.13.0" +let linux_target_triple = "x86_64-unknown-linux" +let target_triple = ref osx_target_triple +let platform_flags = ref "" + + +(* Set the link commands properly, ensure output directory exists *) +let configure_os () = + if os = "Linux" then + begin + linux := true; + target_triple := linux_target_triple; + platform_flags := "-mstackrealign -Wno-unused-command-line-argument" + end + else + if os = "Darwin" then + begin + linux := false; + target_triple := osx_target_triple; + platform_flags := "-fno-asynchronous-unwind-tables -mstackrealign" + end + else + failwith @@ "Unsupported OS detected: " ^ os + +(* verbose compiler output -------------------------------------------------- *) +let verbose = ref false +let verb msg = (if !verbose then (print_string msg; flush Pervasives.stdout)) + +let verb_os () = + verb @@ Printf.sprintf "* PLATFORM: %s TRIPLE: %s FLAGS %s\n" + os !target_triple !platform_flags + +let enable_verbose () = + verbose := true; + verb_os () + +(* create the output directory, which is assumed to exist *) +let create_output_dir () = + try ignore (stat !output_path) + with Unix_error (ENOENT,_,_) -> + (verb @@ Printf.sprintf "creating output directory: %s\n" !output_path); + mkdir !output_path 0o755 + + +(* clang invocation stuff --------------------------------------------------- *) +let common_flags = "-Wno-override-module" +let clang_ll_mode = "-S" +let as_mode = "-c" +let opt_level = ref "-O1 -Wall" +let clang args = + Printf.sprintf "clang %s -o " (String.concat " " args) + +let clang_cmd () = clang [clang_ll_mode; !opt_level; common_flags; !platform_flags] +let as_cmd () = clang [as_mode; !opt_level; common_flags; !platform_flags] +let link_cmd () = clang [common_flags; !opt_level; !platform_flags] + + +(* filename munging --------------------------------------------------------- *) +let path_to_basename_ext (path:string) : string * string = + (* The path is of the form ... "foo/bar/baz/.ext" *) + let paths = Str.split (Str.regexp_string path_sep) path in + let _ = if (List.length paths) = 0 then failwith @@ sprintf "bad path: %s" path in + let filename = List.hd (List.rev paths) in + match Str.split (Str.regexp_string ".") filename with + | [root] -> root, "" + | [root; ext] -> root, ext + | _ -> failwith @@ sprintf "bad filename: %s" filename + + +(* compilation and shell commands-------------------------------------------- *) + +(* Platform independent shell command *) +let sh (cmd:string) (ret:string -> int -> 'a) : 'a = + verb (sprintf "* %s\n" cmd); + match (system cmd) with + | WEXITED i -> ret cmd i + | WSIGNALED i -> raise (PlatformError (cmd, sprintf "Signaled with %d." i)) + | WSTOPPED i -> raise (PlatformError (cmd, sprintf "Stopped with %d." i)) + +(* Generate a file name that does not already exist. + basedir includes the path separator +*) +let gen_name (basedir:string) (basen:string) (baseext:string) : string = + let rec nocollide ofs = + let nfn = sprintf "%s/%s%s%s" basedir basen + (if ofs = 0 then "" else "_"^(string_of_int ofs)) baseext + in + try ignore (stat nfn); nocollide (ofs + 1) + with Unix_error (ENOENT,_,_) -> nfn + in nocollide 0 + + +let raise_error cmd i = + if i <> 0 then raise (PlatformError (cmd, sprintf "Exited with status %d." i)) + +let ignore_error _ _ = () + +let preprocess (dot_oat:string) (dot_i:string) : unit = + sh (sprintf "%s%s %s %s" !pp_cmd + (List.fold_left (fun s -> fun i -> s ^ " -I" ^ i) "" !include_paths) + dot_oat dot_i) raise_error + +let clang_compile (dot_ll:string) (dot_s:string) : unit = + sh (sprintf "%s%s %s" (clang_cmd ()) dot_s dot_ll) raise_error + +let assemble (dot_s:string) (dot_o:string) : unit = + sh (sprintf "%s%s %s" (as_cmd ()) dot_o dot_s) raise_error + +let link (mods:string list) (out_fn:string) : unit = + sh (sprintf "%s%s %s %s %s %s" (link_cmd ()) out_fn + (String.concat " " (mods @ !lib_paths)) + (List.fold_left (fun s -> fun i -> s ^ " -L" ^ i) "" !lib_search_paths) + (List.fold_left (fun s -> fun i -> s ^ " -I" ^ i) "" !include_paths) + (List.fold_left (fun s -> fun l -> s ^ " -l" ^ l) "" !libs)) + raise_error + + + diff --git a/hw6/util/range.ml b/hw6/util/range.ml new file mode 100644 index 0000000..03901c4 --- /dev/null +++ b/hw6/util/range.ml @@ -0,0 +1,41 @@ +open Lexing + +type pos = int * int (* Line number and column *) +type t = string * pos * pos + +let line_of_pos (l,_) = l +let col_of_pos (_,c) = c +let mk_pos line col = (line, col) + +let file_of_range (f,_,_) = f +let start_of_range (_,s,_) = s +let end_of_range (_,_,e) = e +let mk_range f s e = (f,s,e) +let valid_pos (l,c) = l >= 0 && c >=0 + +let merge_range ((f,s1,e1) as r1) ((f',s2,e2) as r2) = + if f <> f' then failwith @@ Printf.sprintf "merge_range called on different files: %s and %s" f f' + else + if not (valid_pos s1) then r2 else + if not (valid_pos s2) then r1 else + mk_range f (min s1 s2) (max e1 e2) + +let string_of_range (f,(sl,sc),(el,ec)) = + Printf.sprintf "%s:[%d.%d-%d.%d]" f sl sc el ec + +let ml_string_of_range (f,(sl,sc),(el,ec)) = + Printf.sprintf "(\"%s\", (%d, %d), (%d, %d))" f sl sc el ec + +let norange = ("__internal", (0,0), (0,0)) + +(* Creates a Range.pos from the Lexing.position data *) +let pos_of_lexpos (p:position) : pos = + mk_pos (p.pos_lnum) (p.pos_cnum - p.pos_bol) + +let mk_lex_range (p1:position) (p2:position) : t = + mk_range p1.pos_fname (pos_of_lexpos p1) (pos_of_lexpos p2) + +(* Expose the lexer state as a Range.t value *) +let lex_range lexbuf : t = + mk_lex_range (lexeme_start_p lexbuf) (lexeme_end_p lexbuf) + diff --git a/hw6/util/range.mli b/hw6/util/range.mli new file mode 100644 index 0000000..c14f54f --- /dev/null +++ b/hw6/util/range.mli @@ -0,0 +1,53 @@ +(* Ranges and utilities on ranges. *) + +(* A range represents a segment of text in a given file; it has a + * beginning and ending position specified in terms of line and column + * numbers. A range is associated with tokens during lexing to allow + * the compiler to give better error messages during lexing and + * parsing. + *) + +(* a position in the source file; line number and column *) +type pos = int * int + +(* a range of positions in a particular file *) +type t = string * pos * pos + +(* line of position *) +val line_of_pos : pos -> int + +(* column of position *) +val col_of_pos : pos -> int + +(* new position with given line and col *) +val mk_pos : int -> int -> pos + +(* the filename a range is in *) +val file_of_range : t -> string + +(* the beginning of the range *) +val start_of_range : t -> pos + +(* the end of the range *) +val end_of_range : t -> pos + +(* create a new range from the given filename and start, end positions *) +val mk_range : string -> pos -> pos -> t + +(* merge two ranges together *) +val merge_range : t -> t -> t + +(* pretty-print a range *) +val string_of_range : t -> string + +(* print a range as an ocaml value *) +val ml_string_of_range : t -> string + +(* use to tag generated AST nodes where range does not apply *) +val norange : t + +val pos_of_lexpos : Lexing.position -> pos + +val mk_lex_range : Lexing.position -> Lexing.position -> t + +val lex_range : Lexing.lexbuf -> t diff --git a/hw6/x86/testX86.ml b/hw6/x86/testX86.ml new file mode 100644 index 0000000..1b23983 --- /dev/null +++ b/hw6/x86/testX86.ml @@ -0,0 +1,34 @@ +open X86 +open Cunit + +let hello_label = mk_lbl_named "hellostr" +let puts_label = mk_lbl_named "_puts" (* gcc on linux/mac uses _ to munge names *) + +let main_seq = [ + Push (esp); + Mov (ebp, esp); + + Add (esp, Imm (-8l)); (* Not sure why this has to be 8 *) + Mov (stack_offset 0l, Lbl hello_label); + Call (Lbl puts_label); + + Mov (esp, ebp); + Pop (ebp); + Ret +] + +let main_bb = { + (mk_insn_block (mk_lbl_named "_main") main_seq) with + global = true +} + +let hello_data = { + link = false; + label = (mk_lbl_named "hellostr"); + value = GStringz "Hello, world!" +} + +let cu = [Data hello_data; Code main_bb] + +let _ = + print_endline (string_of_cunit cu) diff --git a/hw6/x86/x86.ml b/hw6/x86/x86.ml new file mode 100644 index 0000000..802ee18 --- /dev/null +++ b/hw6/x86/x86.ml @@ -0,0 +1,165 @@ +(* X86lite language representation. *) + +(* assembler syntax --------------------------------------------------------- *) + +(* Labels for code blocks and global data. *) +type lbl = string + +type quad = int64 + +(* Immediate operands *) +type imm = Lit of quad + | Lbl of lbl + +(* Registers: + instruction pointer: rip + arguments: rdi, rsi, rdx, rcx, r09, r08 + callee-save: rbx, rbp, r12-r15 +*) +type reg = Rip + | Rax | Rbx | Rcx | Rdx | Rsi | Rdi | Rbp | Rsp + | R08 | R09 | R10 | R11 | R12 | R13 | R14 | R15 + +type operand = Imm of imm (* immediate *) + | Reg of reg (* register *) + | Ind1 of imm (* indirect: displacement *) + | Ind2 of reg (* indirect: (%reg) *) + | Ind3 of (imm * reg) (* indirect: displacement(%reg) *) + +(* Condition Codes *) +type cnd = Eq | Neq | Gt | Ge | Lt | Le + +type opcode = Movq | Pushq | Popq + | Leaq + | Incq | Decq | Negq | Notq + | Addq | Subq | Imulq | Xorq | Orq | Andq + | Shlq | Sarq | Shrq + | Jmp | J of cnd + | Cmpq | Set of cnd + | Callq | Retq + +(* An instruction is an opcode plus its operands. + Note that arity and other constraints about the operands + are not checked. *) +type ins = opcode * operand list + +type data = Asciz of string + | Quad of imm + +type asm = Text of ins list (* code *) + | Data of data list (* data *) + +(* labeled blocks of data or code *) +type elem = { lbl: lbl; global: bool; asm: asm } + +type prog = elem list + +(* Provide some syntactic sugar for writing x86 code in OCaml files. *) +module Asm = struct + let (~$) i = Imm (Lit (Int64.of_int i)) (* int64 constants *) + let (~$$) l = Imm (Lbl l) (* label constants *) + let (~%) r = Reg r (* registers *) + + (* helper functions for building blocks of data or code *) + let data l ds = { lbl = l; global = true; asm = Data ds } + let text l is = { lbl = l; global = false; asm = Text is } + let gtext l is = { lbl = l; global = true; asm = Text is } +end + +(* pretty printing ----------------------------------------------------------- *) + +let string_of_reg : reg -> string = function + | Rip -> "%rip" + | Rax -> "%rax" | Rbx -> "%rbx" | Rcx -> "%rcx" | Rdx -> "%rdx" + | Rsi -> "%rsi" | Rdi -> "%rdi" | Rbp -> "%rbp" | Rsp -> "%rsp" + | R08 -> "%r8 " | R09 -> "%r9 " | R10 -> "%r10" | R11 -> "%r11" + | R12 -> "%r12" | R13 -> "%r13" | R14 -> "%r14" | R15 -> "%r15" + +let string_of_byte_reg : reg -> string = function + | Rip -> failwith "%rip used as byte register" + | Rax -> "%al" | Rbx -> "%bl" | Rcx -> "%cl" | Rdx -> "%dl" + | Rsi -> "%sil" | Rdi -> "%dil" | Rbp -> "%bpl" | Rsp -> "%spl" + | R08 -> "%r8b" | R09 -> "%r9b" | R10 -> "%r10b" | R11 -> "%r11b" + | R12 -> "%r12b" | R13 -> "%r13b" | R14 -> "%r14b" | R15 -> "%r15b" + +let string_of_lbl (l:lbl) : string = l + +let string_of_imm : imm -> string = function + | Lit i -> Int64.to_string i + | Lbl l -> string_of_lbl l + +let string_of_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_byte_operand : operand -> string = function + | Imm i -> "$" ^ string_of_imm i + | Reg r -> string_of_byte_reg r + | Ind1 i -> string_of_imm i + | Ind2 r -> "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_jmp_operand : operand -> string = function + | Imm i -> string_of_imm i + | Reg r -> "*" ^ string_of_reg r + | Ind1 i -> "*" ^ string_of_imm i + | Ind2 r -> "*" ^ "(" ^ string_of_reg r ^ ")" + | Ind3 (i, r) -> "*" ^ string_of_imm i ^ "(" ^ string_of_reg r ^ ")" + +let string_of_cnd : cnd -> string = function + | Eq -> "e" | Neq -> "ne" | Gt -> "g" + | Ge -> "ge" | Lt -> "l" | Le -> "le" + +let string_of_opcode : opcode -> string = function + | Movq -> "movq" | Pushq -> "pushq" | Popq -> "popq" + | Leaq -> "leaq" + | Incq -> "incq" | Decq -> "decq" | Negq -> "negq" | Notq -> "notq" + | Addq -> "addq" | Subq -> "subq" | Imulq -> "imulq" + | Xorq -> "xorq" | Orq -> "orq" | Andq -> "andq" + | Shlq -> "shlq" | Sarq -> "sarq" | Shrq -> "shrq" + | Jmp -> "jmp" | J c -> "j" ^ string_of_cnd c + | Cmpq -> "cmpq" | Set c -> "set" ^ string_of_cnd c + | Callq -> "callq" | Retq -> "retq" + +let map_concat s f l = String.concat s @@ List.map f l + +let string_of_shift op = function + | [ Imm i ; dst ] as args -> + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " string_of_operand args + | [ Reg Rcx ; dst ] -> + Printf.sprintf "\t%s\t%%cl, %s" (string_of_opcode op) (string_of_operand dst) + | args -> failwith (Printf.sprintf "shift instruction has invalid operands: %s\n" + (map_concat ", " string_of_operand args)) + +let string_of_ins (op, args: ins) : string = + match op with + | Shlq | Sarq | Shrq -> string_of_shift op args + | _ -> + let f = match op with + | J _ | Jmp | Callq -> string_of_jmp_operand + | Set _ -> string_of_byte_operand + | _ -> string_of_operand + in + "\t" ^ string_of_opcode op ^ "\t" ^ map_concat ", " f args + +let string_of_data : data -> string = function + | Asciz s -> "\t.asciz\t" ^ "\"" ^ (String.escaped s) ^ "\"" + | Quad i -> "\t.quad\t" ^ string_of_imm i + +let string_of_asm : asm -> string = function + | Text is -> "\t.text\n" ^ map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n" ^ map_concat "\n" string_of_data ds + +let string_of_elem {lbl; global; asm} : string = + let sec, body = match asm with + | Text is -> "\t.text\n", map_concat "\n" string_of_ins is + | Data ds -> "\t.data\n", map_concat "\n" string_of_data ds + in + let glb = if global then "\t.globl\t" ^ string_of_lbl lbl ^ "\n" else "" in + sec ^ glb ^ string_of_lbl lbl ^ ":\n" ^ body + +let string_of_prog (p:prog) : string = + String.concat "\n" @@ List.map string_of_elem p