Skip to content

Instantly share code, notes, and snippets.

Created January 22, 2013 02:34
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/4591596 to your computer and use it in GitHub Desktop.
Save anonymous/4591596 to your computer and use it in GitHub Desktop.
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