Преглед на файлове

implemented aot-compiler

Nicolas Winkler преди 6 години
родител
ревизия
5be850bdde
променени са 12 файла, в които са добавени 478 реда и са изтрити 7 реда
  1. 105 0
      Cargo.lock
  2. 6 0
      Cargo.toml
  3. BIN
      src/.interpret.rs.swp
  4. BIN
      src/.ir.rs.swp
  5. BIN
      src/.lowering.rs.swp
  6. BIN
      src/.main.rs.swp
  7. BIN
      src/.parser.rs.swp
  8. 218 0
      src/compile.rs
  9. 9 2
      src/interpret.rs
  10. 50 2
      src/ir.rs
  11. 30 3
      src/main.rs
  12. 60 0
      src/optimize.rs

+ 105 - 0
Cargo.lock

@@ -1,4 +1,109 @@
 [[package]]
+name = "bitflags"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "byteorder"
+version = "1.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "dynasm"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "dynasmrt"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "lazy_static"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "memmap"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "owning_ref"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "take_mut"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "zombie"
 version = "0.1.0"
+dependencies = [
+ "dynasm 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dynasmrt 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
+[metadata]
+"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
+"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781"
+"checksum dynasm 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "29d7cb708c99b82d551fabe7ff2fdecb99ba41b831084803958e2dc0fe0ad66e"
+"checksum dynasmrt 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cecfc9019e3f0c585f2bad0ca008073031900c50f369398c3a26728b336e326e"
+"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
+"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
+"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
+"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
+"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
+"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
+"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 6 - 0
Cargo.toml

@@ -4,4 +4,10 @@ version = "0.1.0"
 authors = ["Nicolas Winkler <nicolas.winkler@gmx.ch>"]
 edition = "2018"
 
+#[dependencies.assembler]
+#path = "assembler/workspace/assembler"
+#[dependencies.x86asm]
+#path = "rust-x86asm"
 [dependencies]
+dynasm = "*"
+dynasmrt = "*"

BIN
src/.interpret.rs.swp


BIN
src/.ir.rs.swp


BIN
src/.lowering.rs.swp


BIN
src/.main.rs.swp


BIN
src/.parser.rs.swp


+ 218 - 0
src/compile.rs

@@ -0,0 +1,218 @@
+use std::i64;
+use super::ir;
+use std::io::{Write, Read};
+use std::mem;
+use super::ir::{MutVisitor, Instruction};
+
+
+use dynasmrt::{DynasmApi, DynasmLabelApi};
+
+pub fn compile(mut instrs: Vec<ir::Instruction>) -> Vec<u8> {
+    /*let mut ops = dynasmrt::x64::Assembler::new().unwrap();
+    let string = "Hello World!";
+
+    dynasm!(ops
+        ; ->hello:
+        ; .bytes string.as_bytes()
+    );
+
+    let hello = ops.offset();
+    dynasm!(ops
+        ; lea rcx, [->hello]
+        ; xor edx, edx
+        ; mov dl, BYTE string.len() as _
+        ; sub rsp, BYTE 0x28
+        ; call rax
+        ; add rsp, BYTE 0x28
+        ; ret
+    );
+
+    let buf = ops.finalize().unwrap();
+    buf.to_vec()
+    */
+    let mut cg = CodeGenerator::new();
+    cg.initialize();
+
+    let entry = cg.buffer.offset();
+
+    cg.visit_instructions(&mut instrs);
+    cg.finalize();
+    let buf = cg.buffer.finalize().unwrap();
+
+    let ret = buf.to_vec();
+    //println!("{:02x?}", ret);
+
+    let function: extern "C" fn(memory: *mut u8) -> bool = unsafe {
+        mem::transmute(buf.ptr(entry))
+    };
+
+    let mut data: Vec<u8> = Vec::with_capacity(100000);
+    unsafe {
+        //function(&mut *data.into_boxed_slice().as_mut_ptr() as *mut u8);
+        function(std::alloc::alloc_zeroed(std::alloc::Layout::new::<[u8; 1000]>()));
+    }
+
+    //cg.into_vec()
+    ret
+}
+
+pub struct CodeGenerator {
+    pub buffer: dynasmrt::x64::Assembler
+}
+
+impl CodeGenerator {
+    pub fn new() -> Self {
+        CodeGenerator {
+            buffer: dynasmrt::x64::Assembler::new().unwrap()
+        }
+    }
+
+    pub fn initialize(&mut self) {
+        dynasm!(self.buffer
+            ; xor rsi, rsi
+        );
+    }
+
+    pub fn finalize(&mut self) {
+        dynasm!(self.buffer
+            ; ret
+        );
+    }
+}
+
+impl ir::MutVisitor for CodeGenerator {
+    type Ret = ();
+
+    fn visit_add(&mut self, add: &'_ mut Instruction) {
+        if let Instruction::Add{ offset, value } = add {
+            dynasm!(self.buffer
+                ; add [rdi + rsi + *offset as i32], BYTE *value as i8
+            );
+        }
+    }
+
+    fn visit_move_ptr(&mut self, mp: &'_ mut Instruction) {
+        if let Instruction::MovePtr(offset) = mp {
+            dynasm!(self.buffer
+                ; add rsi, DWORD *offset as i32
+            );
+        }
+    }
+
+    fn visit_loop(&mut self, l: &mut Instruction) {
+        if let Instruction::Loop(insts) = l {
+            let begin = self.buffer.new_dynamic_label();
+            let end = self.buffer.new_dynamic_label();
+            dynasm!(self.buffer
+                ; mov al, BYTE [rdi + rsi]
+                ; test al, al
+                ; jz => end
+                ; => begin
+            );
+            self.visit_instructions(insts);
+            dynasm!(self.buffer
+                ; mov al, BYTE [rdi + rsi]
+                ; test al, al
+                ; jnz => begin 
+                ; => end 
+            );
+        }
+    }
+
+    fn visit_linear_loop(&mut self, l: &mut Instruction) {
+        if let Instruction::LinearLoop(factors) = l {
+            if factors.len() > 1 ||
+                factors.len() >= 1 && !factors.contains_key(&0) {
+                dynasm!(self.buffer
+                    ; mov cl, BYTE [rdi + rsi]
+                );
+            }
+            for (&offset, &mut factor) in factors {
+                if offset == 0 {
+                    continue;
+                }
+
+                if factor == 0 {
+                }
+                else if factor == 1 {
+                    dynasm!(self.buffer
+                        ; add BYTE [rdi + rsi + offset as i32], cl
+                    );
+                }
+                else if factor == -1 {
+                    dynasm!(self.buffer
+                        ; sub BYTE [rdi + rsi + offset as i32], cl
+                    );
+                }
+                else if factor.count_ones() == 1 {
+                    dynasm!(self.buffer
+                        ; mov bl, cl
+                        ; shl bl, factor.trailing_zeros() as i8
+                        ; add BYTE [rdi + rsi + offset as i32], bl
+                    );
+                }
+                else if (-factor).count_ones() == 1 {
+                    dynasm!(self.buffer
+                        ; mov bl, cl
+                        ; shl bl, factor.trailing_zeros() as i8
+                        ; sub BYTE [rdi + rsi + offset as i32], bl
+                    );
+                }
+                else {
+                    dynasm!(self.buffer
+                        ; mov al, factor as i8
+                        ; mul cl
+                        ; add BYTE [rdi + rsi + offset as i32], al
+                    );
+                }
+            }
+            dynasm!(self.buffer
+                ; mov BYTE [rdi + rsi], 0
+            );
+        }
+    }
+
+    fn visit_write(&mut self, w: &mut Instruction) {
+        if let Instruction::Write(offset) = w {
+            dynasm!(self.buffer
+                ; push rdi
+                ; push rsi
+                ; sub rsp, 24
+                ; mov dil, BYTE [rdi + rsi + *offset as i32]
+                ; mov rax, QWORD putbyte as _
+                ; call rax
+                ; add rsp, 24
+                ; pop rsi
+                ; pop rdi
+            );
+        }
+    }
+
+    fn visit_read(&mut self, r: &mut Instruction) {
+        if let Instruction::Read(offset) = r {
+            dynasm!(self.buffer
+                ; push rdi
+                ; push rsi
+                ; sub rsp, 24
+                ; mov rax, QWORD readbyte as _
+                ; call rax
+                ; add rsp, 24
+                ; pop rsi
+                ; pop rdi
+                ; mov BYTE [rdi + rsi + *offset as i32], al
+            );
+        }
+    }
+}
+
+extern "C" fn putbyte(chr: u8) {
+    //print!("{:?}", chr as char);
+    std::io::stdout().write(&[chr]);
+}
+
+extern "C" fn readbyte() -> u8 {
+    let mut byte: u8 = 0;
+    //std::io::stdin().read(&mut [byte]).unwrap();
+    std::io::stdin().bytes().next().unwrap_or(Ok(0)).unwrap_or(0)
+}
+

+ 9 - 2
src/interpret.rs

@@ -42,8 +42,15 @@ fn run_instrs(instructions: &Vec<Instruction>, data: &mut Data) {
                 let cell = data.memory[(data.ptr + offset) as usize % len];
                 io::stdout().write(&[cell]).unwrap();
                 io::stdout().flush().unwrap();
-            }
-            _ => {}
+            },
+            Instruction::LinearLoop(factors) => {
+                assert_eq!(factors.get(&0), Some(&-1));
+                let multiplicator = data.memory[(data.ptr as usize) % len];
+                for (offset, value) in factors {
+                    let cell = &mut data.memory[(data.ptr + offset) as usize % len];
+                    *cell = cell.wrapping_add(multiplicator.wrapping_mul(*value as u8));
+                }
+            },
         }
     }
 }

