Explorar o código

added c-transpiling

Nicolas Winkler %!s(int64=5) %!d(string=hai) anos
pai
achega
3351535ce8
Modificáronse 7 ficheiros con 441 adicións e 104 borrados
  1. 59 26
      Cargo.lock
  2. 2 2
      Cargo.toml
  3. 40 33
      src/compile.rs
  4. 99 1
      src/ir.rs
  5. 15 12
      src/main.rs
  6. 118 30
      src/optimize.rs
  7. 108 0
      src/transpile_c.rs

+ 59 - 26
Cargo.lock

@@ -1,37 +1,41 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
 [[package]]
 name = "bitflags"
-version = "1.0.4"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "byteorder"
-version = "1.2.6"
+version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "dynasm"
-version = "0.2.3"
+version = "0.5.2"
 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)",
+ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dynasmrt"
-version = "0.2.3"
+version = "0.5.2"
 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)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "lazy_static"
-version = "0.2.11"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -41,7 +45,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "memmap"
-version = "0.6.2"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -50,21 +54,42 @@ dependencies = [
 
 [[package]]
 name = "owning_ref"
-version = "0.3.3"
+version = "0.4.0"
 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 = "proc-macro2"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.8 (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"
+name = "syn"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "typed-arena"
@@ -72,6 +97,11 @@ version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "unicode-xid"
+version = "0.2.0"
+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"
@@ -94,24 +124,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 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)",
+ "dynasm 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dynasmrt 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.6 (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 bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
+"checksum dynasm 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "42a814e1edeb85dd2a3c6fc0d6bf76d02ca5695d438c70ecee3d90774f3259c5"
+"checksum dynasmrt 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a393aaeb4441a48bcf47b5b6155971f82cc1eb77e22855403ccc0415ac8328d"
+"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 "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 memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
+"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
+"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
+"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
 "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 syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
 "checksum typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6c06a92aef38bb4dc5b0df00d68496fc31307c5344c867bb61678c6e1671ec5"
+"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
 "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"

+ 2 - 2
Cargo.toml

@@ -9,7 +9,7 @@ edition = "2018"
 #[dependencies.x86asm]
 #path = "rust-x86asm"
 [dependencies]
-dynasm = "*"
-dynasmrt = "*"
+dynasm = "0.5.2"
+dynasmrt = "0.5.2"
 winapi = "*"
 typed-arena = "1.4.1"

+ 40 - 33
src/compile.rs

@@ -1,23 +1,32 @@
 use std::i64;
-use super::ir;
+use super::{ir, optimize};
 use std::io::{Write, Read};
 use std::mem;
-use super::ir::{MutVisitor, Instruction};
+use super::ir::{ConstVisitor, Instruction};
 
 #[cfg(target_os = "windows")]
 use winapi::um::memoryapi::VirtualAlloc;
 #[cfg(target_os = "windows")]
 use winapi::um::winnt::{MEM_COMMIT, PAGE_EXECUTE_READWRITE};
-
 use dynasmrt::{DynasmApi, DynasmLabelApi};
 
-pub fn compile(mut instrs: Vec<ir::Instruction>) -> Vec<u8> {
+pub enum Storation {
+    Register(&'static str),
+    Stack(i64),
+}
+
+pub fn compile_cfg<'a>(cfg: Vec<optimize::DfInstr<'a>>) -> Box<fn (*mut u8) -> ()> {
+    Box::new(|_| {})
+}
+
+
+pub fn compile(instrs: &Vec<ir::Instruction>) -> Vec<u8> {
     let mut cg = CodeGenerator::new();
     cg.initialize();
 
     let entry = cg.buffer.offset();
 
-    cg.visit_instructions(&mut instrs);
+    cg.visit_instructions(instrs);
     cg.buffer.commit();
     cg.finalize();
     let buf = cg.buffer.finalize().unwrap();
@@ -30,10 +39,10 @@ pub fn compile(mut instrs: Vec<ir::Instruction>) -> Vec<u8> {
         mem::transmute(buf.ptr(entry))
     };
 
-    let mut data: Vec<u8> = Vec::with_capacity(100000);
+    //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]>()));
+        function(std::alloc::alloc_zeroed(std::alloc::Layout::new::<[u8; 100000]>()));
     }
 
     //cg.into_vec()
@@ -80,37 +89,37 @@ impl CodeGenerator {
     }
 }
 
-impl ir::MutVisitor for CodeGenerator {
+impl ir::ConstVisitor for CodeGenerator {
     type Ret = ();
 
-    fn visit_nop(&mut self, nop: &mut Instruction) {
+    fn visit_nop(&mut self, nop: &Instruction) {
     }
 
-    fn visit_add(&mut self, add: &'_ mut Instruction) {
+    fn visit_add(&mut self, add: &'_ Instruction) {
         if let Instruction::Add{ offset, value } = add {
             dynasm!(self.buffer
-                ; add BYTE [rdi + rsi + *offset as i32], *value as i8
+                ; add BYTE [rdi + *offset as i32], *value as i8
             );
         }
     }
 
-    fn visit_set(&mut self, set: &'_ mut Instruction) {
+    fn visit_set(&mut self, set: &'_ Instruction) {
         if let Instruction::Set{ offset, value } = set {
             dynasm!(self.buffer
-                ; mov BYTE [rdi + rsi + *offset as i32], *value as i8
+                ; mov BYTE [rdi + *offset as i32], *value as i8
             );
         }
     }
 
-    fn visit_linear_loop(&mut self, l: &mut Instruction) {
+    fn visit_linear_loop(&mut self, l: &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]
+                    ; mov cl, BYTE [rdi]
                 );
             }
-            for (&offset, &mut factor) in factors {
+            for (&offset, &factor) in factors {
                 if offset == 0 {
                     continue;
                 }
@@ -119,71 +128,69 @@ impl ir::MutVisitor for CodeGenerator {
                 }
                 else if factor == 1 {
                     dynasm!(self.buffer
-                        ; add BYTE [rdi + rsi + offset as i32], cl
+                        ; add BYTE [rdi + offset as i32], cl
                     );
                 }
                 else if factor == -1 {
                     dynasm!(self.buffer
-                        ; sub BYTE [rdi + rsi + offset as i32], cl
+                        ; sub BYTE [rdi + 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
+                        ; add BYTE [rdi + 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
+                        ; sub BYTE [rdi + offset as i32], bl
                     );
                 }
                 else {
                     dynasm!(self.buffer
                         ; mov al, factor as i8
                         ; mul cl
-                        ; add BYTE [rdi + rsi + offset as i32], al
+                        ; add BYTE [rdi + offset as i32], al
                     );
                 }
             }
             dynasm!(self.buffer
-                ; mov BYTE [rdi + rsi], 0
+                ; mov BYTE [rdi], 0
             );
         }
     }
 
-    fn visit_move_ptr(&mut self, mp: &'_ mut Instruction) {
+    fn visit_move_ptr(&mut self, mp: &Instruction) {
         if let Instruction::MovePtr(offset) = mp {
             dynasm!(self.buffer
-                ; add rsi, DWORD *offset as i32
+                ; lea rdi, [rdi + *offset as i32]
             );
         }
     }
 
-    fn visit_loop(&mut self, l: &mut Instruction) {
+    fn visit_loop(&mut self, l: &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
+                ; cmp BYTE [rdi], 0
                 ; jz => end
                 ; => begin
             );
             self.visit_instructions(insts);
             dynasm!(self.buffer
-                ; mov al, BYTE [rdi + rsi]
-                ; test al, al
+                ; cmp BYTE [rdi], 0
                 ; jnz => begin
                 ; => end
             );
         }
     }
     
-    fn visit_read(&mut self, r: &mut Instruction) {
+    fn visit_read(&mut self, r: &Instruction) {
         if let Instruction::Read(offset) = r {
             dynasm!(self.buffer
                 ; push rdi
@@ -194,18 +201,18 @@ impl ir::MutVisitor for CodeGenerator {
                 ; add rsp, 24
                 ; pop rsi
                 ; pop rdi
-                ; mov BYTE [rdi + rsi + *offset as i32], al
+                ; mov BYTE [rdi + *offset as i32], al
             );
         }
     }
 
-    fn visit_write(&mut self, w: &mut Instruction) {
+    fn visit_write(&mut self, w: &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 dil, BYTE [rdi + *offset as i32]
                 ; mov rax, QWORD putbyte as _
                 ; call rax
                 ; add rsp, 24

+ 99 - 1
src/ir.rs

@@ -12,7 +12,46 @@ pub enum Instruction {
     Write(i64)
 }
 
-
+impl Instruction {
+    pub fn to_string(&self) -> String {
+        use self::Instruction::*;
+        match self {
+            Nop => "Nop".to_string(),
+            Add{ offset, value } => {
+                if *offset == 0 {
+                    if *value == 1 {
+                        "Inc".to_string()
+                    }
+                    else if *value == -1 {
+                        "Dec".to_string()
+                    }
+                    else {
+                        format!("Add(@{}, {})", offset, value)
+                    }
+                } 
+                else {
+                    format!("Add(@{}, {})", offset, value)
+                }
+            },
+            Set{ offset, value } => format!("Set(@{}, {})", offset, value),
+            LinearLoop(map) => {
+                "LinearLoop".to_string()
+            },
+            MovePtr(val) => format!("MovePtr({})", val),
+            Loop(instrs) => {
+                let mut ret = "[\n".to_string();
+                for instr in instrs {
+                    ret += &instr.to_string();
+                    ret += "\n";
+                }
+                ret += "]\n";
+                ret
+            },
+            Read(offset) => format!("Read(@{})", offset),
+            Write(offset) => format!("Read(@{})", offset),
+        }
+    }
+}
 
 pub trait MutVisitor {
     type Ret: Default;
@@ -73,4 +112,63 @@ pub trait MutVisitor {
     }
 }
 
+pub trait ConstVisitor {
+    type Ret: Default;
+
+    fn visit_instructions(&mut self, instr: &Vec<Instruction>) {
+        for inst in instr {
+            self.walk_instruction(inst);
+        }
+    }
+
+    fn visit_nop(&mut self, nop: &Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn visit_add(&mut self, add: &Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn visit_set(&mut self, add: &Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn visit_linear_loop(&mut self, lloop: &Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn visit_move_ptr(&mut self, move_ptr: &Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn visit_loop(&mut self, l: &Instruction) -> Self::Ret {
+        if let Instruction::Loop(instrs) = l {
+            self.visit_instructions(instrs);
+        }
+        Self::Ret::default()
+    }
+
+    fn visit_read(&mut self, read: &Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+    
+    fn visit_write(&mut self, write: &Instruction) -> Self::Ret {
+        Self::Ret::default()
+    }
+
+    fn walk_instruction(&mut self, inst: &Instruction) -> Self::Ret {
+        use self::Instruction::*;
+        match inst {
+            Nop => self.visit_nop(inst),
+            Add {offset: _, value: _} => self.visit_add(inst),
+            Set {offset: _, value: _} => self.visit_set(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),
+        }
+    }
+}
+
 

+ 15 - 12
src/main.rs

@@ -1,8 +1,8 @@
-#![feature(plugin)]
-#![plugin(dynasm)]
-
-//#[macro_use]
-//extern crate dynasm;
+//#![feature(plugin)]
+//#![plugin(dynasm)]
+#![feature(proc_macro_hygiene)]
+#[macro_use]
+extern crate dynasm;
 
 extern crate winapi;
 extern crate typed_arena;
@@ -11,11 +11,15 @@ use std::io::{self, Read};
 use std::fs::File;
 use std::env;
 
+use dynasm::dynasm;
+use dynasmrt::{DynasmApi, DynasmLabelApi};
+
 pub mod ir;
 pub mod parser;
 pub mod interpret;
 pub mod optimize;
 pub mod compile;
+pub mod transpile_c;
 
 use crate::ir::MutVisitor;
 
@@ -33,15 +37,14 @@ fn main() -> io::Result<()> {
     let insts = parser::parse(&buffer);
     if let Ok(mut insts) = insts {
         let mut lin_loop_optimizer = optimize::Optimizer::new();
-        //println!("code: {:#?}", insts);
         lin_loop_optimizer.visit_instructions(&mut insts);
-        //println!("code: {:#?}", insts);
-
-        //interpret::run(&insts);
-        let code = compile::compile(insts);
-
+        
+        for ref inst in &insts {
+            //println!("{}\n", inst.to_string());
+        }
+        //println!("{}", transpile_c::transpile_c(&insts));
 
-        //println!("{:?}", code.into_iter().map(|x| format!("{:x}", x)).collect::<Vec<String>>());
+        let code = compile::compile(&insts);
     }
     else if let Err(msg) = insts {
         println!("error parsing: {}", msg);

+ 118 - 30
src/optimize.rs

@@ -1,61 +1,139 @@
-
+use std::cell::{Cell, RefCell};
 use std::collections::BTreeMap;
-use super::ir;
+use super::{ir, compile};
 use super::ir::Instruction;
 use typed_arena::Arena;
 
 pub struct DfgOptimizer<'a> {
     dfg: DataflowGraph<'a>,
-    tape_state: TapeState<'a>,
+    cell_states: BTreeMap<i64, DfgNode<'a>>,
+    cfg: Vec<DfInstr<'a>>,
 }
 
 struct DataflowGraph<'a> {
-    nodes: Arena<DfgNode<'a>>
+    arena: Arena<DfgNode<'a>>,
+}
+
+pub struct DfgNode<'a> {
+    storation: Option<compile::Storation>,
+    kind: DfgNodeKind<'a>,
 }
 
-enum DfgNode<'a> {
+pub enum DfgNodeKind<'a> {
     Offset(i64),
-    ConstAdd(&'a Cell<DfgNode<'a>>),
+    ConstAdd(&'a DfgNode<'a>),
     Const(i64),
-    AddMultiplied(&'a Cell<DfgNode<'a>>, i64, &'a Cell<DfgNode<'a>>),
+    AddMultiplied(&'a DfgNode<'a>, i64, &'a DfgNode<'a>),
+    Read(),
 }
 
-struct TapeState<'a> {
-    pub cell_states: BTreeMap<i64, DfgNode<'a>>
+pub enum DfInstr<'a> {
+    Print(&'a RefCell<DfgNode<'a>>),
+    WriteMem(i64, &'a DfgNode<'a>),
+    Loop(i64, Vec<DfInstr<'a>>),
 }
 
-pub struct Optimizer {
+impl<'a> DfgNode<'a> {
+    pub fn new(kind: DfgNodeKind<'a>) -> Self {
+        DfgNode {
+            storation: None,
+            kind: kind
+        }
+    }
 }
 
-impl TapeState<'a> {
-    fn add(&'a mut self, offset: i64, value: i64) {
-        if let Some(cell) = cell_state {
-            let new_cell = match cell {
-                CellState::Value(val) => CellState::Value(*val + value),
-                CellState::Added(val) => CellState::Added(*val + value)
-            };
-            std::mem::replace(cell, new_cell);
-        }
-        else {
-            self.cell_states.insert(offset, CellState::Added(value));
+impl<'a> DfgOptimizer<'a> {
+}
+
+impl<'a> ir::MutVisitor for DfgOptimizer<'a> {
+    type Ret = ();
+
+    fn visit_instructions(&mut self, instr: &mut Vec<Instruction>) {
+        for inst in instr {
+            self.walk_instruction(inst);
         }
     }
 
-    fn set(&mut self, offset: i64, value: i64) {
-        let cell_state = self.cell_states.get_mut(&offset);
-        if let Some(cell) = cell_state {
-            std::mem::replace(cell, CellState::Value(value));
+    fn visit_add(&mut self, add: &mut Instruction) {
+        if let Instruction::Add{ offset, value } = add {
+            let arena = &self.dfg.arena;
+            let load = RefCell::new(arena.alloc(DfgNode::new(DfgNodeKind::Offset(*offset))));
+            //let addition: &'a _ = arena.alloc(DfgNode::new(DfgNodeKind::ConstAdd(load)));
+            //self.cfg.push(DfInstr::WriteMem(*offset, addition));
         }
-        else {
-            self.cell_states.insert(offset, CellState::Value(value));
+    }
+
+    fn visit_set(&mut self, set: &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));
+            }
+            // set cell at offset 0 to 0
         }
     }
 
-    fn get(&self, offset: i64) -> Option<&CellState> {
-        self.cell_states.get(&offset)
+    fn visit_read(&mut self, read: &'_ mut Instruction) {
+    }
+
+    fn visit_write(&mut self, write: &'_ mut Instruction) {
     }
 }
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+pub struct Optimizer {
+}
+
 impl Optimizer {
     pub fn new() -> Self {
         Optimizer {
@@ -106,9 +184,19 @@ impl ir::MutVisitor for Optimizer {
                 }
             }
 
-            if !dirty && increments.get(&0) == Some(&-1) {
+            if !dirty && increments.len() == 1 {
+                if let Some(&v) = increments.get(&0) {
+                    if v % 2 != 0 {
+                        // cases like [-]
+                        // also [---]
+                        std::mem::replace(l, Instruction::Set{ offset: 0, value: 0 });
+                    }
+                }
+            }
+            else if !dirty && increments.get(&0) == Some(&-1) {
                 std::mem::replace(l, Instruction::LinearLoop(increments));
             }
+
             // set cell at offset 0 to 0
         }
     }

+ 108 - 0
src/transpile_c.rs

@@ -0,0 +1,108 @@
+
+use super::{ir, optimize};
+
+use ir::Instruction;
+use ir::ConstVisitor;
+
+struct Transpiler {
+    pub code: String
+}
+
+
+pub fn transpile_c(instrs: &Vec<ir::Instruction>) -> String {
+    let mut transpiler = Transpiler::default();
+    transpiler.visit_instructions(instrs);
+    transpiler.finalize();
+    return transpiler.code;
+}
+
+
+impl Default for Transpiler {
+    fn default() -> Self {
+        let mut transpiler = Transpiler{ code: "".to_string() };
+
+        transpiler.code += r#"#include <stdio.h>
+#include <stdlib.h>
+int main() {
+    unsigned char* buffer = calloc(2000000000, 1);
+    buffer += 1000000000;
+"#;
+        transpiler
+    }
+}
+
+impl Transpiler {
+    pub fn finalize(&mut self) {
+        self.code += "}\n";
+    }
+}
+
+
+impl ir::ConstVisitor for Transpiler {
+    type Ret = ();
+
+    fn visit_nop(&mut self, nop: &Instruction) {
+        self.code += "\n";
+    }
+
+    fn visit_add(&mut self, add: &'_ Instruction) {
+        if let Instruction::Add{ offset, value } = add {
+            self.code += &format!("buffer[{}] += {};\n", offset, value);
+        }
+    }
+
+    fn visit_set(&mut self, set: &'_ Instruction) {
+        if let Instruction::Set{ offset, value } = set {
+            self.code += &format!("buffer[{}] = {};\n", offset, value);
+        }
+    }
+
+    fn visit_linear_loop(&mut self, l: &Instruction) {
+        if let Instruction::LinearLoop(factors) = l {
+            for (&offset, &factor) in factors {
+                if offset == 0 {
+                    continue;
+                }
+
+                if factor == 0 {
+                }
+                else if factor == 1 {
+                    self.code += &format!("buffer[{}] += buffer[0];\n", offset);
+                }
+                else if factor == -1 {
+                    self.code += &format!("buffer[{}] -= buffer[0];\n", offset);
+                }
+                else {
+                    self.code += &format!("buffer[{}] += {} * buffer[0];\n", offset, factor);
+                }
+            }
+            self.code += "buffer[0] = 0;\n";
+        }
+    }
+
+    fn visit_move_ptr(&mut self, mp: &'_ Instruction) {
+        if let Instruction::MovePtr(offset) = mp {
+            self.code += &format!("buffer += {};\n", offset);
+        }
+    }
+
+    fn visit_loop(&mut self, l: &Instruction) {
+        if let Instruction::Loop(insts) = l {
+            self.code += "while(buffer[0]) {\n";
+            self.visit_instructions(insts);
+            self.code += "}\n";
+        }
+    }
+    
+    fn visit_read(&mut self, r: &Instruction) {
+        if let Instruction::Read(offset) = r {
+            self.code += &format!("buffer[{}] = getchar();\n", offset);
+        }
+    }
+
+    fn visit_write(&mut self, w: &Instruction) {
+        if let Instruction::Write(offset) = w {
+            self.code += &format!("putchar(buffer[{}]);\n", offset);
+        }
+    }
+}