Permalink
Browse files

First import

  • Loading branch information...
0 parents commit 162305c6bd09eb2e6d45e4734a49e51c5aad2153 @tombagby committed Aug 21, 2008
Showing with 1,071 additions and 0 deletions.
  1. +21 −0 COPYING
  2. +45 −0 README
  3. +14 −0 extconf.rb
  4. +206 −0 llvm_basicblock.cpp
  5. BIN llvm_basicblock.o
  6. +83 −0 llvm_function.cpp
  7. BIN llvm_function.o
  8. +39 −0 llvm_module.cpp
  9. BIN llvm_module.o
  10. +64 −0 llvm_value.cpp
  11. BIN llvm_value.o
  12. +115 −0 llvmruby.c
  13. +24 −0 llvmruby.h
  14. BIN llvmruby.o
  15. +1 −0 mkmf
  16. +459 −0 test.rb
21 COPYING
@@ -0,0 +1,21 @@
+Copyright (c) 2008 Thomas Bagby
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
45 README
@@ -0,0 +1,45 @@
+* What's LLVMRuby
+
+LLVMRuby is a set of bindings making the LLVM compiler infrastructure
+(http://llvm.org) usable from Ruby. This extention allows using LLVM
+as an abstract assembler and reflects a good chunk of the LLVM class
+hierarchy into Ruby. Included is an example of using this to built
+a simple JIT compiler, written entirely in Ruby, which is able to
+interact with the native Ruby 1.8/1.9 data types.
+
+* How to build
+
+You must get and build LLVM seperately, available for download at:
+
+ http://llvm.org/releases
+
+Add the llvm bin directory to your path, extconf needs to be able to find llvm-conf:
+
+ $ export PATH=$PATH:/$LLVMDIR/Debug/bin
+
+Once you have built LLVM, run extconf.rb giving it location of LLVM:
+
+ $ ruby extconf.rb --with-llvm-include=/$DIR/llvm/include --with-llvm-lib=/$DIR/llvm/Debug/lib
+
+Run make
+
+ $ make
+
+Look in test.rb to see examples of use and start messing around.
+
+* Caveats
+
+I created this for version 2.3 of LLVM. Other versions may not work.
+I have only been using this on 64bit machines. I know for a fact that
+the example JIT assumes that you are using 64bit Ruby. These should
+be quite easy to change in the Ruby code, but I have no machine to
+test that on.
+
+* Copying
+
+See the file COPYING
+
+* Author
+
+For questions or answers, my email is: tomatobagby@gmail.com
+
14 extconf.rb
@@ -0,0 +1,14 @@
+require 'mkmf'
+
+extension_name = 'llvmruby'
+
+dir_config(extension_name)
+
+have_library('stdc++')
+
+dir_config('llvm')
+
+with_ldflags(`llvm-config --libs all`) do
+ create_makefile(extension_name)
+end
+
206 llvm_basicblock.cpp
@@ -0,0 +1,206 @@
+#include "llvmruby.h"
+
+extern VALUE cLLVMBasicBlock;
+extern VALUE cLLVMBuilder;
+
+extern "C" {
+VALUE llvm_basic_block_wrap(BasicBlock* bb) {
+ return Data_Wrap_Struct(cLLVMBasicBlock, NULL, NULL, bb);
+}
+
+VALUE llvm_basic_block_builder(VALUE self) {
+ BasicBlock* bb;
+ Data_Get_Struct(self, BasicBlock, bb);
+ IRBuilder<> *builder = new IRBuilder<>(bb);
+ return Data_Wrap_Struct(cLLVMBuilder, NULL, NULL, builder);
+}
+
+VALUE llvm_builder_create_add(VALUE self, VALUE rv1, VALUE rv2) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v1, *v2;
+ Data_Get_Struct(rv1, Value, v1);
+ Data_Get_Struct(rv2, Value, v2);
+
+ Value *res = builder->CreateBinOp(Instruction::Add, v1, v2);
+ return llvm_value_wrap(res);
+}
+
+VALUE llvm_builder_create_sub(VALUE self, VALUE rv1, VALUE rv2) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v1, *v2;
+ Data_Get_Struct(rv1, Value, v1);
+ Data_Get_Struct(rv2, Value, v2);
+
+ Value *res = builder->CreateBinOp(Instruction::Sub, v1, v2);
+ return llvm_value_wrap(res);
+}
+
+VALUE llvm_builder_create_mul(VALUE self, VALUE rv1, VALUE rv2) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v1, *v2;
+ Data_Get_Struct(rv1, Value, v1);
+ Data_Get_Struct(rv2, Value, v2);
+
+ Value *res = builder->CreateBinOp(Instruction::Mul, v1, v2);
+ return llvm_value_wrap(res);
+}
+
+VALUE llvm_builder_create_xor(VALUE self, VALUE rv1, VALUE rv2) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v1, *v2;
+ Data_Get_Struct(rv1, Value, v1);
+ Data_Get_Struct(rv2, Value, v2);
+
+ Value *res = builder->CreateBinOp(Instruction::Xor, v1, v2);
+ return llvm_value_wrap(res);
+}
+
+VALUE llvm_builder_create_and(VALUE self, VALUE rv1, VALUE rv2) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v1, *v2;
+ Data_Get_Struct(rv1, Value, v1);
+ Data_Get_Struct(rv2, Value, v2);
+
+ Value *res = builder->CreateBinOp(Instruction::And, v1, v2);
+ return llvm_value_wrap(res);
+}
+
+VALUE llvm_builder_create_shl(VALUE self, VALUE rv1, VALUE rv2) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v1, *v2;
+ Data_Get_Struct(rv1, Value, v1);
+ Data_Get_Struct(rv2, Value, v2);
+
+ Value *res = builder->CreateBinOp(Instruction::Shl, v1, v2);
+ return llvm_value_wrap(res);
+}
+
+VALUE llvm_builder_create_lshr(VALUE self, VALUE rv1, VALUE rv2) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v1, *v2;
+ Data_Get_Struct(rv1, Value, v1);
+ Data_Get_Struct(rv2, Value, v2);
+
+ Value *res = builder->CreateBinOp(Instruction::LShr, v1, v2);
+ return llvm_value_wrap(res);
+}
+
+VALUE llvm_builder_create_return(VALUE self, VALUE rv) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v;
+ Data_Get_Struct(rv, Value, v);
+ return llvm_value_wrap(builder->CreateRet(v));
+}
+
+VALUE llvm_builder_create_br(VALUE self, VALUE rblock) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ BasicBlock *bb;
+ Data_Get_Struct(rblock, BasicBlock, bb);
+ return llvm_value_wrap(builder->CreateBr(bb));
+}
+
+VALUE llvm_builder_create_cond_br(VALUE self, VALUE rcond, VALUE rtrue_block, VALUE rfalse_block) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *cond;
+ Data_Get_Struct(rcond, Value, cond);
+
+ BasicBlock *true_block, *false_block;
+ Data_Get_Struct(rtrue_block, BasicBlock, true_block);
+ Data_Get_Struct(rfalse_block, BasicBlock, false_block);
+
+ return llvm_value_wrap(builder->CreateCondBr(cond, true_block, false_block));
+}
+
+VALUE llvm_builder_create_alloca(VALUE self, VALUE rtype, VALUE rsize) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ const Type* type;
+ Data_Get_Struct(rtype, Type, type);
+
+ Value *size = ConstantInt::get(Type::Int32Ty, FIX2INT(rsize));
+ Value *v = builder->CreateAlloca(type, size);
+ return llvm_value_wrap(v);
+}
+
+VALUE llvm_builder_create_load(VALUE self, VALUE rptr) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *ptr;
+ Data_Get_Struct(rptr, Value, ptr);
+ return llvm_value_wrap(builder->CreateLoad(ptr));
+}
+
+VALUE llvm_builder_create_store(VALUE self, VALUE rv, VALUE rptr) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *v, *ptr;
+ Data_Get_Struct(rv, Value, v);
+ Data_Get_Struct(rptr, Value, ptr);
+ return llvm_value_wrap(builder->CreateStore(v, ptr));
+}
+
+VALUE llvm_builder_create_icmpeq(VALUE self, VALUE rlhs, VALUE rrhs) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *lhs, *rhs;
+ Data_Get_Struct(rlhs, Value, lhs);
+ Data_Get_Struct(rrhs, Value, rhs);
+ return llvm_value_wrap(builder->CreateICmpEQ(lhs, rhs));
+}
+
+VALUE llvm_builder_create_gep(VALUE self, VALUE rptr, VALUE ridx) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *ptr, *idx;
+ Data_Get_Struct(rptr, Value, ptr);
+ Data_Get_Struct(ridx, Value, idx);
+ return llvm_value_wrap(builder->CreateGEP(ptr, idx));
+}
+
+VALUE llvm_builder_create_struct_gep(VALUE self, VALUE rptr, VALUE ridx) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *ptr;
+ Data_Get_Struct(rptr, Value, ptr);
+ return llvm_value_wrap(builder->CreateStructGEP(ptr, FIX2INT(ridx)));
+}
+
+VALUE llvm_builder_create_int_to_ptr(VALUE self, VALUE ri, VALUE rtype) {
+ IRBuilder<>* builder;
+ Data_Get_Struct(self, IRBuilder<>, builder);
+
+ Value *i;
+ Data_Get_Struct(ri, Value, i);
+
+ const Type* type;
+ Data_Get_Struct(rtype, Type, type);
+
+ return llvm_value_wrap(builder->CreateIntToPtr(i, type));
+}
+}
BIN llvm_basicblock.o
Binary file not shown.
83 llvm_function.cpp
@@ -0,0 +1,83 @@
+#include "llvmruby.h"
+
+typedef struct {
+ Module *M;
+ Function* F;
+ long(*FP)(long);
+} llvm_function_t;
+
+extern "C" {
+void llvm_function_free(llvm_function_t* data) { delete data; }
+VALUE llvm_function_allocate(VALUE klass) {
+ return Data_Wrap_Struct(klass, NULL, llvm_function_free, new llvm_function_t);
+}
+
+VALUE llvm_function_call(VALUE self, VALUE n) {
+ llvm_function_t* data;
+ Data_Get_Struct(self, llvm_function_t, data);
+ return INT2NUM(data->FP(FIX2INT(n)));
+}
+
+VALUE llvm_function_call2(VALUE self, VALUE n) {
+ llvm_function_t* data;
+ Data_Get_Struct(self, llvm_function_t, data);
+ return data->FP(n);
+}
+
+VALUE llvm_function_compile(VALUE self) {
+ cout << "Compiling!\n";
+
+ llvm_function_t* data;
+ Data_Get_Struct(self, llvm_function_t, data);
+
+/*
+ PassManager p;
+ p.add(new TargetData(data->M));
+ p.add(createVerifierPass());
+ p.add(createLowerSetJmpPass());
+ p.add(createRaiseAllocationsPass());
+ p.add(createCFGSimplificationPass());
+ p.add(createPromoteMemoryToRegisterPass());
+ p.add(createGlobalOptimizerPass());
+ p.add(createGlobalDCEPass());
+ p.add(createFunctionInliningPass());
+ p.run(*data->M);
+*/
+
+ ExistingModuleProvider *MP = new ExistingModuleProvider(data->M);
+ ExecutionEngine *EE = ExecutionEngine::create(MP, false);
+
+ std::cerr << "verifying... ";
+ if (verifyModule(*data->M)) {
+ std::cerr << "Error constructing function!\n";
+ }
+ std::cerr << "\n" << *data->M;
+ data->FP = (long(*)(long))EE->getPointerToFunction(data->F);
+ return Qnil;
+}
+
+VALUE llvm_function_initialize(VALUE self) {
+ llvm_function_t* data;
+ Data_Get_Struct(self, llvm_function_t, data);
+
+ Module *M = new Module("jit_test");
+ data->M = M;
+ data->F = cast<Function>(M->getOrInsertFunction("fib", Type::Int64Ty, Type::Int64Ty, (Type *)0));
+
+ return self;
+}
+
+VALUE llvm_function_create_block(VALUE self) {
+ llvm_function_t* data;
+ Data_Get_Struct(self, llvm_function_t, data);
+ BasicBlock *bb = BasicBlock::Create("bb", data->F);
+ return llvm_basic_block_wrap(bb);
+}
+
+VALUE llvm_function_argument(VALUE self) {
+ llvm_function_t* data;
+ Data_Get_Struct(self, llvm_function_t, data);
+ Value *arg = data->F->arg_begin();
+ return llvm_value_wrap(arg);
+}
+}
BIN llvm_function.o
Binary file not shown.
39 llvm_module.cpp
@@ -0,0 +1,39 @@
+#define __STDC_LIMIT_MACROS
+
+#include "llvm/Module.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Constants.h"
+#include "llvm/Instructions.h"
+#include "llvm/ModuleProvider.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/ExecutionEngine/Interpreter.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
+#include <iostream>
+using namespace llvm;
+
+#include "ruby.h"
+
+typedef struct {
+ Module *M;
+} llvm_module_t;
+
+
+extern "C" void llvm_module_free(llvm_module_t* data) {
+ cout << "Freeing some crap! " << data->M << "\n";
+ if(data->M != NULL) delete data->M;
+ cout << "FREED A FUCKIN MODULE\n";
+ delete data;
+}
+
+extern "C" VALUE llvm_module_allocate(VALUE klass) {
+ cout << "Allocating module space\n";
+ return Data_Wrap_Struct(klass, NULL, llvm_module_free, new llvm_module_t);
+}
+
+extern "C" VALUE llvm_module_initialize(VALUE self) {
+ llvm_module_t* data;
+ Data_Get_Struct(self, llvm_module_t, data);
+ data->M = new Module("jit_test");
+ return self;
+}
BIN llvm_module.o
Binary file not shown.
64 llvm_value.cpp
@@ -0,0 +1,64 @@
+#include "llvmruby.h"
+
+extern VALUE cLLVMType;
+extern VALUE cLLVMPointerType;
+extern VALUE cLLVMStructType;
+extern VALUE cLLVMArrayType;
+extern VALUE cLLVMVectorType;
+extern VALUE cLLVMValue;
+
+extern "C" {
+VALUE llvm_value_wrap(Value* v) {
+ return Data_Wrap_Struct(cLLVMValue, NULL, NULL, v);
+}
+
+VALUE llvm_value_get_constant(VALUE self, VALUE v) {
+ return llvm_value_wrap(ConstantInt::get(Type::Int64Ty, FIX2INT(v)));
+}
+
+VALUE llvm_type_pointer(VALUE self, VALUE rtype) {
+ Type *type;
+ Data_Get_Struct(rtype, Type, type);
+ Type* ptr_type = PointerType::getUnqual(type);
+ return Data_Wrap_Struct(cLLVMPointerType, NULL, NULL, ptr_type);
+}
+
+VALUE llvm_type_struct(VALUE self, VALUE rtypes, VALUE rpacked) {
+ std::vector<const Type*> types;
+
+ for(int i = 0; i < RARRAY_LEN(rtypes); ++i) {
+ VALUE v = RARRAY_PTR(rtypes)[i];
+ const Type *t;
+ Data_Get_Struct(v, Type, t);
+ types.push_back(t);
+ }
+ StructType *s = StructType::get(types);
+ return Data_Wrap_Struct(cLLVMStructType, NULL, NULL, s);
+}
+
+VALUE llvm_type_array(VALUE self, VALUE rtype, VALUE size) {
+ Type *type;
+ Data_Get_Struct(rtype, Type, type);
+ type = ArrayType::get(type, FIX2INT(size));
+ return Data_Wrap_Struct(cLLVMArrayType, NULL, NULL, type);
+}
+
+VALUE llvm_type_vector(VALUE self, VALUE rtype, VALUE size) {
+ Type *type;
+ Data_Get_Struct(rtype, Type, type);
+ type = ArrayType::get(type, FIX2INT(size));
+ return Data_Wrap_Struct(cLLVMVectorType, NULL, NULL, type);
+}
+
+void init_types() {
+ rb_define_const(cLLVMType, "Int1Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<IntegerType*>(Type::Int1Ty)));
+ rb_define_const(cLLVMType, "Int8Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<IntegerType*>(Type::Int8Ty)));
+ rb_define_const(cLLVMType, "Int16Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<IntegerType*>(Type::Int16Ty)));
+ rb_define_const(cLLVMType, "Int32Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<IntegerType*>(Type::Int32Ty)));
+ rb_define_const(cLLVMType, "Int64Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<IntegerType*>(Type::Int64Ty)));
+ rb_define_const(cLLVMType, "VoidTy", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<Type*>(Type::VoidTy)));
+ rb_define_const(cLLVMType, "LabelTy", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<Type*>(Type::LabelTy)));
+ rb_define_const(cLLVMType, "FloatTy", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<Type*>(Type::FloatTy)));
+ rb_define_const(cLLVMType, "DoubleTy", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast<Type*>(Type::DoubleTy)));
+}
+}
BIN llvm_value.o
Binary file not shown.
115 llvmruby.c
@@ -0,0 +1,115 @@
+#include "ruby.h"
+
+VALUE cLLVMRuby = Qnil;
+VALUE cLLVMValue = Qnil;
+VALUE cLLVMModule = Qnil;
+VALUE cLLVMFunction = Qnil;
+VALUE cLLVMBasicBlock = Qnil;
+VALUE cLLVMBuilder = Qnil;
+VALUE cLLVMType = Qnil;
+VALUE cLLVMPointerType = Qnil;
+VALUE cLLVMStructType = Qnil;
+VALUE cLLVMArrayType = Qnil;
+VALUE cLLVMVectorType = Qnil;
+
+void init_types();
+VALUE llvm_type_pointer(VALUE, VALUE);
+VALUE llvm_type_struct(VALUE, VALUE, VALUE);
+VALUE llvm_type_array(VALUE, VALUE, VALUE);
+VALUE llvm_type_vector(VALUE, VALUE, VALUE);
+
+VALUE llvm_module_allocate(VALUE);
+VALUE llvm_module_initialize(VALUE);
+
+VALUE llvm_function_allocate(VALUE);
+VALUE llvm_function_initialize(VALUE);
+VALUE llvm_function_create_block(VALUE);
+VALUE llvm_function_compile(VALUE);
+VALUE llvm_function_call(VALUE, VALUE);
+VALUE llvm_function_call2(VALUE, VALUE);
+VALUE llvm_function_argument(VALUE);
+
+VALUE llvm_basic_block_builder(VALUE);
+
+VALUE llvm_builder_create_add(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_sub(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_mul(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_and(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_xor(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_shl(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_lshr(VALUE, VALUE, VALUE);
+
+VALUE llvm_builder_create_return(VALUE, VALUE);
+VALUE llvm_builder_create_br(VALUE, VALUE);
+VALUE llvm_builder_create_cond_br(VALUE, VALUE, VALUE, VALUE);
+
+VALUE llvm_builder_create_alloca(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_load(VALUE, VALUE);
+VALUE llvm_builder_create_store(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_icmpeq(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_gep(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_struct_gep(VALUE, VALUE, VALUE);
+VALUE llvm_builder_create_int_to_ptr(VALUE, VALUE, VALUE);
+
+VALUE llvm_value_get_constant(VALUE);
+
+void Init_llvmruby() {
+ cLLVMRuby = rb_define_module("LLVM");
+
+ cLLVMType = rb_define_class_under(cLLVMRuby, "Type", rb_cObject);
+ cLLVMPointerType = rb_define_class_under(cLLVMRuby, "PointerType", cLLVMType);
+ cLLVMStructType = rb_define_class_under(cLLVMRuby, "StructType", cLLVMType);
+ cLLVMArrayType = rb_define_class_under(cLLVMRuby, "ArrayType", cLLVMType);
+ cLLVMVectorType = rb_define_class_under(cLLVMRuby, "VectorType", cLLVMType);
+
+ cLLVMValue = rb_define_class_under(cLLVMRuby, "Value", rb_cObject);
+ cLLVMModule = rb_define_class_under(cLLVMRuby, "Module", rb_cObject);
+ cLLVMFunction = rb_define_class_under(cLLVMRuby, "Function", rb_cObject);
+ cLLVMBasicBlock = rb_define_class_under(cLLVMRuby, "BasicBlock", cLLVMValue);
+ cLLVMBuilder = rb_define_class_under(cLLVMRuby, "Builder", rb_cObject);
+
+ init_types();
+ rb_define_module_function(cLLVMType, "pointer", llvm_type_pointer, 1);
+ rb_define_module_function(cLLVMType, "struct", llvm_type_struct, 1);
+ rb_define_module_function(cLLVMType, "array", llvm_type_array, 2);
+ rb_define_module_function(cLLVMType, "vector", llvm_type_vector, 2);
+
+ rb_define_module_function(cLLVMValue, "get_constant", llvm_value_get_constant, 1);
+
+ rb_define_alloc_func(cLLVMModule, llvm_module_allocate);
+ rb_define_method(cLLVMModule, "initialize", llvm_module_initialize, 0);
+
+ rb_define_alloc_func(cLLVMFunction, llvm_function_allocate);
+ rb_define_method(cLLVMFunction, "initialize", llvm_function_initialize, 0);
+ rb_define_method(cLLVMFunction, "create_block", llvm_function_create_block, 0);
+ rb_define_method(cLLVMFunction, "compile", llvm_function_compile, 0);
+ rb_define_method(cLLVMFunction, "call", llvm_function_call, 1);
+ rb_define_method(cLLVMFunction, "call2", llvm_function_call2, 1);
+ rb_define_method(cLLVMFunction, "argument", llvm_function_argument, 0);
+
+ rb_define_method(cLLVMBasicBlock, "builder", llvm_basic_block_builder, 0);
+
+ rb_define_method(cLLVMBuilder, "create_add", llvm_builder_create_add, 2);
+ rb_define_method(cLLVMBuilder, "create_sub", llvm_builder_create_sub, 2);
+ rb_define_method(cLLVMBuilder, "create_mul", llvm_builder_create_mul, 2);
+ rb_define_method(cLLVMBuilder, "create_xor", llvm_builder_create_xor, 2);
+ rb_define_method(cLLVMBuilder, "create_shl", llvm_builder_create_shl, 2);
+ rb_define_method(cLLVMBuilder, "create_lshr", llvm_builder_create_lshr, 2);
+ rb_define_method(cLLVMBuilder, "create_and", llvm_builder_create_and, 2);
+ rb_define_method(cLLVMBuilder, "create_return", llvm_builder_create_return, 1);
+ rb_define_method(cLLVMBuilder, "create_br", llvm_builder_create_br, 1);
+ rb_define_method(cLLVMBuilder, "create_cond_br", llvm_builder_create_cond_br, 3);
+ rb_define_method(cLLVMBuilder, "create_alloca", llvm_builder_create_alloca, 2);
+ rb_define_method(cLLVMBuilder, "create_load", llvm_builder_create_load, 1);
+ rb_define_method(cLLVMBuilder, "create_store", llvm_builder_create_store, 2);
+ rb_define_method(cLLVMBuilder, "create_icmpeq", llvm_builder_create_icmpeq, 2);
+ rb_define_method(cLLVMBuilder, "create_gep", llvm_builder_create_gep, 2);
+ rb_define_method(cLLVMBuilder, "create_struct_gep", llvm_builder_create_struct_gep, 2);
+ rb_define_method(cLLVMBuilder, "create_int_to_ptr", llvm_builder_create_int_to_ptr, 2);
+
+ printf("sizeof long: %d\n", (int)sizeof(long));
+ printf("sizeof ptr: %d\n", (int)sizeof(long*));
+ printf("sizeof value: %d\n", (int)sizeof(VALUE));
+ printf("sizeof array: %d\n", (int)sizeof(struct RArray));
+ printf("sizeof char: %d\n", (int)sizeof(char));
+}
24 llvmruby.h
@@ -0,0 +1,24 @@
+#define __STDC_LIMIT_MACROS
+
+#include "llvm/Module.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Constants.h"
+#include "llvm/Instructions.h"
+#include "llvm/ModuleProvider.h"
+#include "llvm/PassManager.h"
+#include "llvm/LinkAllPasses.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/ExecutionEngine/Interpreter.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
+#include "llvm/Support/IRBuilder.h"
+#include <iostream>
+using namespace llvm;
+
+#include "ruby.h"
+
+extern "C" VALUE llvm_value_wrap(Value*);
+extern "C" VALUE llvm_basic_block_wrap(BasicBlock*);
+extern "C" VALUE llvm_function_create_block(VALUE);
BIN llvmruby.o
Binary file not shown.
1 mkmf
@@ -0,0 +1 @@
+ruby extconf.rb --with-llvm-include=/home/tom/llvm/include --with-llvm-lib=/home/tom/llvm/Debug/lib
459 test.rb
@@ -0,0 +1,459 @@
+require 'llvmruby'
+require 'benchmark'
+
+include LLVM
+
+def simple_test
+ f = LLVM::Function.new
+ bb = f.create_block
+ builder = bb.builder
+ x = LLVM::Value.get_constant(23)
+ y = LLVM::Value.get_constant(42)
+ tmp = builder.create_add(x, y)
+ builder.create_return(tmp)
+ f.compile
+ puts "simple_test: #{f.call(0)}"
+end
+
+def call_test
+ f = LLVM::Function.new
+ entry_block = f.create_block
+ subroutine_block = f.create_block
+
+ builder = entry_block.builder
+ space = builder.create_alloca(10)
+ val = LLVM::Value.get_constant(23)
+ builder.create_store(val, space)
+
+ start_val = LLVM::Value.get_constant(0)
+ stop_val = LLVM::Value.get_constant(10)
+ cmp = builder.create_icmpeq(start_val, stop_val)
+
+ builder.create_br(subroutine_block)
+
+ builder = subroutine_block.builder
+ loaded_val = builder.create_load(space)
+ builder.create_return(loaded_val)
+
+ f.compile
+ puts "call_test: #{f.call(0)}"
+end
+
+def cond_br_test
+ f = Function.new
+ entry_block = f.create_block
+ true_block = f.create_block
+ false_block = f.create_block
+
+ builder = entry_block.builder
+ arg = f.argument
+ v1 = Value.get_constant(1)
+ cmp = builder.create_icmpeq(arg, v1)
+ builder.create_cond_br(cmp, true_block, false_block)
+
+ builder = true_block.builder
+ builder.create_return(Value.get_constant(23))
+
+ builder = false_block.builder
+ builder.create_return(Value.get_constant(666))
+
+ f.compile
+ puts "cond_br_test(0): #{f.call(0)}"
+ puts "cond_br_test(1): #{f.call(1)}"
+end
+
+def fib_test
+ f = Function.new
+ n = f.argument
+ entry_block = f.create_block
+ loop_block = f.create_block
+ exit_block = f.create_block
+
+ builder = entry_block.builder
+
+ # Make the counter
+ counter = builder.create_alloca(1)
+ builder.create_store(Value.get_constant(2), counter)
+
+ # Initialize the array
+ space = builder.create_alloca(20)
+ v1 = Value.get_constant(1)
+ builder.create_store(v1, space)
+ s1 = builder.create_gep(space, v1)
+ builder.create_store(v1, s1)
+
+ # Start the loop
+ builder.create_br(loop_block)
+
+ builder = loop_block.builder
+ current_counter = builder.create_load(counter)
+ current_space = builder.create_gep(space, current_counter)
+ back_1 = builder.create_sub(current_counter, v1)
+ back_2 = builder.create_sub(back_1, v1)
+ back_1_space = builder.create_gep(space, back_1)
+ back_2_space = builder.create_gep(space, back_2)
+ back_1_val = builder.create_load(back_1_space)
+ back_2_val = builder.create_load(back_2_space)
+ new_val = builder.create_add(back_1_val, back_2_val)
+ builder.create_store(new_val, current_space)
+ new_counter = builder.create_add(current_counter, v1)
+ builder.create_store(new_counter, counter)
+
+ cmp = builder.create_icmpeq(n, new_counter)
+ builder.create_cond_br(cmp, exit_block, loop_block)
+
+ builder = exit_block.builder
+ last_idx = builder.create_sub(n, v1)
+ last_slot = builder.create_gep(space, current_counter)
+ ret_val = builder.create_load(last_slot)
+ builder.create_return(ret_val)
+
+ f.compile
+ inputs = Array.new(10) {|n| n+3}
+ outputs = inputs.map {|n| f.call(n)}
+ puts "inputs: #{inputs.inspect}"
+ puts "outputs: #{outputs.inspect}"
+end
+
+def add_up
+ x = 0
+ y = 100
+ until y == 0
+ y -= 1
+ x += y
+ end
+ x
+end
+
+GC.disable
+
+class Fixnum
+ def llvm
+ Value::get_constant(self)
+ end
+end
+
+class LLVM::Value
+ def llvm
+ self
+ end
+end
+
+class Builder
+ FIXNUM_FLAG = 0x1.llvm
+ CHAR = Type::Int8Ty
+ P_CHAR = Type::pointer(CHAR)
+ LONG = Type::Int64Ty
+ VALUE = Type::Int64Ty
+ P_VALUE = Type::pointer(VALUE)
+ RBASIC = Type::struct([VALUE, VALUE])
+ RARRAY = Type::struct([RBASIC, LONG, LONG, P_VALUE])
+ P_RARRAY = Type::pointer(RARRAY)
+ RSTRING = Type::struct([RBASIC, LONG, P_CHAR, VALUE])
+ P_RSTRING = Type::pointer(RSTRING)
+
+ def self.set_globals(b)
+ @@stack = b.create_alloca(VALUE, 100)
+ @@stack_ptr = b.create_alloca(P_VALUE, 0)
+ b.create_store(@@stack, @@stack_ptr)
+ @@locals = b.create_alloca(VALUE, 100)
+ end
+
+ def fixnum?(val)
+ create_and(FIXNUM_FLAG, val)
+ end
+
+ def num2fix(val)
+ shifted = create_shl(val, 1.llvm)
+ create_xor(FIXNUM_FLAG, shifted)
+ end
+
+ def fix2int(val)
+ x = create_xor(FIXNUM_FLAG, val)
+ create_lshr(val, 1.llvm)
+ end
+
+ def slen(str)
+ val_ptr = create_int_to_ptr(str, P_RSTRING)
+ len_ptr = create_struct_gep(val_ptr, 1)
+ create_load(len_ptr)
+ end
+
+ def alen(ary)
+ val_ptr = create_int_to_ptr(ary, P_RARRAY)
+ len_ptr = create_struct_gep(val_ptr, 1)
+ create_load(len_ptr)
+ end
+
+ def aref(ary, idx)
+ val_ptr = create_int_to_ptr(ary, P_RARRAY)
+ data_ptr = create_struct_gep(val_ptr, 3)
+ data_ptr = create_load(data_ptr)
+ slot_n = create_gep(data_ptr, idx.llvm)
+ create_load(slot_n)
+ end
+
+ def aset(ary, idx, set)
+ val_ptr = create_int_to_ptr(ary, P_RARRAY)
+ data_ptr = create_struct_gep(val_ptr, 3)
+ data_ptr = create_load(data_ptr)
+ slot_n = create_gep(data_ptr, idx.llvm)
+ create_store(set, slot_n)
+ end
+
+ def stack
+ @@stack
+ end
+
+ def stack_ptr
+ @@stack_ptr
+ end
+
+ def push(val)
+ sp = create_load(stack_ptr)
+ create_store(val, sp)
+ new_sp = create_gep(sp, 1.llvm)
+ create_store(new_sp, stack_ptr)
+ end
+
+ def pop
+ sp = create_load(stack_ptr)
+ new_sp = create_gep(sp, -1.llvm)
+ create_store(new_sp, stack_ptr)
+ create_load(new_sp)
+ end
+
+ def peek(n = 1)
+ sp = create_load(stack_ptr)
+ peek_sp = create_gep(sp, (-n).llvm)
+ create_load(peek_sp)
+ end
+
+ def locals
+ @@locals
+ end
+end
+
+def ruby_fac(n)
+ fac = n
+ while n > 1
+ n = n-1
+ fac = fac*n
+ end
+ fac
+end
+
+
+def bytecode_test
+ #bytecode = [
+ # [:putobject, 1],
+ # [:setlocal, 0],
+ # [:dup],
+ # [:getlocal, 0],
+ # [:opt_plus],
+ # [:setlocal, 0],
+ # [:putobject, 1],
+ # [:opt_minus],
+ # [:dup],
+ # [:branchif, 2],
+ # [:getlocal, 0],
+ #]
+
+ # Factorial
+ #bytecode = [
+ # [:dup],
+ # [:setlocal, 0],
+ # [:putobject, 1],
+ # [:opt_minus],
+ # [:dup],
+ # [:branchunless, 11],
+ # [:dup],
+ # [:getlocal, 0],
+ # [:opt_mult],
+ # [:setlocal, 0],
+ # [:jump, 2],
+ # [:getlocal, 0]
+ #]
+
+ bytecode = [
+ [:putobject, 2],
+ [:opt_aref]
+ ]
+
+ f = Function.new
+ entry_block = f.create_block
+ b = entry_block.builder
+ Builder.set_globals(b)
+ b.push(f.argument)
+
+ blocks = bytecode.map { f.create_block }
+ exit_block = f.create_block
+ blocks << exit_block
+ b.create_br(blocks.first)
+
+ bytecode.each_with_index do |opcode, i|
+ op, arg = opcode
+
+ block = blocks[i]
+ b = block.builder
+
+ case op
+ when :nop
+ when :putobject
+ b.push(arg.object_id.llvm)
+ when :pop
+ b.pop
+ when :dup
+ b.push(b.peek)
+ when :swap
+ v1 = b.pop
+ v2 = b.pop
+ b.push(v1)
+ b.push(v2)
+ when :setlocal
+ v = b.pop
+ local_slot = b.create_gep(b.locals, arg.llvm)
+ b.create_store(v, local_slot)
+ when :getlocal
+ local_slot = b.create_gep(b.locals, arg.llvm)
+ val = b.create_load(local_slot)
+ b.push(val)
+ when :opt_plus
+ v1 = b.fix2int(b.pop)
+ v2 = b.fix2int(b.pop)
+ sum = b.create_add(v1, v2)
+ b.push(b.num2fix(sum))
+ when :opt_minus
+ v1 = b.fix2int(b.pop)
+ v2 = b.fix2int(b.pop)
+ sum = b.create_sub(v2, v1)
+ b.push(b.num2fix(sum))
+ when :opt_mult
+ v1 = b.fix2int(b.pop)
+ v2 = b.fix2int(b.pop)
+ mul = b.create_mul(v1, v2)
+ b.push(b.num2fix(mul))
+ when :opt_aref
+ idx = b.fix2int(b.pop)
+ ary = b.pop
+ out = b.aref(ary, idx)
+ b.push(out)
+ when :jump
+ b.create_br(blocks[arg])
+ when :branchif
+ v = b.pop
+ cmp = b.create_icmpeq(v, 1.llvm)
+ b.create_cond_br(cmp, blocks[i+1], blocks[arg])
+ when :branchunless
+ v = b.pop
+ cmp = b.create_icmpeq(v, 1.llvm)
+ b.create_cond_br(cmp, blocks[arg], blocks[i+1])
+ else
+ raise("Unrecognized op code")
+ end
+
+ if op != :jump && op != :branchif && op != :branchunless
+ b.create_br(blocks[i+1])
+ end
+ end
+
+ b = exit_block.builder
+ ret_val = b.pop
+ b.create_return(ret_val)
+
+ f.compile
+
+ puts "returned: #{f.call2([1,2,3,4,5,6,7,8,9,10])}"
+end
+
+bytecode_test
+
+def test_types
+ type = Type::Int32Ty
+ struct = Type::struct([Type::Int32Ty, Type::Int32Ty, Type::Int32Ty])
+ array = Type::array(struct, 10)
+ vector = Type::vector(struct, 5)
+ puts struct.inspect
+ puts array.inspect
+ puts vector.inspect
+ puts "tested types"
+end
+
+def test_builder
+ f = Function.new
+ block = f.create_block
+ b = block.builder
+
+ arg = f.argument
+ out = b.slen(arg)
+ out = b.num2fix(out)
+ b.create_return(out)
+ #x = b.aref(arg, 3)
+ #x = b.fix2int(x)
+ #y = 10.llvm
+ #sum = b.create_add(x, y)
+ #b.aset(arg, 3, b.num2fix(sum))
+ #b.create_return(arg)
+
+ f.compile
+ puts "out: #{f.call2("shaka")}"
+ #puts "meh: #{f.call2([1,2,3,4,5,6,7])}"
+end
+
+def test_fixnums
+ f = Function.new
+ block = f.create_block
+ b = block.builder
+ arg = f.argument
+ int = b.fix2int(arg)
+ sum = b.create_add(int, 23.llvm)
+ out = b.num2fix(sum)
+ b.create_return(out)
+ f.compile
+ puts "out: #{f.call2(5)}"
+end
+
+def test_array
+ f = Function.new
+ block = f.create_block
+ b = block.builder
+
+ rVALUE = Type::Int64Ty
+ cLONG = Type::Int64Ty
+ rBasic = Type::struct([rVALUE, rVALUE])
+ rArray = Type::struct([rBasic, cLONG, cLONG, Type::pointer(rVALUE)])
+ rArrayPtr = Type::pointer(rArray)
+
+ arg = f.argument
+ val_ptr = b.create_int_to_ptr(arg, rArrayPtr)
+ len_ptr = b.create_struct_gep(val_ptr, 2)
+ out = b.create_load(len_ptr)
+ data_ptr = b.create_struct_gep(val_ptr, 3)
+ data_ptr = b.create_load(data_ptr)
+ slot_n = b.create_gep(data_ptr, 0.llvm)
+ out = b.create_load(slot_n)
+ b.create_return(out)
+
+ #b.create_return(b.num2fix(out))
+
+ f.compile
+ puts "length [1,2]: #{f.call2([1,2])}"
+ puts "length [1,2,3,4]: #{f.call2([1,2,3,4])}"
+ puts "length [1,2,3,4,5,6]: #{f.call2([1,2,3,4,5,6])}"
+end
+
+def test_bitwise_ops
+ f = Function.new
+ bb = f.create_block
+ builder = bb.builder
+ arg = f.argument
+ out = builder.fixnum?(arg)
+ out = builder.create_shl(1.llvm, 2.llvm)
+ out = builder.create_lshr(out, 1.llvm)
+ builder.create_return(out)
+ f.compile
+ puts "out: #{f.call2(0)}"
+ puts "out: #{f.call2(666)}"
+ puts "out: #{f.call2("shaka")}"
+ puts "out: #{f.call2([])}"
+end

0 comments on commit 162305c

Please sign in to comment.