+ 50 - 2
src/ir.rs

@@ -1,9 +1,9 @@
-
 use std::collections::BTreeMap;
 
+#[derive(Debug)]
 pub enum Instruction {
     Add{ offset: i64, value: i64 },
-    LinearLoop{ offset: i64, increment: i64, factors: BTreeMap<i64, i64> },
+    LinearLoop(BTreeMap<i64, i64>),
     MovePtr(i64),
     Loop(Vec<Instruction>),
     Read(i64),
@@ -12,5 +12,53 @@ pub enum Instruction {
 
 
 
+pub trait MutVisitor {
+    type Ret: Default;
+
+    fn visit_instructions(&mut self, instr: &mut Vec<Instruction>) {
+        for inst in instr {
+            self.walk_instruction(inst);
+        }
+    }
+
+    fn visit_add(&mut self, add: &mut Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn visit_linear_loop(&mut self, lloop: &mut Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn visit_move_ptr(&mut self, move_ptr: &mut Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn visit_loop(&mut self, l: &mut Instruction) -> Self::Ret {
+        if let Instruction::Loop(instrs) = l {
+            self.visit_instructions(instrs);
+        }
+        Self::Ret::default()
+    }
+
+    fn visit_read(&mut self, read: &mut Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+    
+    fn visit_write(&mut self, write: &mut Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn walk_instruction(&mut self, inst: &mut Instruction) -> Self::Ret {
+        use self::Instruction::*;
+        match inst {
+            Add {offset: _, value: _} => self.visit_add(inst),
+            LinearLoop (_) => self.visit_linear_loop(inst),
+            MovePtr(_) => self.visit_move_ptr(inst),
+            Loop(_) => self.visit_loop(inst),
+            Read(_) => self.visit_read(inst),
+            Write(_) => self.visit_write(inst),
+        }
+    }
+}
 
 

+ 30 - 3
src/main.rs

@@ -1,16 +1,43 @@
+#![feature(plugin)]
+#![plugin(dynasm)]
+
+//#[macro_use]
+//extern crate dynasm;
+
 use std::io::{self, Read};
+use std::fs::File;
+use std::env;
 
 pub mod ir;
 pub mod parser;
 pub mod interpret;
+pub mod optimize;
+pub mod compile;
+
+use crate::ir::MutVisitor;
 
 fn main() -> io::Result<()> {
+    let args: Vec<String> = env::args().collect();
     let mut buffer = String::new();
-    io::stdin().read_to_string(&mut buffer)?;
+
+    if args.len() > 1 {
+        File::open(&args[1])?.read_to_string(&mut buffer)?;
+    }
+    else {
+        io::stdin().read_to_string(&mut buffer)?;
+    }
 
     let insts = parser::parse(&buffer);
-    if let Ok(insts) = insts {
-        interpret::run(&insts);
+    if let Ok(mut insts) = insts {
+        let mut lin_loop_optimizer = optimize::LoopLinearizer;
+        //println!("code: {:#?}", insts);
+        lin_loop_optimizer.visit_instructions(&mut insts);
+        //println!("code: {:#?}", insts);
+
+        //interpret::run(&insts);
+        let code = compile::compile(insts);
+        
+        //println!("{:?}", code.into_iter().map(|x| format!("{:x}", x)).collect::<Vec<String>>());
     }
     else if let Err(msg) = insts {
         println!("error parsing: {}", msg);

+ 60 - 0
src/optimize.rs

@@ -0,0 +1,60 @@
+
+use std::collections::BTreeMap;
+use super::ir;
+use super::ir::Instruction;
+
+
+pub struct LoopLinearizer;
+
+impl ir::MutVisitor for LoopLinearizer {
+    type Ret = ();
+
+    fn visit_instructions(&mut self, instr: &'_ mut Vec<Instruction>) {
+        for inst in instr {
+            self.walk_instruction(inst);
+        }
+    }
+
+    fn visit_add(&mut self, add: &'_ mut Instruction) {
+    }
+
+    fn visit_linear_loop(&mut self, lloop: &'_ mut Instruction) {
+    }
+
+    fn visit_move_ptr(&mut self, move_ptr: &'_ mut Instruction) {
+    }
+
+    fn visit_loop(&mut self, l: &mut Instruction) {
+        if let Instruction::Loop(instrs) = l {
+            let mut increments: BTreeMap<i64, i64> = BTreeMap::new();
+            let mut dirty = false;
+            for inst in instrs {
+                self.walk_instruction(inst);
+                if !dirty {
+                    use super::ir::Instruction::*;
+                    match inst {
+                        Add { offset, value } => {
+                            match increments.get_mut(offset) {
+                                Some(v) => *v += *value,
+                                None => { increments.insert(*offset, *value); },
+                            }
+                        },
+                        _ => {
+                            dirty = true;
+                        }
+                    }
+                }
+            }
+
+            if !dirty && increments.get(&0) == Some(&-1) {
+                std::mem::replace(l, Instruction::LinearLoop(increments));
+            }
+        }
+    }
+
+    fn visit_read(&mut self, read: &'_ mut Instruction) {
+    }
+
+    fn visit_write(&mut self, write: &'_ mut Instruction) {
+    }
+}