Skip to content

Instantly share code, notes, and snippets.

@jakobrs
Created February 25, 2024 13:48
Show Gist options
  • Save jakobrs/651df7b82166513e5ef72f320b0622bd to your computer and use it in GitHub Desktop.
Save jakobrs/651df7b82166513e5ef72f320b0622bd to your computer and use it in GitHub Desktop.
[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"
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