├── .gitignore ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── examples ├── lambda_example ├── list_example ├── run_tests.py ├── runtime.c ├── src ├── anf.rs ├── ast.rs ├── emit.rs ├── lexer.rs ├── main.rs ├── parser.rs ├── util.rs └── x86.rs └── tests ├── add.input ├── add.output ├── add2.input ├── add2.output ├── fibo.input ├── fibo.output ├── func.input ├── func.output ├── if.input ├── if.output ├── lambda.input ├── lambda.output ├── neg.input ├── neg.output ├── tuple1.input └── tuple1.output /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - nightly 4 | 5 | addons: 6 | apt: 7 | sources: 8 | - deadsnakes 9 | packages: 10 | - python3.5 11 | - nasm 12 | 13 | script: python3.5 run_tests.py 14 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "log" 5 | version = "0.3.7" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "rusl" 10 | version = "0.1.0" 11 | dependencies = [ 12 | "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 13 | ] 14 | 15 | [metadata] 16 | "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusl" 3 | version = "0.1.0" 4 | authors = ["Samrat Man Singh "] 5 | 6 | [dependencies] 7 | log = "0.3.7" 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Samrat Man Singh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRC=examples 2 | 3 | test: runtime.o 4 | cargo run $(SRC) > test.s 5 | nasm -f elf64 test.s 6 | gcc -o a.out runtime.o test.o 7 | 8 | runtime.o: runtime.c 9 | gcc -c -g -std=c99 runtime.c 10 | 11 | test_suite: 12 | python run_tests.py 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rusl 2 | 3 | [![Build Status](https://travis-ci.org/samrat/rusl.svg?branch=master)](https://travis-ci.org/samrat/rusl) 4 | 5 | A minimal Lisp that compiles to x86-64. 6 | 7 | ```scheme 8 | (define (fibo x) 9 | (if (< x 2) 10 | 1 11 | (+ (fibo (+ x (- 2))) 12 | (fibo (+ x (- 1)))))) 13 | 14 | (fibo 6) 15 | ``` 16 | 17 | ## Trying out rusl 18 | 19 | You need to have `Cargo`, `gcc` and `nasm` installed. Currently, 20 | `rusl` requires the nightly version of Rust. 21 | 22 | ```shell 23 | make test SRC=list_example && ./a.out 24 | ``` 25 | 26 | OR 27 | 28 | ```shell 29 | cargo run foo.txt > test.s 30 | nasm -f elf64 test.s 31 | gcc -c -g -std=c99 runtime.c 32 | gcc -g runtime.o test.o 33 | ./a.out 34 | ``` 35 | 36 | ## Compiler organization 37 | 38 | The compiler is organized as a series of passes. Each pass is a 39 | function. 40 | 41 | ### Compiler pipeline for a single function: 42 | 43 | A string is parsed into an SExpr(`parser::read`). The variables in 44 | the SExpr is then uniquified(`uniquify`). Then, lambdas are 45 | de-sugared into tuples(`convert_to_closures`). We then convert 46 | SExpr into Flat-- the difference being that subexpressions are 47 | lifted up into let-bindings. We then convert to a form we will 48 | call pseudo-X86; this is a three-address code but uses variables 49 | and supports if-conditionals so isn't quite X86. `uncover-live` 50 | performs liveness analysis, and `assign_homes` does 51 | register-allocation with spilling to stack where appropriate(we 52 | use linear-scan register allocation). 53 | 54 | Next, we lower if-conditionals to jumps(`lower_conditionals`). We are 55 | very close to a representation of X86 now, but there will be some 56 | instructions which are not valid X86 such as `mov [rbp-16], 57 | [rbp-32]`. `patch_instructions` will fix those up (in the case of the 58 | last example, by using a register as an intermediate buffer). 59 | 60 | ## Data representation in memory 61 | 62 | - If LSB == 0 => ```integer``` 63 | - If LSB == 1 => 64 | - If (bit 1) == 1 => ```boolean``` 65 | - If (bit 1) == 0 => ```tuple``` 66 | 67 | 68 | - The first word in a tuple is the number of elements contained. 69 | - Because the last two bits in a tuple are tag bits, a tuple must 70 | always be located in an address ending with 0b00. This means that if 71 | the no. of elements in the tuple would have resulted in an odd 72 | number of words, we add padding to the tuple storage space. 73 | -------------------------------------------------------------------------------- /examples: -------------------------------------------------------------------------------- 1 | (if (> 4 3) 12 42) 2 | -------------------------------------------------------------------------------- /lambda_example: -------------------------------------------------------------------------------- 1 | (define (adder x) 2 | (lambda (y) (+ x y))) 3 | 4 | (let ((add1 (adder 1))) 5 | (add1 40)) 6 | -------------------------------------------------------------------------------- /list_example: -------------------------------------------------------------------------------- 1 | (define (cons a b) 2 | (tuple a b)) 3 | 4 | (define (car t) 5 | (tuple-ref t 0)) 6 | 7 | (define (cdr t) 8 | (tuple-ref t 1)) 9 | 10 | (define (sum l) 11 | (if (= l #f) 12 | 0 13 | (+ (car l) (sum (cdr l))))) 14 | 15 | (define (length l) 16 | (if (= l #f) 17 | 0 18 | (+ 1 (length (cdr l))))) 19 | 20 | (let ((mylist (cons 1 (cons 2 (cons 3 #f))))) 21 | (sum mylist)) 22 | -------------------------------------------------------------------------------- /run_tests.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import subprocess 3 | import re 4 | import shutil 5 | import os 6 | import sys 7 | 8 | """ 9 | USAGE: python run_tests.py 10 | 11 | Runs all tests in the `tests` directory. 12 | 13 | The way to specify a test is to add a pair of files- a .input file with 14 | the rusl program and a .output file with the expected output. 15 | """ 16 | 17 | def get_test_names(): 18 | input_files = glob.glob("tests/*.input") 19 | test_names = list(map(lambda i: re.match(r"tests/(\w+)\.input", i).group(1), input_files)) 20 | 21 | return test_names 22 | 23 | def run_test(test_name): 24 | output_path = "tests/" + test_name + ".output" 25 | input_path = "tests/" + test_name + ".input" 26 | try: 27 | output_file = open(output_path, "r") 28 | except FileNotFoundError: 29 | print("No corresponding .output file found for: " + test_name + ".input") 30 | return 1 31 | 32 | # TODO: Handle this for non-integer tests 33 | expected_output = int(output_file.read()) 34 | 35 | # Compile and run the program 36 | asm_path = "tests/_bin/" + test_name + ".s" 37 | asm_file = open(asm_path, "w") 38 | object_path = "tests/_bin/" + test_name + ".o" 39 | bin_path = "tests/_bin/" + test_name + ".out" 40 | 41 | # TODO: check that each of these pass before running the next 42 | # command 43 | subprocess.run(["cargo", "run", input_path], stdout=asm_file) 44 | subprocess.run(["nasm", "-f", "elf64", asm_path]) 45 | subprocess.run(["gcc", "-std=c99", "-o", bin_path, "runtime.c", object_path]) 46 | 47 | bin_run = subprocess.run(bin_path, stdout=subprocess.PIPE) 48 | 49 | actual_output = int(bin_run.stdout) 50 | if expected_output != actual_output: 51 | print("Test %s failed. \t Expected: %d \t Actual: %d" % 52 | (test_name, expected_output, actual_output)) 53 | return 1 54 | 55 | return 0 56 | 57 | 58 | def run_all_tests(delete_generated_files=True): 59 | test_names = get_test_names() 60 | num_tests = len(test_names) 61 | failures = 0 62 | for test in test_names: 63 | print("Running %s" % test) 64 | failures += run_test(test) 65 | 66 | print("\n\n Ran %d tests. %d tests failed." % (num_tests, failures)) 67 | 68 | # Delete generated files 69 | if delete_generated_files: 70 | shutil.rmtree("tests/_bin") 71 | 72 | if failures > 0: 73 | sys.exit(1) 74 | 75 | 76 | if __name__ == '__main__': 77 | try: 78 | os.mkdir("tests/_bin") 79 | except FileExistsError: 80 | pass 81 | run_all_tests() 82 | -------------------------------------------------------------------------------- /runtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int64_t *heap; 6 | int64_t *rootstack; 7 | int64_t *free_ptr; 8 | 9 | const int64_t TRUE = 0xffffffffffffffff; 10 | const int64_t FALSE = 0x7fffffffffffffff; 11 | 12 | void rec_print(int64_t val) { 13 | if(val & 0x00000001 ^ 0x00000001) { 14 | printf("%" PRId64, val >> 1); 15 | } 16 | else if(val == TRUE) { 17 | printf("#t"); 18 | } 19 | else if(val == FALSE) { 20 | printf("#f"); 21 | } 22 | else if((val & 0x00000003) == 0x00000001) { 23 | int64_t *tup_base = (int64_t*)(val - 1); 24 | int tup_count = *tup_base; 25 | printf("("); 26 | for (int i = 1; i < tup_count + 1; i++) { 27 | int64_t ith_val = *(tup_base + i); 28 | rec_print(ith_val); 29 | 30 | if (i != tup_count) { 31 | printf(", "); 32 | } 33 | } 34 | printf(")"); 35 | } 36 | else { 37 | printf("Unknown value: %#010x", val); 38 | } 39 | } 40 | 41 | int64_t print(int64_t val) { 42 | rec_print(val); 43 | printf("\n"); 44 | return val; 45 | } 46 | 47 | void initialize() { 48 | heap = malloc(200); 49 | rootstack = malloc(200); 50 | free_ptr = heap; 51 | } 52 | 53 | /* FIXME: right now, correct `val` is not passed */ 54 | void error_not_number(int64_t val) { 55 | fprintf(stderr, "expected a number: %#010x\n", print(val)); 56 | exit(1); 57 | } 58 | 59 | void error_not_bool(int64_t val) { 60 | fprintf(stderr, "expected a boolean: %#010x\n", val); 61 | exit(1); 62 | } 63 | 64 | void error_not_tuple(int64_t val) { 65 | fprintf(stderr, "expected a tuple: %#010x\n", val); 66 | exit(1); 67 | } 68 | -------------------------------------------------------------------------------- /src/anf.rs: -------------------------------------------------------------------------------- 1 | use util::get_unique_varname; 2 | use std::rc::Rc; 3 | use ast::{Ast, CC}; 4 | 5 | #[derive(Clone, Debug, PartialEq)] 6 | pub enum Flat { 7 | Symbol(Rc), 8 | FuncName(Rc), // for closure-conversion 9 | Number(i64), 10 | Bool(bool), 11 | Tuple(Vec), 12 | Assign(Rc, Box), 13 | Return(Box), 14 | If(Box, Vec, Vec), 15 | Cmp(CC, Box, Box), 16 | App(Rc, Vec), 17 | Prim(Rc, Vec), 18 | } 19 | 20 | #[derive(Debug, PartialEq)] 21 | pub enum FlatResult { 22 | Prog(Vec, Vec, Vec>), 23 | Define(Rc, Vec>, Vec, Vec>), 24 | Flat(Flat, Vec, Vec>), 25 | } 26 | 27 | fn flatten_args(args: &[Ast]) 28 | -> (Vec, Vec, Vec>) { 29 | let mut flat_args = vec![]; 30 | let mut args_assigns : Vec = vec![]; 31 | let mut args_vars = vec![]; 32 | 33 | for arg in args { 34 | match flatten(arg) { 35 | FlatResult::Flat(flat, assigns, vars) => { 36 | flat_args.push(flat); 37 | args_assigns.extend_from_slice(&assigns); 38 | args_vars.extend_from_slice(&vars); 39 | }, 40 | _ => panic!("unreachable"), 41 | }; 42 | } 43 | 44 | (flat_args, args_assigns, args_vars) 45 | } 46 | 47 | fn flatten_tuple(elts: &[Ast]) -> FlatResult { 48 | let tup_temp = Rc::new(get_unique_varname("tmp")); 49 | let mut flat_elts = vec![]; 50 | let mut elts_assigns : Vec = vec![]; 51 | let mut elts_vars = vec![]; 52 | 53 | for elt in elts { 54 | if let FlatResult::Flat(flat, assigns, vars) = flatten(&elt) { 55 | flat_elts.push(flat); 56 | elts_assigns.extend_from_slice(&assigns); 57 | elts_vars.extend_from_slice(&vars); 58 | } else { 59 | panic!("unreachable") 60 | } 61 | } 62 | 63 | elts_assigns.extend_from_slice(&[ 64 | Flat::Assign(tup_temp.clone(), 65 | box Flat::Tuple(flat_elts)) 66 | ]); 67 | elts_vars.extend_from_slice(&[tup_temp.clone()]); 68 | 69 | FlatResult::Flat(Flat::Symbol(tup_temp), 70 | elts_assigns, 71 | elts_vars) 72 | } 73 | 74 | fn flatten_let(bindings: &[(Rc, Ast)], body: &Box) -> FlatResult { 75 | if let FlatResult::Flat(flat_body, body_assigns, body_vars) = flatten(&body) { 76 | let mut bindings_assigns = vec![]; 77 | let mut bindings_vars = vec![]; 78 | for (k, v) in bindings { 79 | if let FlatResult::Flat(flat_v, v_assigns, v_vars) = flatten(v) { 80 | if let Flat::Symbol(name) = flat_v.clone() { 81 | bindings_vars.push(name) 82 | } 83 | bindings_assigns.extend_from_slice(&v_assigns); 84 | bindings_assigns.extend_from_slice( 85 | &[Flat::Assign(k.clone(), Box::new(flat_v))] 86 | ); 87 | bindings_vars.extend_from_slice(&v_vars); 88 | bindings_vars.push(k.clone()); 89 | } 90 | else { 91 | panic!("unreachable"); 92 | } 93 | } 94 | bindings_assigns.extend_from_slice(&body_assigns); 95 | bindings_vars.extend_from_slice(&body_vars); 96 | 97 | FlatResult::Flat(flat_body, 98 | bindings_assigns, 99 | bindings_vars) 100 | 101 | } else { 102 | panic!("NYI"); 103 | } 104 | } 105 | 106 | 107 | // This function does and ANF transformation. The output is a Flat 108 | // expression. 109 | pub fn flatten(expr: &Ast) -> FlatResult { 110 | match expr { 111 | Ast::Symbol(name) => FlatResult::Flat(Flat::Symbol(name.clone()), 112 | vec![], 113 | vec![name.clone()]), 114 | Ast::FuncName(name) => FlatResult::Flat(Flat::FuncName(name.clone()), 115 | vec![], 116 | vec![name.clone()]), 117 | Ast::Number(n) => FlatResult::Flat(Flat::Number(*n), 118 | vec![], 119 | vec![]), 120 | Ast::Bool(b) => FlatResult::Flat(Flat::Bool(*b), 121 | vec![], 122 | vec![]), 123 | Ast::Lambda(_, _) => 124 | panic!("closure conversion should happen before flatten"), 125 | Ast::Tuple(elts) => flatten_tuple(elts), 126 | Ast::Let(bindings, body) => flatten_let(bindings, body), 127 | Ast::List(_) => { 128 | panic!("NYI"); 129 | }, 130 | Ast::Define(name, args, body) => { 131 | let (flat_body, mut body_assigns, mut body_vars) = 132 | match flatten(body) { 133 | FlatResult::Flat(flat_body, body_assigns, body_vars) => 134 | (flat_body, body_assigns, body_vars), 135 | _ => panic!("unreachable"), 136 | }; 137 | body_assigns.extend_from_slice(&[ 138 | Flat::Return(Box::new(flat_body)) 139 | ]); 140 | 141 | // Remove args from body_vars 142 | for arg in args { 143 | body_vars = body_vars.iter().filter(|v| v != &arg).cloned().collect(); 144 | } 145 | 146 | FlatResult::Define(name.clone(), 147 | args.to_vec(), 148 | body_assigns, 149 | body_vars) 150 | }, 151 | Ast::If(cnd, thn, els) => { 152 | let (flat_cnd, mut cnd_assigns, mut cnd_vars) = 153 | match flatten(cnd) { 154 | FlatResult::Flat(flat_cnd, cnd_assigns, cnd_vars) => 155 | (flat_cnd, cnd_assigns, cnd_vars), 156 | _ => panic!("unreachable"), 157 | }; 158 | let (flat_thn, mut thn_assigns, mut thn_vars) = 159 | match flatten(thn) { 160 | FlatResult::Flat(flat_thn, thn_assigns, thn_vars) => 161 | (flat_thn, thn_assigns, thn_vars), 162 | _ => panic!("unreachable"), 163 | }; 164 | let (flat_els, mut els_assigns, mut els_vars) = 165 | match flatten(els) { 166 | FlatResult::Flat(flat_els, els_assigns, els_vars) => 167 | (flat_els, els_assigns, els_vars), 168 | _ => panic!("unreachable"), 169 | }; 170 | 171 | let if_temp = Rc::new(get_unique_varname("if")); 172 | 173 | thn_assigns.extend_from_slice(&[Flat::Assign(if_temp.clone(), 174 | Box::new(flat_thn))]); 175 | els_assigns.extend_from_slice(&[Flat::Assign(if_temp.clone(), 176 | Box::new(flat_els))]); 177 | let flat_if = Flat::If(Box::new(flat_cnd), 178 | thn_assigns, 179 | els_assigns); 180 | 181 | cnd_assigns.extend_from_slice(&[flat_if]); 182 | cnd_vars.append(&mut thn_vars); 183 | cnd_vars.append(&mut els_vars); 184 | cnd_vars.extend_from_slice(&[if_temp.clone()]); 185 | FlatResult::Flat(Flat::Symbol(if_temp), 186 | cnd_assigns, 187 | cnd_vars) 188 | 189 | }, 190 | Ast::Cmp(cc, left, right) => { 191 | let (flat_left, mut left_assigns, mut left_vars) = 192 | match flatten(left) { 193 | FlatResult::Flat(flat, assigns, vars) => (flat, assigns, vars), 194 | _ => panic!("unreachable"), 195 | }; 196 | let (flat_right, mut right_assigns, mut right_vars) = 197 | match flatten(right) { 198 | FlatResult::Flat(flat, assigns, vars) => (flat, assigns, vars), 199 | _ => panic!("unreachable"), 200 | }; 201 | let cmp_temp = Rc::new(get_unique_varname("tmp")); 202 | left_assigns.append(&mut right_assigns); 203 | left_assigns.extend_from_slice(&[ 204 | Flat::Assign(cmp_temp.clone(), box Flat::Cmp(cc.clone(), 205 | box flat_left, 206 | box flat_right)) 207 | ]); 208 | left_vars.append(&mut right_vars); 209 | left_vars.push(cmp_temp.clone()); 210 | 211 | FlatResult::Flat(Flat::Symbol(cmp_temp), 212 | left_assigns, 213 | left_vars) 214 | }, 215 | Ast::App(f, args) => { 216 | match f { 217 | box Ast::Symbol(fname) => { 218 | match &fname[..] { 219 | "-" => { 220 | let arg1 = match &args[..] { 221 | &[ref arg1] => arg1, 222 | _ => panic!("Wrong no. of args to `-`: {:?}", args), 223 | }; 224 | let (flat_e, mut e_assigns, mut e_vars) = 225 | match flatten(arg1) { 226 | FlatResult::Flat(flat_e, e_assigns, e_vars) => 227 | (flat_e, e_assigns, e_vars), 228 | _ => panic!("unreachable"), 229 | }; 230 | let neg_temp = Rc::new(get_unique_varname("tmp")); 231 | let flat_neg = Flat::Assign(neg_temp.clone(), 232 | Box::new(Flat::Prim(Rc::new("-".to_string()), vec![flat_e]))); 233 | e_assigns.extend_from_slice(&[flat_neg]); 234 | e_vars.extend_from_slice(&[neg_temp.clone()]); 235 | FlatResult::Flat(Flat::Symbol(neg_temp), 236 | e_assigns, 237 | e_vars) 238 | }, 239 | "+" => { 240 | let (arg1, arg2) = match &args[..] { 241 | [ref arg1, ref arg2] => (arg1, arg2), 242 | _ => panic!("Wrong no. of args to `+`"), 243 | }; 244 | let (flat_e1, mut e1_assigns, mut e1_vars) = 245 | match flatten(arg1) { 246 | FlatResult::Flat(flat_e1, e1_assigns, e1_vars) => 247 | (flat_e1, e1_assigns, e1_vars), 248 | _ => panic!("unreachable"), 249 | }; 250 | let (flat_e2, mut e2_assigns, mut e2_vars) = 251 | match flatten(arg2) { 252 | FlatResult::Flat(flat_e2, e2_assigns, e2_vars) => 253 | (flat_e2, e2_assigns, e2_vars), 254 | _ => panic!("unreachable"), 255 | }; 256 | 257 | let plus_temp = Rc::new(get_unique_varname("tmp")); 258 | 259 | let flat_plus = Flat::Assign(plus_temp.clone(), 260 | Box::new(Flat::Prim(Rc::new("+".to_string()), vec![flat_e1, flat_e2]))); 261 | e1_assigns.append(&mut e2_assigns); 262 | e1_assigns.extend_from_slice(&[flat_plus]); 263 | 264 | e1_vars.append(&mut e2_vars); 265 | e1_vars.extend_from_slice(&[plus_temp.clone()]); 266 | 267 | FlatResult::Flat(Flat::Symbol(plus_temp), 268 | e1_assigns, 269 | e1_vars) 270 | }, 271 | "tuple-ref" => { 272 | let (tuple, index) = match &args[..] { 273 | [ref tuple, ref index] => (tuple, index), 274 | _ => panic!("Wrong no. of args to `tuple-ref`: {:?}", args), 275 | }; 276 | let index = match index { 277 | Ast::Number(n) => Flat::Number(*n), 278 | _ => panic!("index to tuple-ref must be a literal number"), 279 | }; 280 | let (flat_tuple, mut tup_assigns, mut tup_vars) = 281 | match flatten(tuple) { 282 | FlatResult::Flat(flat, assigns, vars) => 283 | (flat, assigns, vars), 284 | _ => panic!("unreachable"), 285 | }; 286 | 287 | let ref_temp = Rc::new(get_unique_varname("tmp")); 288 | let flat_ref = Flat::Assign(ref_temp.clone(), 289 | Box::new(Flat::Prim(Rc::new("tuple-ref".to_string()), 290 | vec![flat_tuple, index]))); 291 | tup_assigns.extend_from_slice(&[flat_ref]); 292 | 293 | tup_vars.extend_from_slice(&[ref_temp.clone()]); 294 | 295 | FlatResult::Flat(Flat::Symbol(ref_temp), 296 | tup_assigns, 297 | tup_vars) 298 | }, 299 | _f => { 300 | flatten(&Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())), 301 | vec![Ast::Tuple(vec![Ast::FuncName(fname.clone())]), 302 | Ast::Number(0)])) 303 | }, 304 | } 305 | }, 306 | box Ast::App(_, _) => { 307 | if let FlatResult::Flat(flat_fref, 308 | mut fref_assigns, 309 | mut fref_vars) = flatten(f) { 310 | let flat_fref = match flat_fref { 311 | Flat::Symbol(fname) => fname, 312 | _ => panic!("unreachable: {:?}", flat_fref), 313 | }; 314 | 315 | let app_temp = Rc::new(get_unique_varname("tmp")); 316 | let (flat_args, args_assigns, args_vars) = 317 | flatten_args(&args); 318 | let flat_app = Flat::Assign(app_temp.clone(), 319 | box Flat::App(flat_fref, 320 | flat_args)); 321 | 322 | fref_assigns.extend_from_slice(&args_assigns); 323 | fref_assigns.extend_from_slice(&[flat_app]); 324 | 325 | fref_vars.extend_from_slice(&[app_temp.clone()]); 326 | fref_vars.extend_from_slice(&args_vars[..]); 327 | 328 | FlatResult::Flat(Flat::Symbol(app_temp.clone()), 329 | fref_assigns, 330 | fref_vars) 331 | } else { 332 | panic!("unreachable"); 333 | } 334 | 335 | }, 336 | _ => panic!("not a function: {:?}", f), 337 | } 338 | }, 339 | Ast::Prog(defs, e) => { 340 | let (flat_e, mut e_assigns, mut e_vars) = 341 | match flatten(e) { 342 | FlatResult::Flat(flat_e, e_assigns, e_vars) => 343 | (flat_e, e_assigns, e_vars), 344 | _ => panic!("unreachable"), 345 | }; 346 | let return_e = Flat::Return(Box::new(flat_e)); 347 | 348 | e_assigns.extend_from_slice(&[return_e]); 349 | e_vars.dedup(); 350 | 351 | let mut flat_defs = vec![]; 352 | for def in defs { 353 | flat_defs.push(flatten(def)); 354 | } 355 | 356 | FlatResult::Prog(flat_defs, 357 | e_assigns, 358 | e_vars) 359 | }, 360 | _ => unimplemented!(), 361 | } 362 | } 363 | 364 | #[test] 365 | fn test_flatten() { 366 | use parser::Parser; 367 | 368 | let input = String::from("(+ 12 (+ 13 14))"); 369 | let parser = Parser::new(&input); 370 | let toplevel : Vec<_> = parser.collect(); 371 | 372 | assert_eq!( 373 | flatten(&Ast::Prog(vec![], Box::new(toplevel[0].clone()))), 374 | FlatResult::Prog(vec![], 375 | vec![Flat::Assign(Rc::new("tmp1".to_string()), Box::new(Flat::Prim(Rc::new("+".to_string()), 376 | vec![Flat::Number(13), Flat::Number(14)]))), 377 | Flat::Assign(Rc::new("tmp2".to_string()), 378 | Box::new(Flat::Prim(Rc::new("+".to_string()), 379 | vec![Flat::Number(12), 380 | Flat::Symbol(Rc::new("tmp1".to_string()))]))), 381 | Flat::Return(Box::new(Flat::Symbol(Rc::new("tmp2".to_string()))))], 382 | vec![Rc::new("tmp1".to_string()), 383 | Rc::new("tmp2".to_string())]) 384 | ); 385 | 386 | // TODO: Reset start(var counter) so that these asserts are 387 | // independent. 388 | assert_eq!( 389 | flatten(&Ast::Define(Rc::new("foo".to_string()), 390 | vec![Rc::new("x".to_string()), 391 | Rc::new("y".to_string()), 392 | Rc::new("z".to_string())], 393 | box (Ast::App(box (Ast::Symbol(Rc::new("+".to_string()))), 394 | vec![Ast::Symbol(Rc::new("x".to_string())), 395 | Ast::Number(10)])))), 396 | FlatResult::Define(Rc::new("foo".to_string()), 397 | vec![Rc::new("x".to_string()), 398 | Rc::new("y".to_string()), 399 | Rc::new("z".to_string())], 400 | vec![Flat::Assign(Rc::new("tmp3".to_string()), 401 | Box::new(Flat::Prim(Rc::new("+".to_string()), 402 | vec![Flat::Symbol(Rc::new("x".to_string())), Flat::Number(10)]))), 403 | Flat::Return(Box::new(Flat::Symbol(Rc::new("tmp3".to_string()))))], 404 | vec![Rc::new("tmp3".to_string())]) 405 | ); 406 | } 407 | -------------------------------------------------------------------------------- /src/ast.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | use std::rc::Rc; 3 | 4 | use util::get_unique_varname; 5 | 6 | #[derive(Debug, PartialEq, Clone)] 7 | pub enum CC { 8 | // condition codes 9 | E, L, LE, G, GE, 10 | } 11 | 12 | #[derive(Debug, Clone)] 13 | pub enum Ast { 14 | Symbol(Rc), 15 | Number(i64), 16 | Bool(bool), 17 | List(Vec), 18 | FuncName(Rc), // for closure-conversion 19 | 20 | Define(Rc, Vec>, Box), 21 | If(Box, // cnd 22 | Box, // thn 23 | Box), // els 24 | Let(Vec<(Rc, Ast)>, Box), 25 | Lambda(Vec>, Box), 26 | Tuple(Vec), 27 | Cmp(CC, Box, Box), 28 | App(Box, Vec), 29 | Prog(Vec, Box), 30 | Nil, 31 | } 32 | 33 | impl Ast { 34 | pub fn uniquify(&self, mapping: &mut HashMap, Rc>) -> Self { 35 | match self { 36 | Ast::Symbol(name) => { 37 | let uniq_name = mapping.get(name) 38 | .expect("unbound symbol"); 39 | Ast::Symbol(uniq_name.clone()) 40 | }, 41 | Ast::Number(_) | Ast::Bool(_) => self.clone(), 42 | Ast::Tuple(elts) => { 43 | let elts = 44 | elts.iter().map(|e| e.uniquify(mapping)).collect(); 45 | Ast::Tuple(elts) 46 | }, 47 | Ast::Let(bindings, body) => { 48 | let mut new_bindings = vec![]; 49 | for (k, v) in bindings { 50 | let uniq_k = Rc::new(get_unique_varname(&k)); 51 | new_bindings.push((uniq_k.clone(), 52 | v.uniquify(mapping))); 53 | mapping.insert(k.clone(), uniq_k.clone()); 54 | 55 | } 56 | Ast::Let(new_bindings, 57 | Box::new(body.uniquify(mapping))) 58 | }, 59 | Ast::List(elts) => { 60 | let new_elts : Vec<_> = elts.iter().map(|e| e.uniquify(mapping)).collect(); 61 | Ast::List(new_elts) 62 | }, 63 | Ast::Cmp(cc, left, right) => 64 | Ast::Cmp(cc.clone(), 65 | box left.uniquify(mapping), 66 | box right.uniquify(mapping)), 67 | Ast::Lambda(args, body) => { 68 | let mut new_args = vec![]; 69 | for arg in args { 70 | let new_arg = Rc::new(get_unique_varname(arg)); 71 | new_args.push(new_arg.clone()); 72 | mapping.insert(arg.clone(), new_arg.clone()); 73 | } 74 | 75 | Ast::Lambda(new_args, 76 | box body.uniquify(mapping)) 77 | }, 78 | Ast::Define(name, args, val) => { 79 | let uniq_fname = Rc::new(get_unique_varname(name)); 80 | mapping.insert(name.clone(), uniq_fname.clone()); 81 | 82 | let mut new_args = vec![]; 83 | for arg in args { 84 | let new_arg = Rc::new(get_unique_varname(arg)); 85 | new_args.push(new_arg.clone()); 86 | mapping.insert(arg.clone(), new_arg.clone()); 87 | } 88 | 89 | Ast::Define(uniq_fname, 90 | new_args, 91 | box val.uniquify(mapping)) 92 | }, 93 | Ast::If(cond, thn, els) => 94 | Ast::If(box (cond.uniquify(mapping)), 95 | box (thn.uniquify(mapping)), 96 | box (els.uniquify(mapping))), 97 | Ast::App(f, args) => { 98 | let new_args : Vec<_> = args.iter() 99 | .map(|a| a.uniquify(mapping)).collect(); 100 | Ast::App(box f.uniquify(mapping), 101 | new_args) 102 | }, 103 | Ast::Prog(defs, e) => { 104 | let new_defs : Vec<_> = defs.iter() 105 | .map(|def| def.uniquify(mapping)).collect(); 106 | Ast::Prog(new_defs, box e.uniquify(mapping)) 107 | }, 108 | _ => panic!("NYI"), 109 | } 110 | } 111 | 112 | fn get_free_variables(&self, 113 | env: &HashSet>, 114 | parent_env: &HashSet>) -> Vec> { 115 | match self { 116 | Ast::Number(_) => vec![], 117 | Ast::Symbol(name) => { 118 | match env.get(name) { 119 | Some(_) => vec![], 120 | None => { 121 | match parent_env.get(name) { 122 | Some(_) => vec![name.clone()], 123 | None => panic!("no binding found in parent env for free-variable {} env: {:?} parent-env: {:?}", name, env, parent_env), 124 | } 125 | } 126 | } 127 | }, 128 | Ast::If(cnd, thn, els) => { 129 | let mut cnd_freevars = 130 | cnd.get_free_variables(env, parent_env); 131 | let thn_freevars = 132 | thn.get_free_variables(env, parent_env); 133 | let els_freevars = 134 | els.get_free_variables(env, parent_env); 135 | 136 | cnd_freevars.extend_from_slice(&thn_freevars); 137 | cnd_freevars.extend_from_slice(&els_freevars); 138 | 139 | cnd_freevars 140 | }, 141 | Ast::Define(_, args, body) | 142 | Ast::Lambda(args, body) => { 143 | let mut new_parent_env : HashSet> = HashSet::new() 144 | .union(&env).cloned().collect(); 145 | new_parent_env = new_parent_env 146 | .union(&parent_env).cloned().collect(); 147 | 148 | let new_env : HashSet> = args.iter().cloned().collect(); 149 | 150 | println!("[lambda] new_env: {:?} new_parent_env: {:?}", 151 | new_env, 152 | new_parent_env); 153 | 154 | body.get_free_variables(&new_env, &new_parent_env) 155 | }, 156 | Ast::Let(bindings, body) => { 157 | let mut new_env = HashSet::new(); 158 | let mut bindings_free_vars = vec![]; 159 | for (k, v) in bindings { 160 | let v_freevars : Vec<_> = 161 | v.get_free_variables(env, parent_env); 162 | new_env.insert(k.clone()); 163 | bindings_free_vars.extend_from_slice(&v_freevars); 164 | } 165 | 166 | new_env = new_env.union(&env).cloned().collect(); 167 | let body_freevars : Vec<_> = 168 | body.get_free_variables(&new_env, 169 | parent_env); 170 | bindings_free_vars.extend_from_slice(&body_freevars); 171 | 172 | bindings_free_vars 173 | }, 174 | Ast::App(_, args) => { 175 | let mut args_freevars = vec![]; 176 | for arg in args { 177 | let arg_freevars : Vec<_> = 178 | arg.get_free_variables(env, 179 | parent_env); 180 | args_freevars.extend_from_slice(&arg_freevars); 181 | } 182 | 183 | args_freevars 184 | }, 185 | _ => panic!("NYI: {:?}", self), 186 | } 187 | } 188 | 189 | 190 | fn symbol_is_primitive(sym: &str) -> bool { 191 | match sym { 192 | "+" | "-" | "tuple-ref" | "tuple" => true, 193 | _ => false, 194 | } 195 | } 196 | 197 | fn get_define_name(def: &Ast) -> Rc { 198 | match def { 199 | Ast::Define(name, _, _) => name.clone(), 200 | _ => panic!("not a Define"), 201 | } 202 | } 203 | 204 | /// Converts a lambda into a top-level define'd function. For all 205 | /// functions, adds a closure arg, and updates function 206 | /// applications to pass the closure arg. The `clos` arg is a 207 | /// tuple (f, a1, ..., an) capturing free variables. 208 | pub fn convert_to_closures(&self, env: &HashSet>, toplevel_funs: &HashSet>) 209 | -> (Ast, Vec) { 210 | match self { 211 | Ast::Cmp(_, _, _) | 212 | Ast::Bool(_) | 213 | Ast::Symbol(_) | 214 | Ast::FuncName(_) | 215 | Ast::Number(_) => (self.clone(), vec![]), 216 | Ast::If(cnd, thn, els) => { 217 | let (converted_cnd, mut cnd_defines) = 218 | cnd.convert_to_closures(env, toplevel_funs); 219 | let (converted_thn, thn_defines) = 220 | thn.convert_to_closures(env, toplevel_funs); 221 | let (converted_els, els_defines) = 222 | els.convert_to_closures(env, toplevel_funs); 223 | 224 | let converted = Ast::If(box converted_cnd, 225 | box converted_thn, 226 | box converted_els); 227 | 228 | cnd_defines.extend_from_slice(&thn_defines); 229 | cnd_defines.extend_from_slice(&els_defines); 230 | 231 | (converted, cnd_defines) 232 | }, 233 | Ast::Define(name, args, body) => { 234 | let mut new_args = args.clone(); 235 | let mut new_env = env.clone(); 236 | 237 | for arg in args { 238 | new_env.insert(arg.clone()); 239 | } 240 | let (converted_body, body_defines) = 241 | body.convert_to_closures(&new_env, toplevel_funs); 242 | 243 | new_args.insert(0, Rc::new("clos".to_string())); 244 | 245 | let converted = Ast::Define(name.clone(), 246 | new_args, 247 | box converted_body); 248 | 249 | (converted, body_defines) 250 | 251 | }, 252 | Ast::Lambda(args, body) => { 253 | let mut new_env = HashSet::new(); 254 | let mut new_args = args.clone(); 255 | for arg in args { 256 | new_env.insert(arg.clone()); 257 | } 258 | 259 | let (converted_body, mut new_defines) = 260 | body.convert_to_closures(&new_env, toplevel_funs); 261 | 262 | let lambda_name = Rc::new(get_unique_varname("lam")); 263 | let free_vars : Vec<_> = body.get_free_variables(&new_env, 264 | env); 265 | let mut load_free_vars = converted_body; 266 | for (i, fvar) in free_vars.iter().enumerate() { 267 | let bindings = vec![(fvar.clone(), 268 | Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())), 269 | vec![Ast::Symbol(Rc::new("clos".to_string())), 270 | Ast::Number((i+1) as i64)]))]; 271 | load_free_vars = 272 | Ast::Let(bindings, 273 | box load_free_vars); 274 | } 275 | 276 | new_args.insert(0, Rc::new("clos".to_string())); 277 | 278 | let mut closure_elts = 279 | vec![Ast::FuncName(lambda_name.clone())]; 280 | 281 | let free_vars : Vec = 282 | free_vars.iter().map(|fv| Ast::Symbol(fv.clone())).collect(); 283 | closure_elts.extend_from_slice(&free_vars[..]); 284 | let closure = Ast::Tuple(closure_elts); 285 | 286 | new_defines.extend_from_slice(&[ 287 | Ast::Define(lambda_name.clone(), 288 | new_args, 289 | box load_free_vars) 290 | ]); 291 | 292 | (closure, new_defines) 293 | }, 294 | Ast::Tuple(elts) => { 295 | let mut converted_elts = vec![]; 296 | let mut elts_defines = vec![]; 297 | 298 | for elt in elts { 299 | let (conv_elt, elt_defines) : (Ast, Vec) = 300 | elt.convert_to_closures(env, toplevel_funs); 301 | converted_elts.push(conv_elt); 302 | elts_defines.extend_from_slice(&elt_defines); 303 | } 304 | 305 | let converted = Ast::Tuple(converted_elts); 306 | (converted, elts_defines) 307 | 308 | }, 309 | Ast::App(box Ast::Symbol(f), ref args) 310 | if Self::symbol_is_primitive(f) => { 311 | let mut converted_args = vec![]; 312 | let mut args_defines = vec![]; 313 | 314 | for arg in args.clone() { 315 | let (conv_arg, arg_defines) : (Ast, Vec) = 316 | arg.convert_to_closures(env, toplevel_funs); 317 | converted_args.push(conv_arg); 318 | args_defines.extend_from_slice(&arg_defines); 319 | } 320 | 321 | let converted = Ast::App(box Ast::Symbol(f.clone()), 322 | converted_args); 323 | (converted, args_defines) 324 | }, 325 | Ast::App(box Ast::Symbol(f), ref args) 326 | if !Self::symbol_is_primitive(f) => { 327 | let fname = match toplevel_funs.get(f) { 328 | Some(_) => Ast::Tuple(vec![Ast::FuncName(f.clone())]), 329 | None => Ast::Symbol(f.clone()), 330 | }; 331 | 332 | let (fclos, fdefines) : (Ast, Vec) = 333 | fname.convert_to_closures(env, toplevel_funs); 334 | let f_temp = Rc::new(get_unique_varname("tmp")); 335 | 336 | let mut converted_args = 337 | vec![Ast::Symbol(f_temp.clone())]; 338 | let mut args_defines = vec![]; 339 | 340 | for arg in args { 341 | let (conv_arg, arg_defines) : (Ast, Vec) = 342 | arg.convert_to_closures(env, toplevel_funs); 343 | converted_args.push(conv_arg); 344 | args_defines.extend_from_slice(&arg_defines); 345 | } 346 | 347 | args_defines.extend_from_slice(&fdefines); 348 | 349 | let converted = Ast::Let(vec![(f_temp.clone(), fclos)], 350 | box Ast::App( 351 | box Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())), 352 | vec![Ast::Symbol(f_temp), 353 | Ast::Number(0)]), 354 | converted_args)); 355 | (converted, args_defines) 356 | }, 357 | Ast::Let(bindings, body) => { 358 | let mut new_bindings = vec![]; 359 | let mut bindings_defines = vec![]; 360 | let mut new_env = env.clone(); 361 | 362 | for (k, v) in bindings { 363 | let (converted_v, v_defines) : (Ast, Vec) = 364 | v.convert_to_closures(env, toplevel_funs); 365 | 366 | new_env.insert(k.clone()); 367 | new_bindings.push((k.clone(), converted_v)); 368 | bindings_defines.extend_from_slice(&v_defines); 369 | }; 370 | 371 | let (converted_body, body_defines) : (Ast, Vec) = 372 | body.convert_to_closures(&new_env, toplevel_funs); 373 | 374 | bindings_defines.extend_from_slice(&body_defines); 375 | 376 | let converted = Ast::Let(new_bindings, 377 | box converted_body); 378 | (converted, bindings_defines) 379 | }, 380 | Ast::Prog(defines, main) => { 381 | let mut converted_defines = vec![]; 382 | let mut defines_new_defines = vec![]; 383 | let mut toplevel_funs = toplevel_funs.clone(); 384 | 385 | for def in defines { 386 | toplevel_funs.insert(Self::get_define_name(&def)); 387 | let (converted_define, new_defines) : (Ast, Vec) = 388 | def.convert_to_closures(env, &toplevel_funs); 389 | 390 | converted_defines.push(converted_define); 391 | defines_new_defines.extend_from_slice(&new_defines); 392 | } 393 | 394 | let (converted_main, main_defines) : (Ast, Vec) = 395 | main.convert_to_closures(env, &toplevel_funs); 396 | 397 | converted_defines.extend_from_slice(&defines_new_defines); 398 | converted_defines.extend_from_slice(&main_defines); 399 | 400 | let converted = Ast::Prog(converted_defines, 401 | box converted_main); 402 | 403 | (converted, vec![]) 404 | }, 405 | _ => panic!("NYI: {:?}", self), 406 | } 407 | } 408 | } 409 | -------------------------------------------------------------------------------- /src/emit.rs: -------------------------------------------------------------------------------- 1 | use x86::{Reg, X86Arg, X86, 2 | CALLEE_SAVE_REGS}; 3 | use ast::CC; 4 | 5 | fn display_reg(reg: &Reg) -> String { 6 | match reg { 7 | Reg::AL => "al", 8 | Reg::RAX => "rax", 9 | Reg::RBX => "rbx", 10 | Reg::RBP => "rbp", 11 | Reg::RDX => "rdx", 12 | Reg::RCX => "rcx", 13 | Reg::RDI => "rdi", 14 | Reg::RSI => "rsi", 15 | Reg::R8 => "r8", 16 | Reg::R9 => "r9", 17 | Reg::R10 => "r10", 18 | Reg::R11 => "r11", 19 | Reg::R12 => "r12", 20 | Reg::R13 => "r13", 21 | Reg::R14 => "r14", 22 | Reg::R15 => "r15", 23 | }.to_string() 24 | } 25 | 26 | fn print_x86_arg(arg: X86Arg) -> String { 27 | match arg { 28 | X86Arg::Reg(r) => format!("{}", display_reg(&r)), 29 | X86Arg::Imm(n) => format!("{}", n), 30 | X86Arg::RegOffset(r, offset) => { 31 | if offset < 0 { 32 | format!("QWORD [{}{}]", 33 | display_reg(&r), 34 | offset) 35 | } 36 | else { 37 | format!("QWORD [{}+{}]", 38 | display_reg(&r), 39 | offset) 40 | } 41 | }, 42 | X86Arg::FuncName(f) => format!("{}", f), 43 | X86Arg::GlobalVal(g) => format!("QWORD [rel {}]", g), 44 | _ => panic!("invalid arg type: {:?}", arg), 45 | } 46 | } 47 | 48 | fn print_cc(cc: CC) -> String { 49 | match cc { 50 | CC::E => "e", 51 | CC::L => "l", 52 | CC::LE => "le", 53 | CC::G => "g", 54 | CC::GE => "ge", 55 | }.to_string() 56 | } 57 | 58 | fn print_instr(instr: X86) -> String { 59 | let instr_string = match instr.clone() { 60 | X86::Mov(dest, src) => format!("mov {}, {}", 61 | print_x86_arg(dest), 62 | print_x86_arg(src)), 63 | X86::Add(dest, src) => format!("add {}, {}", 64 | print_x86_arg(dest), 65 | print_x86_arg(src)), 66 | X86::And(dest, src) => format!("and {}, {}", 67 | print_x86_arg(dest), 68 | print_x86_arg(src)), 69 | X86::Sub(dest, src) => format!("sub {}, {}", 70 | print_x86_arg(dest), 71 | print_x86_arg(src)), 72 | X86::Cmp(left, right) => format!("cmp {}, {}", 73 | print_x86_arg(left), 74 | print_x86_arg(right)), 75 | X86::JmpIf(cc, label) => format!("j{} {}", 76 | print_cc(cc), 77 | label), 78 | X86::Jmp(label) => format!("jmp {}", label), 79 | X86::Jne(label) => format!("jne {}", label), 80 | X86::Je(label) => format!("je {}", label), 81 | X86::Label(label) => format!("{}:", label), 82 | X86::Call(label) => format!("call {}", print_x86_arg(label)), 83 | X86::Set(X86Arg::Reg(r), cc) => 84 | format!("set{} {}", print_cc(cc), display_reg(&r)), 85 | X86::MovZx(dest, src) => format!("movzx {}, {}", 86 | print_x86_arg(dest), 87 | print_x86_arg(src)), 88 | X86::Neg(n) => format!("neg {}", print_x86_arg(n)), 89 | X86::Push(r) => format!("push {}", display_reg(&r)), 90 | X86::Pop(r) => format!("pop {}", display_reg(&r)), 91 | _ => panic!("invalid op: {:?}", instr), 92 | }; 93 | 94 | match instr { 95 | X86::Label(_) => return format!("{}\n", instr_string), 96 | _ => return format!(" {}\n", instr_string), 97 | } 98 | } 99 | 100 | pub fn print_x86(prog: X86) -> String { 101 | let mut save_callee_save_regs = String::new(); 102 | for r in CALLEE_SAVE_REGS.iter() { 103 | save_callee_save_regs.push_str(&format!(" push {}\n", 104 | display_reg(r))); 105 | } 106 | let mut restore_callee_save_regs = String::new(); 107 | for r in CALLEE_SAVE_REGS.iter().rev() { 108 | restore_callee_save_regs.push_str(&format!(" pop {}\n", 109 | display_reg(r))); 110 | } 111 | 112 | match prog { 113 | X86::DefineWithStackSize(name, stack_size, instrs) => { 114 | let stack_size = 8 * stack_size; 115 | let prelude = format!("{}: 116 | push rbp 117 | mov rbp, rsp 118 | sub rsp, {} 119 | {}\n", name, stack_size, save_callee_save_regs); 120 | let postlude = format!(" mov rdi, rax 121 | {} 122 | add rsp, {} 123 | mov rsp, rbp 124 | pop rbp 125 | ret\n", restore_callee_save_regs, stack_size,); 126 | 127 | let mut instrs_str = prelude; 128 | for i in instrs { 129 | instrs_str.push_str(&print_instr(i)); 130 | } 131 | 132 | instrs_str.push_str(&postlude[..]); 133 | instrs_str 134 | }, 135 | X86::ProgWithStackSize(defs, instrs, stack_size) => { 136 | let stack_size = 8 * stack_size; 137 | let mut defs_str = String::new(); 138 | for def in defs { 139 | defs_str.push_str(&print_x86(def)[..]); 140 | } 141 | let prelude = format!("section .text 142 | extern print 143 | extern initialize 144 | extern heap 145 | extern rootstack 146 | extern free_ptr 147 | extern error_not_number 148 | extern error_not_bool 149 | extern error_not_tuple 150 | global main 151 | main: 152 | push rbp 153 | mov rbp, rsp 154 | sub rsp, {} 155 | {} 156 | call initialize\n", stack_size, save_callee_save_regs); 157 | let postlude = format!(" mov rdi, rax 158 | call print 159 | {} 160 | add rsp, {} 161 | mov rsp, rbp 162 | pop rbp 163 | ret 164 | internal_error_non_number: 165 | call error_not_number 166 | internal_error_non_bool: 167 | call error_not_bool 168 | internal_error_non_tuple: 169 | call error_not_tuple 170 | \n", restore_callee_save_regs, stack_size); 171 | let mut instrs_str = prelude; 172 | for i in instrs { 173 | instrs_str.push_str(&print_instr(i)); 174 | } 175 | instrs_str.push_str(&postlude[..]); 176 | instrs_str.push_str(&defs_str[..]); 177 | instrs_str 178 | }, 179 | _ => panic!("print_x86: not top-level Prog"), 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/lexer.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Clone)] 2 | pub enum Token<'input> { 3 | LParen, 4 | RParen, 5 | Symbol(&'input str), 6 | Number(i64), 7 | EOF, 8 | } 9 | 10 | pub struct Lexer<'input> { 11 | pub s: &'input str, 12 | pub pos: usize, 13 | pub col: usize, 14 | pub line_num: usize, 15 | pub tok_buf: Option>, 16 | } 17 | 18 | fn is_valid_in_symbol(c: char) -> bool { 19 | c.is_alphabetic() || 20 | match c { 21 | '+' | '-' | '*' | '/' | '#' | '<' | '>' | '=' => true, 22 | _ => false, 23 | } 24 | } 25 | 26 | impl<'input> Lexer<'input> { 27 | pub fn new(source: &'input str) -> Lexer<'input> { 28 | Lexer { s: source, 29 | pos: 0, 30 | col: 0, 31 | line_num: 1, 32 | tok_buf: None} 33 | } 34 | 35 | pub fn unread(&mut self, tok: Token<'input>) { 36 | match self.tok_buf { 37 | Some(_) => panic!("error: unread buffer full"), 38 | None => self.tok_buf = Some(tok), 39 | } 40 | } 41 | 42 | pub fn get_token(&mut self) -> Token<'input> { 43 | if let Some(tok) = self.tok_buf.clone() { 44 | self.tok_buf = None; 45 | tok 46 | } 47 | else { 48 | let mut iter = self.s[self.pos..].chars().peekable(); 49 | while let Some(&c) = iter.peek() { 50 | if c.is_numeric() { 51 | let mut n = c; 52 | let start = self.pos; 53 | while n.is_numeric() { 54 | iter.next(); 55 | self.pos += 1; 56 | self.col += 1; 57 | n = match iter.peek() { 58 | Some(&x) => x, 59 | None => break, 60 | }; 61 | } 62 | return Token::Number(self.s[start..self.pos].parse().unwrap()); 63 | } 64 | else if is_valid_in_symbol(c) { 65 | let mut s = c; 66 | let start = self.pos; 67 | while s.is_alphanumeric() || is_valid_in_symbol(s) { 68 | iter.next(); 69 | self.pos += 1; 70 | self.col += 1; 71 | s = match iter.peek() { 72 | Some(&x) => x, 73 | None => break, 74 | }; 75 | } 76 | return Token::Symbol(&self.s[start..self.pos]); 77 | } 78 | else { 79 | match c { 80 | '\n' => { 81 | iter.next(); 82 | self.pos += 1; 83 | self.col = 0; 84 | self.line_num += 1; 85 | continue; 86 | }, 87 | ';' => { 88 | iter.next(); 89 | self.pos += 1; 90 | self.col += 1; 91 | while let Some(c) = iter.next() { 92 | self.pos += 1; 93 | if c == '\n' { 94 | break; 95 | } 96 | } 97 | self.line_num += 1; 98 | self.col = 0; 99 | }, 100 | ' ' => { 101 | iter.next(); 102 | self.pos += 1; 103 | self.col += 1; 104 | continue 105 | }, 106 | '(' => { 107 | iter.next(); 108 | self.pos += 1; 109 | self.col += 1; 110 | return Token::LParen 111 | }, 112 | ')' => { 113 | iter.next(); 114 | self.pos += 1; 115 | self.col += 1; 116 | return Token::RParen 117 | }, 118 | 119 | _ => panic!("line {}:{} unexpected char: {}", self.line_num, self.col, c), 120 | } 121 | } 122 | } 123 | 124 | Token::EOF 125 | } 126 | } 127 | } 128 | 129 | impl<'input> Iterator for Lexer<'input> { 130 | type Item = Token<'input>; 131 | 132 | fn next(&mut self) -> Option> { 133 | match self.get_token() { 134 | Token::EOF => None, 135 | t => Some(t), 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(box_syntax, box_patterns)] 2 | 3 | use std::io; 4 | use std::collections::HashMap; 5 | use std::collections::HashSet; 6 | use std::io::prelude::*; 7 | use std::fs::File; 8 | use std::env; 9 | use std::rc::Rc; 10 | 11 | mod util; 12 | mod lexer; 13 | mod ast; 14 | mod parser; 15 | mod anf; 16 | mod x86; 17 | mod emit; 18 | 19 | use parser::Parser; 20 | use ast::Ast; 21 | use anf::flatten; 22 | use x86::{select_instructions, uncover_live, assign_homes, lower_conditionals, 23 | patch_instructions}; 24 | use emit::print_x86; 25 | 26 | fn read_input(filename: &str, mut input_buffer: &mut String) 27 | -> io::Result<()> { 28 | let mut f = File::open(filename)?; 29 | f.read_to_string(&mut input_buffer)?; 30 | Ok(()) 31 | } 32 | pub fn main() { 33 | let args : Vec<_> = env::args().collect(); 34 | if args.len() < 2 { 35 | panic!("usage: {} filename", args[0].clone()); 36 | } 37 | 38 | let mut input = String::new(); 39 | 40 | let _ = read_input(&args[1], &mut input); 41 | let parser = Parser::new(&input); 42 | let toplevel : Vec<_> = parser.collect(); 43 | 44 | let mut uniquify_mapping : HashMap, Rc> = HashMap::new(); 45 | for prim in ["+", "-", "tuple-ref", "tuple"].iter() { 46 | uniquify_mapping.insert(Rc::new(prim.to_string()), Rc::new(prim.to_string())); 47 | } 48 | 49 | // println!("{:?}", toplevel); 50 | 51 | let uniquified = Ast::Prog(toplevel[..toplevel.len()-1].to_vec(), 52 | Box::new(toplevel[toplevel.len()-1].clone())) 53 | .uniquify(&mut uniquify_mapping); 54 | // println!("Uniquify: {:?}", 55 | // uniquified); 56 | 57 | let (closures_converted, _) = uniquified 58 | .convert_to_closures(&HashSet::new(), 59 | &HashSet::new()); 60 | 61 | // println!("Closures converted: {:?}", 62 | // closures_converted); 63 | 64 | let flattened = flatten(&closures_converted); 65 | // println!("Flattened: {:?}", flattened); 66 | 67 | let pseudo_x86 = select_instructions(flattened); 68 | // println!("Pseudo-X86: {:?}", pseudo_x86); 69 | 70 | let live_vars_uncovered = uncover_live(pseudo_x86); 71 | // println!("Live vars uncovered: {:?}", live_vars_uncovered); 72 | 73 | let homes_assigned = assign_homes(live_vars_uncovered); 74 | // println!("Homes assigned: {:?}", homes_assigned); 75 | 76 | let ifs_lowered = lower_conditionals(homes_assigned); 77 | // println!("Conditionals lowered: {:?}", ifs_lowered); 78 | 79 | let patched = patch_instructions(ifs_lowered); 80 | // println!("Instructions patched: {:?}", patched); 81 | 82 | println!("{}", print_x86(patched)); 83 | } 84 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | use lexer::{Token, Lexer}; 2 | use ast::{Ast, CC}; 3 | 4 | use std::rc::Rc; 5 | 6 | pub struct Parser<'input> { 7 | lexer: Lexer<'input> 8 | } 9 | 10 | impl<'input> Parser<'input> { 11 | pub fn new(source: &'input str) -> Parser<'input> { 12 | Parser { 13 | lexer: Lexer::new(source) 14 | } 15 | } 16 | 17 | pub fn get_list(&mut self) -> Vec { 18 | match self.get_expr() { 19 | Some(expr) => match self.lexer.next() { 20 | None => vec![], 21 | Some(Token::RParen) => vec![expr], 22 | Some(tok) => { 23 | self.lexer.unread(tok); 24 | let mut seq = self.get_list(); 25 | seq.insert(0, expr); 26 | 27 | seq 28 | } 29 | }, 30 | None => vec![], 31 | } 32 | } 33 | 34 | pub fn get_expr(&mut self) -> Option { 35 | match self.lexer.next() { 36 | Some(Token::Symbol(s)) => Some(Ast::Symbol(Rc::new(s.to_string()))), 37 | Some(Token::Number(n)) => Some(Ast::Number(n)), 38 | Some(Token::LParen) => Some(Ast::List(self.get_list())), 39 | Some(Token::RParen) => panic!("line {}: {} unmatched ')'", 40 | self.lexer.line_num, 41 | self.lexer.col), 42 | _ => None, 43 | } 44 | } 45 | 46 | pub fn get_arg_names(args: &[Ast]) -> Vec> { 47 | let arg_names : Vec> = 48 | args.iter().map(|arg| match arg { 49 | Ast::Symbol(name) => name.clone(), 50 | _ => panic!("invalid arg"), 51 | }).collect(); 52 | 53 | arg_names 54 | } 55 | 56 | pub fn get_ast(expr: &Ast) -> Ast { 57 | match expr { 58 | Ast::Symbol(sym) => 59 | match &sym[..] { 60 | "#f" => Ast::Bool(false), 61 | "#t" => Ast::Bool(true), 62 | _ => Ast::Symbol(Rc::new(sym.to_string())) 63 | }, 64 | Ast::List(elts) => 65 | match &elts[..] { 66 | [Ast::Symbol(k), Ast::List(defelts), body] 67 | if &k[..] == "define" => { 68 | let name = &defelts[0]; 69 | let args = &defelts[1..]; 70 | 71 | if let Ast::Symbol(name) = name { 72 | Ast::Define(name.clone(), 73 | Parser::get_arg_names(args), 74 | box Parser::get_ast(body)) 75 | } else { 76 | panic!("invalid function prototype"); 77 | } 78 | }, 79 | [Ast::Symbol(k), cnd, thn, els] 80 | if &k[..] == "if" => { 81 | Ast::If(Box::new(Parser::get_ast(cnd)), 82 | Box::new(Parser::get_ast(thn)), 83 | Box::new(Parser::get_ast(els))) 84 | }, 85 | [Ast::Symbol(k), Ast::List(bindings), body] 86 | if &k[..] == "let" => { 87 | let mut astified_bindings = vec![]; 88 | for bind_pair in bindings { 89 | if let Ast::List(kv) = bind_pair { 90 | let (key, val) = 91 | if kv.len() == 2 { 92 | let astified_val = Parser::get_ast(&kv[1]); 93 | let keyname = 94 | if let Ast::Symbol(k) = kv[0].clone() { 95 | k 96 | } else { 97 | panic!("let binding key is not symbol"); 98 | }; 99 | (keyname, astified_val) 100 | } else { 101 | panic!("invalid let binding syntax"); 102 | }; 103 | 104 | astified_bindings.push((key, val)); 105 | } 106 | } 107 | 108 | Ast::Let(astified_bindings, 109 | Box::new(Parser::get_ast(body))) 110 | }, 111 | [Ast::Symbol(k), Ast::List(args), body] 112 | if &k[..] == "lambda" => { 113 | Ast::Lambda(Parser::get_arg_names(&args), 114 | Box::new(Parser::get_ast(body))) 115 | }, 116 | [Ast::Symbol(k), ..] 117 | if &k[..] == "tuple" => { 118 | let tuple_elts = elts[1..].iter() 119 | // TODO: move? 120 | .map(|e| Parser::get_ast(e)) 121 | .collect(); 122 | Ast::Tuple(tuple_elts) 123 | }, 124 | [Ast::Symbol(cmp), left, right] 125 | if (&cmp[..] == ">" || &cmp[..] == "<" || 126 | &cmp[..] == "<=" || &cmp[..] == ">=" || 127 | &cmp[..] == "=") => { 128 | let cc = match &cmp[..] { 129 | ">" => CC::G, 130 | "<" => CC::L, 131 | ">=" => CC::GE, 132 | "<=" => CC::LE, 133 | "=" => CC::E, 134 | &_ => panic!("invalid cmp op"), 135 | }; 136 | 137 | Ast::Cmp(cc, 138 | Box::new(Parser::get_ast(left)), 139 | Box::new(Parser::get_ast(right))) 140 | }, 141 | [f, ..] => { 142 | let args = elts[1..].iter().map(|e| Parser::get_ast(e)) // TODO: move 143 | .collect(); 144 | 145 | Ast::App(Box::new(f.clone()), args) 146 | } 147 | _ => Ast::Nil, 148 | }, 149 | _ => expr.clone(), 150 | } 151 | } 152 | 153 | pub fn read(&mut self) -> Option { 154 | match self.get_expr() { 155 | Some(expr) => Some(Parser::get_ast(&expr)), 156 | None => None, 157 | } 158 | } 159 | } 160 | 161 | impl<'input> Iterator for Parser<'input> { 162 | type Item = Ast; 163 | 164 | fn next(&mut self) -> Option { 165 | self.read() 166 | } 167 | } 168 | 169 | fn main() { 170 | let mut p = Parser::new("(if #t 42 (define (foo x y) (+ (* 1 2) 2)))"); 171 | println!("{:?}", Parser::get_ast(&p.get_expr().unwrap())); 172 | 173 | let mut p2 = Parser::new("(let ((x 10) (y 2)) (+ x y))"); 174 | println!("{:?}", Parser::get_ast(&p2.get_expr().unwrap())); 175 | 176 | let mut p3 = Parser::new("(lambda (x y) (+ x y))"); 177 | println!("{:?}", Parser::get_ast(&p3.get_expr().unwrap())); 178 | 179 | let mut p4 = Parser::new("(tuple 1 2 3)"); 180 | println!("{:?}", Parser::get_ast(&p4.get_expr().unwrap())); 181 | 182 | let mut p5 = Parser::new("(> 1 2)"); 183 | println!("{:?}", Parser::get_ast(&p5.get_expr().unwrap())); 184 | 185 | let mut p6 = Parser::new("(+ 1 2)"); 186 | println!("{:?}", Parser::get_ast(&p6.get_expr().unwrap())); 187 | 188 | 189 | let ps = Parser::new("(> 1 2) (+ 1 2)"); 190 | for a in ps { 191 | println!("{:?}", a); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | static mut VAR_COUNTER : i32 = 0; 2 | pub fn get_unique_varname(stem: &str) -> String { 3 | unsafe { 4 | VAR_COUNTER += 1; 5 | stem.to_string() + &VAR_COUNTER.to_string() 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/x86.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | use std::collections::{HashMap, HashSet}; 3 | 4 | use ast::CC; 5 | use anf::{Flat, FlatResult}; 6 | use util::get_unique_varname; 7 | 8 | #[derive(Debug, Clone, PartialEq, Hash, Eq)] 9 | pub enum Reg { 10 | AL, 11 | 12 | RAX, RBX, RBP, RCX, RDX, RDI, RSI, 13 | R8, R9, R10, R11, R12, R13, R14, R15, 14 | } 15 | 16 | #[derive(Debug, Clone, Eq, Hash, PartialEq)] 17 | pub enum X86Arg { 18 | Reg(Reg), 19 | Imm(u64), 20 | RegOffset(Reg, i64), 21 | GlobalVal(Rc), 22 | FuncName(Rc), 23 | Var(Rc), // pseudo-x86 24 | } 25 | 26 | 27 | // TODO: It might be a good idea to pull the constructors pertaining 28 | // to pseudo-x86 into a separate datatype. 29 | #[derive(Debug, Clone)] 30 | pub enum X86 { 31 | Mov(X86Arg, X86Arg), 32 | Add(X86Arg, X86Arg), 33 | Sub(X86Arg, X86Arg), 34 | Neg(X86Arg), 35 | Cmp(X86Arg, X86Arg), 36 | And(X86Arg, X86Arg), 37 | Push(Reg), 38 | Pop(Reg), 39 | Set(X86Arg, CC), 40 | MovZx(X86Arg, X86Arg), 41 | EqP(X86Arg, X86Arg), // pseudo-X86 42 | If(Box, Vec, Vec), // pseudo-X86 43 | 44 | // pseudo-X86 45 | IfWithLives(Box, // cond 46 | Vec, // then 47 | Vec>>, // then-live-sets 48 | Vec, // else 49 | Vec>> // else-live-sets 50 | ), 51 | Define(Rc, Vec>, Vec), 52 | DefineWithLives(Rc, // name 53 | Vec>, // vars 54 | Vec>>, // live_sets 55 | Vec, // instrs 56 | ), 57 | DefineWithStackSize(Rc, // name 58 | i64, // stack size 59 | Vec, // instrs 60 | ), 61 | 62 | Prog(Vec, // defines 63 | Vec, // main-instructions 64 | Vec> // main-vars 65 | ), 66 | 67 | ProgWithLives(Vec, // defines 68 | Vec, // main-instructions 69 | Vec>, // main-vars 70 | Vec>> // live-sets 71 | ), 72 | 73 | ProgWithStackSize(Vec, // defines 74 | Vec, // main-instructions 75 | i64, // stack size 76 | ), 77 | Call(X86Arg), 78 | JmpIf(CC, Rc), 79 | Jmp(Rc), 80 | Je(Rc), 81 | Jne(Rc), 82 | Label(Rc), 83 | } 84 | 85 | const CONST_TRUE : u64 = 0xffff_ffff_ffff_ffff; 86 | const CONST_FALSE : u64 = 0x7fff_ffff_ffff_ffff; 87 | 88 | // R11 is used to point to heap 89 | pub const CALLEE_SAVE_REGS : [Reg;5] = 90 | [Reg::RBX, Reg::R12, Reg::R13, Reg::R14, Reg::R15 91 | ]; 92 | pub const CALLER_SAVE_REGS : [Reg;7] = 93 | [Reg::RDX, Reg::RCX, Reg::RSI, Reg::RDI, 94 | Reg::R8, Reg::R9, Reg::R10, // Reg::R11 95 | ]; 96 | // order of registers in which to place first 6 arguments 97 | pub const ARG_REG_ORDER : [Reg; 6] = [Reg::RDI, 98 | Reg::RSI, 99 | Reg::RDX, 100 | Reg::RCX, 101 | Reg::R8, 102 | Reg::R9]; 103 | 104 | // NOTE: registers to use during register allocation. Currently, 105 | // registers that are used in passing arguments are excluded because 106 | // the register allocation pass does not account for interferences 107 | // between registers and variables. 108 | const REGS : [Reg;6] = [ 109 | // callee-save 110 | Reg::RBX, Reg::R12, Reg::R13, Reg::R14, Reg::R15, 111 | 112 | // caller-save 113 | Reg::R10, 114 | // Reg::RDX, Reg::RCX, Reg::RSI, Reg::RDI, 115 | // Reg::R8, Reg::R9, Reg::R11 116 | ]; 117 | 118 | fn flat_arg_type(v: &Flat) -> X86Arg { 119 | match v { 120 | &Flat::Symbol(ref name) => X86Arg::Var(name.clone()), 121 | &Flat::FuncName(ref name) => X86Arg::FuncName(name.clone()), 122 | &Flat::Number(n) => X86Arg::Imm((n << 1) as u64), 123 | &Flat::Bool(b) => { 124 | if b { 125 | X86Arg::Imm(CONST_TRUE) 126 | } else { 127 | X86Arg::Imm(CONST_FALSE) 128 | } 129 | }, 130 | &_ => { 131 | panic!("flat_arg_type: compound expression"); 132 | }, 133 | } 134 | } 135 | 136 | // Emits runtime checks to verify that a is an 137 | // integer(ie. least-significant bit of `a` is zero) 138 | fn ensure_number(a: X86Arg) -> Vec { 139 | vec![X86::Push(Reg::RCX), 140 | X86::Mov(X86Arg::Reg(Reg::RCX), a), 141 | X86::And(X86Arg::Reg(Reg::RCX), X86Arg::Imm(1)), 142 | X86::Cmp(X86Arg::Reg(Reg::RCX), X86Arg::Imm(0)), 143 | X86::Jne(Rc::new("internal_error_non_number".to_string())), 144 | X86::Pop(Reg::RCX)] 145 | } 146 | 147 | // Same as ensure_number but for booleans 148 | fn ensure_bool(a: X86Arg) -> Vec { 149 | let error_label = Rc::new("internal_error_non_bool".to_string()); 150 | vec![X86::Push(Reg::RCX), 151 | X86::Mov(X86Arg::Reg(Reg::RCX), a.clone()), 152 | X86::And(X86Arg::Reg(Reg::RCX), X86Arg::Imm(1)), 153 | X86::Cmp(X86Arg::Reg(Reg::RCX), X86Arg::Imm(0)), 154 | X86::Je(error_label.clone()), 155 | 156 | // second least significant bit 157 | X86::Mov(X86Arg::Reg(Reg::RCX), a), 158 | X86::And(X86Arg::Reg(Reg::RCX), X86Arg::Imm(2)), 159 | X86::Cmp(X86Arg::Reg(Reg::RCX), X86Arg::Imm(0)), 160 | X86::Je(error_label), 161 | X86::Pop(Reg::RCX)] 162 | } 163 | 164 | fn ensure_tuple(a: X86Arg) -> Vec { 165 | let error_label = Rc::new("internal_error_non_tuple".to_string()); 166 | vec![X86::Push(Reg::RCX), 167 | X86::Mov(X86Arg::Reg(Reg::RCX), a.clone()), 168 | X86::And(X86Arg::Reg(Reg::RCX), X86Arg::Imm(1)), 169 | X86::Cmp(X86Arg::Reg(Reg::RCX), X86Arg::Imm(0)), 170 | X86::Je(error_label.clone()), 171 | 172 | // second least significant bit 173 | X86::Mov(X86Arg::Reg(Reg::RCX), a), 174 | X86::And(X86Arg::Reg(Reg::RCX), X86Arg::Imm(2)), 175 | X86::Cmp(X86Arg::Reg(Reg::RCX), X86Arg::Imm(0)), 176 | X86::Jne(error_label.clone()), 177 | 178 | X86::Pop(Reg::RCX)] 179 | } 180 | 181 | 182 | // convert one Flat instruction to pseudo-x86 183 | fn flat_to_px86(instr: Flat) -> Vec { 184 | match instr { 185 | Flat::Assign(dest, e) => { 186 | match *e { 187 | Flat::FuncName(name) => vec![X86::Mov(X86Arg::Var(dest), 188 | X86Arg::FuncName(name))], 189 | Flat::Symbol(name) => vec![X86::Mov(X86Arg::Var(dest), 190 | X86Arg::Var(name))], 191 | Flat::Number(n) => vec![X86::Mov(X86Arg::Var(dest), 192 | X86Arg::Imm((n << 1) as u64))], 193 | Flat::Bool(b) => { 194 | let bval = match b { 195 | true => CONST_TRUE, 196 | false => CONST_FALSE, 197 | }; 198 | return vec![X86::Mov(X86Arg::Var(dest), 199 | X86Arg::Imm(bval as u64))]; 200 | }, 201 | // https://github.com/rust-lang/rust/issues/16223 202 | x => match x { 203 | Flat::Prim(f, args) => { 204 | match &f[..] { 205 | "+" => { 206 | let (arg1, arg2) = match &args[..] { 207 | &[ref arg1, ref arg2] => (arg1, arg2), 208 | _ => { 209 | panic!("`+` expects 2 arguments"); 210 | }, 211 | }; 212 | let mut ret = vec![X86::Mov(X86Arg::Var(dest.clone()), 213 | flat_arg_type(arg1))]; 214 | ret.extend_from_slice(&ensure_number(flat_arg_type(arg1))); 215 | ret.push(X86::Add(X86Arg::Var(dest), 216 | flat_arg_type(arg2))); 217 | ret.extend_from_slice(&ensure_number(flat_arg_type(arg2))); 218 | ret 219 | }, 220 | "-" => { 221 | let arg = match &args[..] { 222 | [ref arg] => arg, 223 | _ => { 224 | panic!("`-` expects 1 argument"); 225 | }, 226 | }; 227 | let mut ret = vec![X86::Mov(X86Arg::Var(dest.clone()), 228 | flat_arg_type(arg))]; 229 | ret.extend_from_slice(&ensure_number(flat_arg_type(arg))); 230 | ret.push(X86::Neg(X86Arg::Var(dest))); 231 | 232 | ret 233 | }, 234 | "tuple-ref" => { 235 | let (tuple, index) = match &args[..] { 236 | [ref tuple, ref index] => (tuple, index), 237 | _ => { 238 | panic!("`tuple-ref` expects 2 arguments"); 239 | }, 240 | }; 241 | 242 | let index = match index { 243 | &Flat::Number(n) => n, 244 | &_ => panic!("index to tuple-ref must be a literal number"), 245 | }; 246 | 247 | let mut ret = ensure_tuple(flat_arg_type(tuple)); 248 | ret.extend_from_slice(&[ 249 | X86::Mov(X86Arg::Reg(Reg::R11), flat_arg_type(tuple)), 250 | // subtract 1 from tuple tag 251 | X86::Sub(X86Arg::Reg(Reg::R11), X86Arg::Imm(1)), 252 | // NOTE: first word contains count 253 | X86::Mov(X86Arg::Var(dest), X86Arg::RegOffset(Reg::R11, 254 | 8*(index+1))) 255 | ]); 256 | 257 | ret 258 | }, 259 | _ => panic!("primitive not defined"), 260 | } 261 | }, 262 | Flat::App(f, args) => { 263 | let mut instrs = vec![]; 264 | 265 | // push caller-save-regs 266 | for r in CALLER_SAVE_REGS.iter() { 267 | instrs.push(X86::Push(r.clone())); 268 | } 269 | 270 | // TODO: if more than 6 args, spill args to stack 271 | // push args 272 | for (i, arg) in args.iter().map(|a| flat_arg_type(a)).enumerate() { 273 | instrs.push( 274 | X86::Mov(X86Arg::Reg(ARG_REG_ORDER[i].clone()), 275 | arg) 276 | ); 277 | } 278 | 279 | instrs.extend_from_slice(&[ 280 | X86::Call(X86Arg::FuncName(f)), 281 | ]); 282 | 283 | // pop caller-save regs 284 | for r in CALLER_SAVE_REGS.iter().rev() { 285 | instrs.push(X86::Pop(r.clone())); 286 | } 287 | 288 | instrs.extend_from_slice(&[ 289 | X86::Mov(X86Arg::Var(dest), X86Arg::Reg(Reg::RAX)) 290 | ]); 291 | 292 | instrs 293 | }, 294 | Flat::Cmp(cc, left, right) => { 295 | let false_label = Rc::new(get_unique_varname("false")); 296 | let done_label = Rc::new(get_unique_varname("done")); 297 | 298 | let mut ret = ensure_number(flat_arg_type(&*left)); 299 | 300 | ret.extend_from_slice(&ensure_number(flat_arg_type(&*right))); 301 | ret.extend_from_slice(&[X86::Cmp(flat_arg_type(&*left), 302 | flat_arg_type(&*right)), 303 | X86::Set(X86Arg::Reg(Reg::AL), cc), 304 | X86::MovZx(X86Arg::Reg(Reg::RAX), X86Arg::Reg(Reg::AL)), 305 | X86::Cmp(X86Arg::Reg(Reg::RAX), X86Arg::Imm(0)), 306 | X86::Je(false_label.clone()), 307 | X86::Mov(X86Arg::Var(dest.clone()), X86Arg::Imm(CONST_TRUE)), 308 | X86::Jmp(done_label.clone()), 309 | X86::Label(false_label), 310 | X86::Mov(X86Arg::Var(dest), X86Arg::Imm(CONST_FALSE)), 311 | X86::Label(done_label),]); 312 | ret 313 | }, 314 | Flat::Tuple(elts) => { 315 | // with count in first word 316 | let len = elts.len() + 1; 317 | let total_len = 8*(len + (len % 2)); 318 | let free_ptr_str = Rc::new("free_ptr".to_string()); 319 | let mut instrs = 320 | vec![X86::Mov(X86Arg::Var(dest.clone()), 321 | X86Arg::GlobalVal(free_ptr_str.clone())), 322 | X86::Add(X86Arg::GlobalVal(free_ptr_str), 323 | X86Arg::Imm(total_len as u64)), 324 | X86::Mov(X86Arg::Reg(Reg::R11), 325 | X86Arg::Var(dest.clone()))]; 326 | // store count in first word 327 | instrs.extend_from_slice(&[ 328 | X86::Mov(X86Arg::RegOffset(Reg::R11, 0), 329 | X86Arg::Imm(elts.len() as u64)) 330 | ]); 331 | 332 | for (i, elt) in elts.iter().enumerate() { 333 | instrs.push( 334 | X86::Mov(X86Arg::RegOffset(Reg::R11, 335 | 8*(i+1) as i64), 336 | flat_arg_type(elt)) 337 | ); 338 | } 339 | 340 | // add 1 to indicate it is a tuple 341 | instrs.extend_from_slice(&[ 342 | X86::Add(X86Arg::Var(dest), X86Arg::Imm(1)) 343 | ]); 344 | 345 | instrs 346 | }, 347 | _ => { 348 | println!("{:?}", x); 349 | panic!("NYI") 350 | }, 351 | }, 352 | } 353 | }, 354 | Flat::Return(v) => { 355 | let val = flat_arg_type(&*v); 356 | return vec![X86::Mov(X86Arg::Reg(Reg::RAX), 357 | val)] 358 | }, 359 | Flat::If(cnd, thn, els) => { 360 | let (eq_left, eq_right) = match *cnd { 361 | x => match x { 362 | // https://github.com/rust-lang/rust/issues/16223 363 | Flat::Number(_) => (flat_arg_type(&x), X86Arg::Imm(CONST_TRUE)), 364 | Flat::Symbol(_) => (flat_arg_type(&x), X86Arg::Imm(CONST_TRUE)), 365 | _ => panic!("if cond needs to be Flat::EqP"), 366 | }, 367 | }; 368 | let mut thn_instrs = vec![]; 369 | for i in thn { 370 | let mut i_instrs = flat_to_px86(i); 371 | thn_instrs.append(&mut i_instrs); 372 | } 373 | let mut els_instrs = vec![]; 374 | for i in els { 375 | let mut i_instrs = flat_to_px86(i); 376 | els_instrs.append(&mut i_instrs); 377 | } 378 | return vec![X86::If(Box::new(X86::EqP(eq_left, eq_right)), 379 | thn_instrs, 380 | els_instrs)]; 381 | }, 382 | _ => panic!("NYI"), 383 | } 384 | } 385 | 386 | /// convert a Flat expression into pseudo-x86 instructions. pseudo-x86 387 | /// is like x86 but with if's and temporaries. It is also "unpatched" 388 | /// (see `patch_instructions`) 389 | pub fn select_instructions(flat_prog: FlatResult) -> X86 { 390 | 391 | match flat_prog { 392 | FlatResult::Define(name, args, assigns, mut vars) => 393 | { 394 | // TODO: if more than 6 args, spill args to stack 395 | assert!(args.len() <= 6); 396 | let mut move_args = vec![]; 397 | for (i, arg) in args.iter().enumerate() { 398 | move_args.push( 399 | X86::Mov(X86Arg::Var(arg.clone()), 400 | X86Arg::Reg(ARG_REG_ORDER[i].clone())) 401 | ); 402 | } 403 | 404 | let mut x86_instrs = move_args; 405 | for i in assigns { 406 | let mut i_instrs = flat_to_px86(i); 407 | x86_instrs.append(&mut i_instrs); 408 | } 409 | 410 | vars.extend_from_slice(&args); 411 | X86::Define(name, 412 | vars, 413 | x86_instrs) 414 | }, 415 | 416 | FlatResult::Prog(defs, main_assigns, main_vars) => { 417 | let mut x86_defines = vec![]; 418 | for def in defs { 419 | x86_defines.push(select_instructions(def)); 420 | } 421 | 422 | let mut x86_instrs = vec![]; 423 | for i in main_assigns { 424 | let mut i_instrs = flat_to_px86(i); 425 | x86_instrs.append(&mut i_instrs); 426 | } 427 | X86::Prog(x86_defines, x86_instrs, main_vars) 428 | }, 429 | _ => panic!("flat_prog is not a top-level Prog"), 430 | } 431 | } 432 | 433 | /// For an instruction, returns a 3-tuple: 434 | /// (variables used in instruction, variables read, variables written to) 435 | fn instruction_rw(instr: X86) -> (Vec>, Vec>, Vec>) { 436 | match instr { 437 | X86::Mov(X86Arg::Var(dest), X86Arg::Var(src)) => { 438 | (vec![dest.clone(), src.clone()], 439 | vec![src], 440 | vec![dest]) 441 | }, 442 | X86::Mov(X86Arg::Var(dest), _) => { 443 | (vec![dest.clone()], 444 | vec![], 445 | vec![dest]) 446 | }, 447 | X86::Mov(X86Arg::Reg(_), X86Arg::Var(src)) => { 448 | (vec![src.clone()], 449 | vec![src], 450 | vec![]) 451 | }, 452 | X86::Mov(X86Arg::RegOffset(_, _), X86Arg::Var(src)) => { 453 | (vec![src.clone()], 454 | vec![src], 455 | vec![]) 456 | }, 457 | X86::Mov(_, _) => { 458 | (vec![], vec![], vec![]) 459 | }, 460 | X86::MovZx(_, _) => { 461 | (vec![], vec![], vec![]) 462 | }, 463 | X86::Set(_, _) => { 464 | (vec![], vec![], vec![]) 465 | }, 466 | 467 | X86::Cmp(left, right) => { 468 | match (left, right) { 469 | (X86Arg::Var(l), X86Arg::Var(r)) => (vec![l.clone(), 470 | r.clone()], 471 | vec![l, r], 472 | vec![]), 473 | (X86Arg::Var(l), _) => (vec![l.clone()], 474 | vec![l], 475 | vec![]), 476 | (_, X86Arg::Var(r)) => (vec![r.clone()], 477 | vec![r], 478 | vec![]), 479 | (_, _) => (vec![], vec![], vec![]), 480 | } 481 | }, 482 | X86::Sub(X86Arg::Var(dest), X86Arg::Var(src)) | 483 | X86::Add(X86Arg::Var(dest), X86Arg::Var(src)) => { 484 | (vec![dest.clone(), src.clone()], 485 | vec![dest.clone(), src], 486 | vec![dest]) 487 | }, 488 | X86::And(X86Arg::Var(dest), X86Arg::Var(src)) => { 489 | (vec![dest.clone(), src.clone()], 490 | vec![dest.clone(), src], 491 | vec![dest]) 492 | }, 493 | X86::Sub(X86Arg::Var(dest), _) | 494 | X86::Add(X86Arg::Var(dest), _) => { 495 | (vec![dest.clone()], 496 | vec![dest.clone()], 497 | vec![dest]) 498 | }, 499 | X86::And(X86Arg::Var(dest), _) => { 500 | (vec![dest.clone()], 501 | vec![dest.clone()], 502 | vec![dest]) 503 | }, 504 | X86::Neg(X86Arg::Var(n)) => { 505 | (vec![n.clone()], 506 | vec![n.clone()], 507 | vec![n]) 508 | }, 509 | X86::Sub(X86Arg::Reg(_), X86Arg::Imm(_)) | 510 | X86::Add(X86Arg::GlobalVal(_), X86Arg::Imm(_)) | 511 | X86::And(X86Arg::Reg(_), X86Arg::Imm(_)) | 512 | X86::Push(_) | X86::Pop(_) | X86::Call(_) | X86::Jne(_) | X86::Je(_) | 513 | X86::Label(_) | X86::Jmp(_) => 514 | (vec![], vec![], vec![]), 515 | _ => panic!("NYI: {:?}", instr), 516 | } 517 | } 518 | 519 | 520 | /// Find live variables during each instruction. For `if`s, the live 521 | /// sets are embedded in the new list of instructions 522 | fn get_live_after_sets(mut instrs: Vec, lives: HashSet>) 523 | -> (HashSet>, Vec>>, Vec) { 524 | let mut live_of_next = lives.clone(); 525 | let mut live_after_sets = vec![]; 526 | let mut new_instrs = vec![]; 527 | 528 | instrs.reverse(); 529 | for instr in instrs { 530 | match instr { 531 | X86::If(cnd, thns, elss) => { 532 | let (thn_lives, thn_live_sets, new_thns) = 533 | get_live_after_sets(thns.clone(), live_of_next.clone()); 534 | let (els_lives, els_live_sets, new_elss) = 535 | get_live_after_sets(elss.clone(), live_of_next.clone()); 536 | let cond_vars = match *cnd.clone() { 537 | x => match x { 538 | // https://github.com/rust-lang/rust/issues/16223 539 | X86::EqP(left, right) => { 540 | match (left, right) { 541 | (X86Arg::Var(l), X86Arg::Var(r)) => vec![l, r], 542 | (X86Arg::Var(l), _) => vec![l], 543 | (_, X86Arg::Var(r)) => vec![r], 544 | _ => vec![], 545 | } 546 | }, 547 | _ => panic!("if cond needs to be EqP"), 548 | } 549 | }; 550 | 551 | let cond_vars : HashSet<_> = cond_vars.iter().cloned().collect(); 552 | 553 | let mut live = lives.clone(); 554 | live = live.union(&lives).cloned().collect(); 555 | live = live.union(&cond_vars).cloned().collect(); 556 | live = live.union(&thn_lives).cloned().collect(); 557 | live = live.union(&els_lives).cloned().collect(); 558 | 559 | live_of_next = live.clone(); 560 | live_after_sets.push(live); 561 | 562 | new_instrs.push(X86::IfWithLives( 563 | cnd, 564 | new_thns, thn_live_sets, 565 | new_elss, els_live_sets)); 566 | }, 567 | 568 | _ => { 569 | let (_, read_vars, written_vars) = 570 | instruction_rw(instr.clone()); 571 | let mut live = live_of_next.clone(); 572 | let written_vars_set : HashSet<_> = 573 | written_vars.iter().cloned().collect(); 574 | live = live.difference(&written_vars_set).cloned().collect(); 575 | let read_vars_set : HashSet<_> = read_vars.iter().cloned().collect(); 576 | live = live.union(&read_vars_set).cloned().collect(); 577 | 578 | live_of_next = live.clone(); 579 | live_after_sets.push(live); 580 | new_instrs.push(instr); 581 | }, 582 | } 583 | }; 584 | 585 | live_after_sets.reverse(); 586 | new_instrs.reverse(); 587 | (live_of_next, live_after_sets, new_instrs) 588 | } 589 | 590 | pub fn uncover_live(prog: X86) -> X86 { 591 | match prog { 592 | X86::Define(name, vars, instrs) => { 593 | let (_, live_sets, new_instrs) = get_live_after_sets(instrs, HashSet::new()); 594 | X86::DefineWithLives(name, vars, live_sets, new_instrs) 595 | }, 596 | 597 | X86::Prog(mut defs, instrs, vars) => { 598 | let (_, live_sets, new_instrs) = get_live_after_sets(instrs, HashSet::new()); 599 | 600 | defs = defs.iter().map(|def| uncover_live(def.clone())).collect(); 601 | X86::ProgWithLives(defs, 602 | new_instrs, 603 | vars, 604 | live_sets) 605 | }, 606 | _ => panic!("prog is not a top-level Prog"), 607 | } 608 | } 609 | 610 | /// For each variable, figure out the interval when it is live. Results 611 | /// are inserted into live_intervals. 612 | fn compute_live_intervals(instrs: &[X86], live_sets: Vec>>, 613 | live_intervals: &mut HashMap, (i32, i32)>, 614 | init_line_num: i32) { 615 | let mut line_num = init_line_num; 616 | let instr_live_sets : Vec<_> = instrs.iter().zip(live_sets).collect(); 617 | for (instr, live_set) in instr_live_sets { 618 | match (instr.clone(), live_set.clone()) { 619 | (X86::IfWithLives(_, thns, thn_lives, 620 | elss, els_lives), _) => { 621 | compute_live_intervals(&thns, thn_lives, live_intervals, line_num); 622 | compute_live_intervals(&elss, els_lives, live_intervals, line_num); 623 | line_num = line_num + thns.len() as i32 + elss.len() as i32; 624 | }, 625 | (_, _) => { 626 | for v in live_set { 627 | match live_intervals.get(&v) { 628 | Some(&(start, _)) => { 629 | live_intervals.insert(v, (start, line_num)); 630 | }, 631 | None => { 632 | live_intervals.insert(v, (line_num-1, line_num)); 633 | }, 634 | } 635 | } 636 | line_num += 1; 637 | }, 638 | } 639 | } 640 | } 641 | 642 | /// Allocate registers for variables. If it can't find a free 643 | /// register, the variable won't be present as a key in the returned 644 | /// hash-map 645 | fn allocate_registers(live_intervals: HashMap, (i32, i32)>) 646 | -> HashMap, i32> { 647 | let mut live_intervals_vec = vec![]; 648 | for (v, live_interval) in live_intervals { 649 | live_intervals_vec.push((v, live_interval)); 650 | } 651 | live_intervals_vec.sort_by_key(|interval| (interval.clone().1).0); 652 | 653 | let mut mapping : HashMap, i32> = HashMap::new(); 654 | let mut free : Vec = (0..REGS.len()).map(|i| i as i32).collect(); 655 | let mut active_intervals : HashSet<(Rc, (i32, i32))> = HashSet::new(); 656 | for (v, (start, end)) in live_intervals_vec { 657 | // clear done intervals from active_intervals, and free 658 | // registers allocated to them 659 | for (a, (astart, aend)) in active_intervals.clone() { 660 | if aend < start { 661 | active_intervals.remove(&(a.clone(), (astart, aend))); 662 | if let Some(reg) = mapping.get(&a.to_string()) { 663 | free.push(reg.clone()); 664 | } 665 | } 666 | } 667 | 668 | // allocate free register, if any. 669 | if !free.is_empty() { 670 | mapping.insert(v.clone(), free.pop().unwrap()); 671 | } 672 | 673 | // add current to active_intervals 674 | active_intervals.insert((v.clone(), (start, end))); 675 | } 676 | mapping 677 | } 678 | 679 | fn assign_homes_to_op2(locs: &HashMap, X86Arg>, 680 | dest: X86Arg, src: X86Arg) -> (X86Arg, X86Arg) { 681 | match (dest.clone(), src.clone()) { 682 | (X86Arg::Var(d), X86Arg::Var(s)) => 683 | (locs.get(&d).unwrap().clone(), 684 | locs.get(&s).unwrap().clone()), 685 | (X86Arg::Var(d), _) => { 686 | (locs.get(&d).unwrap().clone(), 687 | src) 688 | }, 689 | (_, X86Arg::Var(s)) => 690 | (dest, locs.get(&s).unwrap().clone()), 691 | (_, X86Arg::FuncName(_)) => { 692 | (dest, src) 693 | }, 694 | (X86Arg::RegOffset(_, _), X86Arg::Imm(_)) | 695 | (X86Arg::GlobalVal(_), X86Arg::Imm(_)) | 696 | (X86Arg::Imm(_), X86Arg::Imm(_)) | 697 | (X86Arg::Reg(_), _) | 698 | (X86Arg::RegOffset(_, _), X86Arg::GlobalVal(_))=> 699 | (dest, src), 700 | _ => panic!("unreachable: {:?}", (dest, src)), 701 | } 702 | } 703 | 704 | /// Given a list of instructions and mapping from vars to 705 | /// "homes"(register/stack location), return a new list of 706 | /// instructions with vars replaced with their assigned homes. 707 | fn assign_homes_to_instrs(instrs: Vec, locs: HashMap, X86Arg>) -> Vec { 708 | let mut new_instrs = vec![]; 709 | for i in instrs { 710 | match i { 711 | X86::IfWithLives(cnd, thn, _, els, _) => { 712 | let new_cnd = match *cnd { 713 | x => match x { 714 | // https://github.com/rust-lang/rust/issues/16223 715 | X86::EqP(left, right) => { 716 | let new_left = match left { 717 | X86Arg::Var(v) => locs.get(&v).unwrap().clone(), 718 | _ => left, 719 | }; 720 | X86::EqP(new_left, right) 721 | }, 722 | _ => panic!("if cond should be an EqP"), 723 | }, 724 | }; 725 | let new_thn = assign_homes_to_instrs(thn, locs.clone()); 726 | let new_els = assign_homes_to_instrs(els, locs.clone()); 727 | new_instrs.push( 728 | X86::If(Box::new(new_cnd), new_thn, new_els) 729 | ); 730 | }, 731 | X86::Mov(dest, src) => { 732 | let (new_dest, new_src) = assign_homes_to_op2(&locs, dest, src); 733 | new_instrs.push(X86::Mov(new_dest, new_src)) 734 | }, 735 | X86::MovZx(dest, src) => { 736 | let (new_dest, new_src) = assign_homes_to_op2(&locs, dest, src); 737 | new_instrs.push(X86::MovZx(new_dest, new_src)) 738 | }, 739 | X86::Add(dest, src) => { 740 | let (new_dest, new_src) = assign_homes_to_op2(&locs, dest, src); 741 | new_instrs.push(X86::Add(new_dest, new_src)) 742 | }, 743 | X86::And(dest, src) => { 744 | let (new_dest, new_src) = assign_homes_to_op2(&locs, dest, src); 745 | new_instrs.push(X86::And(new_dest, new_src)) 746 | }, 747 | X86::Cmp(left, right) => { 748 | let (new_left, new_right) = 749 | assign_homes_to_op2(&locs, left, right); 750 | new_instrs.push(X86::Cmp(new_left, new_right)) 751 | }, 752 | X86::Neg(n) => { 753 | let new_n = match n { 754 | X86Arg::Var(v) => locs.get(&v).unwrap().clone(), 755 | _ => n, 756 | }; 757 | 758 | new_instrs.push(X86::Neg(new_n)) 759 | } 760 | X86::Call(X86Arg::FuncName(ref fname)) => { 761 | match locs.get(&fname.clone()) { 762 | Some(home) => { 763 | new_instrs.push(X86::Call(home.clone())) 764 | }, 765 | _ => new_instrs.push(i.clone()), 766 | } 767 | }, 768 | X86::Set(X86Arg::Reg(_), _) | 769 | X86::Push(_) | X86::Pop(_) | 770 | X86::Sub(X86Arg::Reg(_), X86Arg::Imm(_)) | 771 | X86::Jmp(_) | X86::Jne(_) | X86::Je(_) | X86::Label(_) 772 | => { 773 | new_instrs.push(i); 774 | }, 775 | _ => panic!("NYI: {:?}", i), 776 | } 777 | }; 778 | 779 | new_instrs 780 | } 781 | 782 | fn decide_locs(vars: &[Rc], instrs: &[X86], 783 | live_sets: Vec>>) 784 | -> (HashMap, X86Arg>, i64) { 785 | let mut live_intervals = HashMap::new(); 786 | compute_live_intervals(instrs, 787 | live_sets, 788 | &mut live_intervals, 1); 789 | let reg_alloc = allocate_registers(live_intervals); 790 | let mut locs = HashMap::new(); 791 | let mut stack_size = 0; 792 | for var in vars { 793 | locs.insert( 794 | var.clone(), 795 | match reg_alloc.get(&var.to_string()) { 796 | Some(reg) => X86Arg::Reg(REGS[*reg as usize].clone()), 797 | None => { 798 | stack_size += 1; 799 | X86Arg::RegOffset(Reg::RBP, stack_size * -8) 800 | }, 801 | } 802 | ); 803 | }; 804 | 805 | (locs, stack_size) 806 | } 807 | 808 | pub fn assign_homes(prog: X86) -> X86 { 809 | match prog { 810 | X86::DefineWithLives(name, vars, live_sets, instrs) => { 811 | let (locs, stack_size) = decide_locs(&vars, &instrs, live_sets); 812 | X86::DefineWithStackSize(name, stack_size, 813 | assign_homes_to_instrs(instrs, locs)) 814 | }, 815 | 816 | X86::ProgWithLives(defs, instrs, vars, live_sets) => { 817 | let (locs, stack_size) = decide_locs(&vars, &instrs, live_sets); 818 | let mut new_defs = vec![]; 819 | for def in defs { 820 | new_defs.push(assign_homes(def)); 821 | } 822 | 823 | X86::ProgWithStackSize(new_defs, assign_homes_to_instrs(instrs, locs), stack_size) 824 | }, 825 | _ => panic!("assign_homes: not top level prog"), 826 | } 827 | } 828 | 829 | fn lower_if (instr: X86) -> Vec { 830 | match instr { 831 | X86::If(cnd, thn, els) => { 832 | let (eqp_left, eqp_right) = match *cnd { 833 | x => match x { 834 | // https://github.com/rust-lang/rust/issues/16223 835 | X86::EqP(left, right) => (left, right), 836 | _ => panic!("if cond is always EqP"), 837 | }, 838 | }; 839 | let thn_label = Rc::new(get_unique_varname("then")); 840 | let end_label = Rc::new(get_unique_varname("endif")); 841 | 842 | let mut new_elss = vec![]; 843 | for i in els { 844 | new_elss.extend_from_slice(&lower_if(i)); 845 | } 846 | let mut new_thns = vec![]; 847 | for i in thn { 848 | new_thns.extend_from_slice(&lower_if(i)); 849 | } 850 | 851 | let mut if_instrs = vec![ 852 | X86::Cmp(eqp_left, eqp_right), 853 | X86::JmpIf(CC::E, thn_label.clone()), 854 | ]; 855 | if_instrs.append(&mut new_elss); 856 | if_instrs.extend_from_slice(&[ 857 | X86::Jmp(end_label.clone()), 858 | X86::Label(thn_label), 859 | ]); 860 | if_instrs.append(&mut new_thns); 861 | if_instrs.extend_from_slice(&[ 862 | X86::Label(end_label), 863 | ]); 864 | 865 | if_instrs 866 | }, 867 | _ => vec![instr], 868 | } 869 | } 870 | 871 | /// Convert If's in pseudo-x86 to x86 jumps 872 | pub fn lower_conditionals(prog: X86) -> X86 { 873 | match prog { 874 | X86::DefineWithStackSize(name, stack_size, mut instrs) => { 875 | instrs = instrs.iter().flat_map(|i| lower_if(i.clone())).collect(); 876 | 877 | X86::DefineWithStackSize(name, stack_size, instrs) 878 | }, 879 | X86::ProgWithStackSize(mut defs, mut instrs, stack_size) => { 880 | instrs = instrs.iter().flat_map(|i| lower_if(i.clone())).collect(); 881 | defs = defs.iter().map(|d| lower_conditionals(d.clone())).collect(); 882 | 883 | X86::ProgWithStackSize(defs, instrs, stack_size) 884 | } 885 | _ => panic!("lower_conditionals: not top-level Prog"), 886 | } 887 | } 888 | 889 | 890 | fn patch_single_instr(instr: X86) -> Vec { 891 | match instr { 892 | // src and dest of Mov are same 893 | X86::Mov(ref dest, ref src) if src == dest => { 894 | vec![] 895 | }, 896 | // both source and dest are indirect addresses 897 | X86::Mov(X86Arg::RegOffset(dest_reg, dest), 898 | X86Arg::RegOffset(src_reg, src)) => { 899 | vec![X86::Mov(X86Arg::Reg(Reg::RAX), 900 | X86Arg::RegOffset(src_reg, src)), 901 | X86::Mov(X86Arg::RegOffset(dest_reg, dest), 902 | X86Arg::Reg(Reg::RAX))] 903 | }, 904 | X86::Mov(X86Arg::RegOffset(dest_reg, dest), 905 | X86Arg::FuncName(f)) => { 906 | vec![X86::Mov(X86Arg::Reg(Reg::RAX), 907 | X86Arg::FuncName(f)), 908 | X86::Mov(X86Arg::RegOffset(dest_reg, dest), 909 | X86Arg::Reg(Reg::RAX))] 910 | }, 911 | X86::MovZx(X86Arg::RegOffset(dest_reg, offset), 912 | src) => { 913 | vec![X86::MovZx(X86Arg::Reg(Reg::RAX), src), 914 | X86::Mov(X86Arg::RegOffset(dest_reg, offset), 915 | X86Arg::Reg(Reg::RAX))] 916 | }, 917 | // both source and dest are indirect addresses 918 | X86::Add(X86Arg::RegOffset(dest_reg, dest), 919 | X86Arg::RegOffset(src_reg, src)) => { 920 | vec![X86::Mov(X86Arg::Reg(Reg::RAX), 921 | X86Arg::RegOffset(dest_reg.clone(), dest)), 922 | X86::Add(X86Arg::Reg(Reg::RAX), 923 | X86Arg::RegOffset(src_reg, src)), 924 | X86::Mov(X86Arg::RegOffset(dest_reg, dest), 925 | X86Arg::Reg(Reg::RAX)) 926 | ] 927 | }, 928 | X86::Neg(X86Arg::RegOffset(reg, offset)) => { 929 | vec![X86::Mov(X86Arg::Reg(Reg::RAX), 930 | X86Arg::RegOffset(reg.clone(), offset)), 931 | X86::Neg(X86Arg::Reg(Reg::RAX)), 932 | X86::Mov(X86Arg::RegOffset(reg, offset), 933 | X86Arg::Reg(Reg::RAX))] 934 | }, 935 | // cmp can't take imm64 936 | X86::Cmp(X86Arg::Imm(i), right) => { 937 | vec![X86::Mov(X86Arg::Reg(Reg::RDX), X86Arg::Imm(i)), 938 | X86::Cmp(X86Arg::Reg(Reg::RDX), right)] 939 | }, 940 | X86::Cmp(left, X86Arg::Imm(i)) => { 941 | vec![X86::Mov(X86Arg::Reg(Reg::RDX), X86Arg::Imm(i)), 942 | X86::Cmp(left, X86Arg::Reg(Reg::RDX))] 943 | }, 944 | _ => vec![instr], 945 | } 946 | } 947 | 948 | /// Fix x86 instructions(eg. moves between two indirect addresses, etc) 949 | pub fn patch_instructions(prog: X86) -> X86 { 950 | match prog { 951 | X86::DefineWithStackSize(name, stack_size, instrs) => { 952 | let patched_instrs = 953 | instrs.iter().flat_map(|i| patch_single_instr(i.clone())).collect(); 954 | 955 | X86::DefineWithStackSize(name, 956 | stack_size, 957 | patched_instrs) 958 | }, 959 | X86::ProgWithStackSize(mut defs, instrs, stack_size) => { 960 | let patched_instrs = 961 | instrs.iter().flat_map(|i| patch_single_instr(i.clone())).collect(); 962 | 963 | defs = defs.iter().map(|d| patch_instructions(d.clone())).collect(); 964 | 965 | X86::ProgWithStackSize(defs, patched_instrs, stack_size) 966 | }, 967 | _ => panic!("patch_instructions: not top-level Prog"), 968 | } 969 | } 970 | -------------------------------------------------------------------------------- /tests/add.input: -------------------------------------------------------------------------------- 1 | (+ 2 3) 2 | -------------------------------------------------------------------------------- /tests/add.output: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /tests/add2.input: -------------------------------------------------------------------------------- 1 | (+ 3 (- 1)) 2 | -------------------------------------------------------------------------------- /tests/add2.output: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /tests/fibo.input: -------------------------------------------------------------------------------- 1 | (define (fibo x) 2 | ;; Get x-th Fibonacci number 3 | (if (< x 2) 4 | 1 5 | (+ (fibo (+ x (- 2))) 6 | (fibo (+ x (- 1)))))) 7 | 8 | (fibo 6) 9 | -------------------------------------------------------------------------------- /tests/fibo.output: -------------------------------------------------------------------------------- 1 | 13 2 | -------------------------------------------------------------------------------- /tests/func.input: -------------------------------------------------------------------------------- 1 | (define (foo x) 2 | x) 3 | 4 | (define (bar y) 5 | (+ 1 (foo 1))) 6 | 7 | (define (baz z) 8 | (+ z (bar z))) 9 | 10 | (baz 1) 11 | -------------------------------------------------------------------------------- /tests/func.output: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /tests/if.input: -------------------------------------------------------------------------------- 1 | (if (> 2 3) 2 | 42 3 | 12) 4 | -------------------------------------------------------------------------------- /tests/if.output: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /tests/lambda.input: -------------------------------------------------------------------------------- 1 | (define (adder x) 2 | (lambda (y) (+ x y))) 3 | 4 | (let ((add1 (adder 1))) 5 | (add1 40)) 6 | -------------------------------------------------------------------------------- /tests/lambda.output: -------------------------------------------------------------------------------- 1 | 41 2 | -------------------------------------------------------------------------------- /tests/neg.input: -------------------------------------------------------------------------------- 1 | (- 1) 2 | -------------------------------------------------------------------------------- /tests/neg.output: -------------------------------------------------------------------------------- 1 | -1 2 | -------------------------------------------------------------------------------- /tests/tuple1.input: -------------------------------------------------------------------------------- 1 | (tuple-ref (tuple 1 2 3) 1) 2 | -------------------------------------------------------------------------------- /tests/tuple1.output: -------------------------------------------------------------------------------- 1 | 2 2 | --------------------------------------------------------------------------------