Created
January 22, 2013 02:34
-
-
Save anonymous/4591596 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
require 'llvm/core' | |
require 'llvm/execution_engine' | |
require 'llvm/transforms/scalar' | |
class Generator | |
attr_accessor :ptr | |
def build(code,name, mod) | |
mod.functions.add(name, [], LLVM::Int) do |f| | |
entry= f.basic_blocks.append("entry") | |
init_loop = f.basic_blocks.append("init loop") | |
init_body = f.basic_blocks.append("init body") | |
body = f.basic_blocks.append("body") | |
@putchar = mod.functions.add("putchar", [LLVM::Int], LLVM::Int) | |
entry.build do |builder| | |
@offset = builder.alloca(LLVM::Int) | |
@data = builder.array_alloca(LLVM::Int, LLVM::Int(1000)) | |
builder.store(LLVM::Int(0), @offset) #initialize offset in the data | |
builder.br init_loop | |
end | |
init_loop.build do |builder| #loop that initializes all data to 0 | |
builder.cond( builder.icmp(:eq, builder.load(@offset), LLVM::Int(1000)), body, init_body) | |
end | |
init_body.build do |builder| | |
builder.store(LLVM::Int(0), builder.gep(@data, [builder.load(@offset)])) #initialize one filed | |
right(builder) #move ptr to rigth | |
builder.br init_loop #initialize next field | |
end | |
body.build do |builder| | |
builder.store(LLVM::Int(500), @offset) | |
code_str = parse(code) | |
puts code_str.inspect | |
builder = code_gen(code_str,f, builder) | |
builder.ret(deref(builder)) | |
end | |
end | |
end | |
def parse(data) | |
data = data.gsub(/[^\[\]\-+,.<>]/,"") | |
md = data.match(/\A(?<beg>[^\[]+)\[(?<in>.*)\](?<out>[^\[]+)\Z/) | |
if md | |
return md[:beg].split("") + [parse(md[:in])] + md[:out].split("") | |
end | |
return data.split("") | |
end | |
def code_gen(code,f, builder) | |
code.each do |instr| | |
case instr | |
when Array then builder = loop_gen(instr,f, builder) | |
when ">" then right(builder) | |
when "<" then left(builder) | |
when "+" then inc(builder) | |
when "-" then dec(builder) | |
when "." then put(builder) | |
end | |
end | |
return builder | |
end | |
def loop_gen(substr,f, builder) | |
loop_head = f.basic_blocks.append("loop head") | |
loop_body = f.basic_blocks.append("loop body") | |
loop_next = f.basic_blocks.append("loop next") | |
builder.br(loop_head) | |
builder.position_at_end(loop_head) | |
builder.cond( builder.icmp(:eq, deref(builder) , LLVM::Int(0)), loop_next, loop_body) | |
loop_body.build do |b| | |
b = code_gen(substr, f, b) | |
b.br(loop_head) | |
end | |
builder.position_at_end(loop_next) | |
return builder | |
end | |
def put(builder) builder.call(@putchar, deref(builder)) end | |
def offs(b) return b.gep(@data,[b.load(@offset)]) end | |
def deref(b) return b.load(offs(b)) end | |
def store(b,val) return b.store(val,offs(b)) end | |
def inc(builder) store(builder, builder.add( deref(builder), LLVM::Int(1))) end | |
def dec(builder) store(builder, builder.sub( deref(builder), LLVM::Int(1))) end | |
def right(builder) | |
builder.store(builder.add(builder.load(@offset),LLVM::Int(1)), @offset) | |
end | |
def left(builder) | |
builder.store(builder.sub(builder.load(@offset),LLVM::Int(1)), @offset) | |
end | |
end | |
LLVM.init_x86 | |
mod = LLVM::Module.new("brainfuck") | |
gen = Generator.new | |
halloworld = <<EOF | |
++++++++++ [ >+++++++>++++++++++>+++>+<<<<- ] | |
>++.>+.+++++++..+++.>++.<<+++++++++++++++. | |
>.+++.------.--------.>+.>.+++. | |
EOF | |
fn = gen.build(halloworld,"main",mod) | |
mod.verify | |
puts "compiling to native" | |
mod.write_bitcode(File.open("test.bc","w")) | |
system("llc test.bc") | |
system("gcc test.s -o test.out") | |
puts "making jit" | |
jit = LLVM::JITCompiler.new(mod) | |
jit.run_function(mod.functions["main"]).to_i |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment