Created
February 25, 2024 13:48
-
-
Save jakobrs/651df7b82166513e5ef72f320b0622bd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "idk" | |
version = "0.1.0" | |
edition = "2021" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
cranelift = "0.105.1" | |
cranelift-module = "0.105.1" | |
cranelift-object = "0.105.1" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use cranelift::prelude::*; | |
use cranelift_module::{DataDescription, Module}; | |
use cranelift_object::{ObjectBuilder, ObjectModule}; | |
#[derive(Copy, Clone)] | |
enum Token { | |
Right(usize), | |
Left(usize), | |
Add(usize), | |
Sub(usize), | |
Out, | |
In, | |
Start, | |
End, | |
} | |
fn compile(tokens: &[Token], target: &str) -> Vec<u8> { | |
let mut builder = cranelift::prelude::settings::builder(); | |
builder.enable("is_pic").unwrap(); | |
let shared_flags = settings::Flags::new(builder); | |
let target_isa = isa::lookup_by_name(target) | |
.unwrap() | |
.finish(shared_flags) | |
.unwrap(); | |
let object_builder = ObjectBuilder::new( | |
target_isa, | |
b"object", | |
cranelift_module::default_libcall_names(), | |
) | |
.unwrap(); | |
let mut module = ObjectModule::new(object_builder); | |
let mem = module | |
.declare_data("mem", cranelift_module::Linkage::Export, true, false) | |
.unwrap(); | |
let mut mem_descr = DataDescription::new(); | |
mem_descr.define_zeroinit(0x200_000); | |
module.define_data(mem, &mem_descr).unwrap(); | |
let mut ctx = module.make_context(); | |
let mut func_builder_ctx = FunctionBuilderContext::new(); | |
let pointer = module.target_config().pointer_type(); | |
let mut func_builder = FunctionBuilder::new(&mut ctx.func, &mut func_builder_ctx); | |
let block = func_builder.create_block(); | |
let mut block_starts = vec![]; | |
let mut block_skips = vec![]; | |
let ptr = Variable::new(1); | |
func_builder.switch_to_block(block); | |
func_builder.seal_block(block); | |
func_builder.declare_var(ptr, pointer); | |
let default_val = func_builder.ins().iconst(pointer, 0x100_000); | |
func_builder.def_var(ptr, default_val); | |
let mem_flags = MemFlags::trusted(); | |
let mem_locally = module.declare_data_in_func(mem, &mut func_builder.func); | |
let mem_addr = func_builder.ins().symbol_value(pointer, mem_locally); | |
let putchar; | |
let putchar_locally; | |
{ | |
let mut putchar_sig = module.make_signature(); | |
putchar_sig.params.push(AbiParam::new(types::I8)); | |
putchar = module | |
.declare_function("putchar", cranelift_module::Linkage::Import, &putchar_sig) | |
.unwrap(); | |
putchar_locally = module.declare_func_in_func(putchar, &mut func_builder.func); | |
} | |
let getchar; | |
let getchar_locally; | |
{ | |
let mut getchar_sig = module.make_signature(); | |
getchar_sig.returns.push(AbiParam::new(types::I8)); | |
getchar = module | |
.declare_function("getchar", cranelift_module::Linkage::Import, &getchar_sig) | |
.unwrap(); | |
getchar_locally = module.declare_func_in_func(getchar, &mut func_builder.func); | |
} | |
for &token in tokens { | |
let ptr_value = func_builder.use_var(ptr); | |
match token { | |
Token::Right(n) => { | |
let result = func_builder.ins().iadd_imm(ptr_value, n as i64); | |
func_builder.def_var(ptr, result); | |
} | |
Token::Left(n) => { | |
let result = func_builder.ins().iadd_imm(ptr_value, -(n as i64)); | |
func_builder.def_var(ptr, result); | |
} | |
Token::Add(n) => { | |
let new_pos = func_builder.ins().iadd(mem_addr, ptr_value); | |
let x = func_builder.ins().load(types::I8, mem_flags, new_pos, 0); | |
let y = func_builder.ins().iadd_imm(x, n as i64); | |
func_builder.ins().store(mem_flags, y, new_pos, 0); | |
} | |
Token::Sub(n) => { | |
let new_pos = func_builder.ins().iadd(mem_addr, ptr_value); | |
let x = func_builder.ins().load(types::I8, mem_flags, new_pos, 0); | |
let y = func_builder.ins().iadd_imm(x, -(n as i64)); | |
func_builder.ins().store(mem_flags, y, new_pos, 0); | |
} | |
Token::Out => { | |
let new_pos = func_builder.ins().iadd(mem_addr, ptr_value); | |
let x = func_builder.ins().load(types::I8, mem_flags, new_pos, 0); | |
func_builder.ins().call(putchar_locally, &[x]); | |
} | |
Token::In => { | |
let inst = func_builder.ins().call(getchar_locally, &[]); | |
let new_pos = func_builder.ins().iadd(mem_addr, ptr_value); | |
let x = func_builder.inst_results(inst)[0]; | |
func_builder.ins().store(mem_flags, x, new_pos, 0); | |
} | |
Token::Start => { | |
let new_block = func_builder.create_block(); | |
let skip_block = func_builder.create_block(); | |
let new_pos = func_builder.ins().iadd(mem_addr, ptr_value); | |
let x = func_builder.ins().load(types::I8, mem_flags, new_pos, 0); | |
func_builder.ins().brif(x, new_block, &[], skip_block, &[]); | |
block_starts.push(new_block); | |
block_skips.push(skip_block); | |
func_builder.switch_to_block(new_block); | |
} | |
Token::End => { | |
let new_pos = func_builder.ins().iadd(mem_addr, ptr_value); | |
let x = func_builder.ins().load(types::I8, mem_flags, new_pos, 0); | |
let this_block = block_starts.pop().unwrap(); | |
let new_block = block_skips.pop().unwrap(); | |
func_builder.ins().brif(x, this_block, &[], new_block, &[]); | |
func_builder.switch_to_block(new_block); | |
func_builder.seal_block(this_block); | |
func_builder.seal_block(new_block); | |
} | |
} | |
} | |
func_builder.ins().return_(&[]); | |
func_builder.finalize(); | |
let main_sig = module.make_signature(); | |
let main_func = module | |
.declare_function("main", cranelift_module::Linkage::Export, &main_sig) | |
.unwrap(); | |
module.define_function(main_func, &mut ctx).unwrap(); | |
module.clear_context(&mut ctx); | |
let object_product = module.finish(); | |
object_product.emit().unwrap() | |
} | |
fn validate(tokens: &[Token]) -> bool { | |
let mut n = 0isize; | |
for &token in tokens { | |
match token { | |
Token::Start => n += 1, | |
Token::End => { | |
n -= 1; | |
if n < 0 { | |
return false; | |
} | |
} | |
_ => (), | |
} | |
} | |
n == 0 | |
} | |
fn parse(mut text: &[u8]) -> Vec<Token> { | |
let mut tokens = vec![]; | |
while !text.is_empty() { | |
let ch = text[0]; | |
let mut j = 1; | |
while j < text.len() && text[j] == ch { | |
j += 1; | |
} | |
text = &text[j..]; | |
match ch { | |
b'<' => tokens.push(Token::Left(j)), | |
b'>' => tokens.push(Token::Right(j)), | |
b'+' => tokens.push(Token::Add(j)), | |
b'-' => tokens.push(Token::Sub(j)), | |
b'.' => tokens.extend((0..j).map(|_| Token::Out)), | |
b',' => tokens.extend((0..j).map(|_| Token::In)), | |
b'[' => tokens.extend((0..j).map(|_| Token::Start)), | |
b']' => tokens.extend((0..j).map(|_| Token::End)), | |
_ => (), | |
} | |
} | |
tokens | |
} | |
fn main() { | |
let target = "x86_64-unknown-linux"; | |
let text = std::fs::read("code").unwrap(); | |
let tokens = parse(&text); | |
assert!(validate(&tokens), "Invalid code"); | |
let obj = compile(&tokens, target); | |
std::fs::write("main.o", &obj).unwrap(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment