gccxml #define __STDC_LIMIT_MACROS #define __STDC_CONSTANT_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 using namespace llvm; #define LLVM_VAL(obj) ((Value*)DATA_PTR(obj)) #define LLVM_USER(obj) ((User*)DATA_PTR(obj)) #define LLVM_USE(obj) ((Use*)DATA_PTR(obj)) #define LLVM_TYPE(obj) ((Type*)DATA_PTR(obj)) #define LLVM_FUNC_TYPE(obj) ((FunctionType*)DATA_PTR(obj)) #define LLVM_MODULE(obj) ((Module*)DATA_PTR(obj)) #define LLVM_FUNCTION(obj) ((Function*)DATA_PTR(obj)) #define LLVM_BASIC_BLOCK(obj) ((BasicBlock*)DATA_PTR(obj)) #define LLVM_INSTRUCTION(obj) ((Instruction*)DATA_PTR(obj)) #define LLVM_PHI(obj) ((PHINode*)DATA_PTR(obj)) #define HANDLE_TERM_INST(Num, Opcode, Klass) extern VALUE cLLVM##Klass; #define HANDLE_MEMORY_INST(Num, Opcode, Klass) extern VALUE cLLVM##Klass; #define HANDLE_OTHER_INST(Num, Opcode, Klass) extern VALUE cLLVM##Klass; #include "llvm/Instruction.def" BasicBlock *bb = LLVM_BASIC_BLOCK(self); bb->size() Instruction llvm_instruction_wrap (global) bb->end() builder->CreateBr #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_size(VALUE self) { BasicBlock *bb = LLVM_BASIC_BLOCK(self); return INT2NUM(bb->size()); } VALUE llvm_basic_block_get_instruction_list(VALUE self) { BasicBlock *bb = LLVM_BASIC_BLOCK(self); VALUE ins_array = rb_ary_new(); BasicBlock::iterator ins = bb->begin(); while(ins != bb->end()) { Instruction *i = ins++; rb_ary_push(ins_array, llvm_instruction_wrap(i)); } return ins_array; } 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); } #define DATA_GET_BUILDER IRBuilder<> *builder; Data_Get_Struct(self, IRBuilder<>, builder); #define DATA_GET_BLOCK BasicBlock *bb; CHECK_TYPE(rbb, cLLVMBasicBlock); Data_Get_Struct(rbb, BasicBlock, bb); VALUE llvm_builder_set_insert_point(VALUE self, VALUE rbb) { DATA_GET_BUILDER DATA_GET_BLOCK builder->SetInsertPoint(bb); return self; } VALUE llvm_builder_bin_op(VALUE self, VALUE rbin_op, VALUE rv1, VALUE rv2) { Check_Type(rbin_op, T_FIXNUM); DATA_GET_BUILDER Instruction::BinaryOps bin_op = (Instruction::BinaryOps)FIX2INT(rbin_op); Value *v1, *v2; Data_Get_Struct(rv1, Value, v1); Data_Get_Struct(rv2, Value, v2); Value *res = builder->CreateBinOp(bin_op, v1, v2); return Data_Wrap_Struct(cLLVMBinaryOperator, NULL, NULL, res); } VALUE llvm_builder_phi(VALUE self, VALUE type) { CHECK_TYPE(type, cLLVMType); DATA_GET_BUILDER PHINode *v = builder->CreatePHI(LLVM_TYPE(type)); return Data_Wrap_Struct(cLLVMPhi, NULL, NULL, v); } VALUE llvm_phi_add_incoming(VALUE self, VALUE val, VALUE rbb) { CHECK_TYPE(val, cLLVMValue); DATA_GET_BLOCK PHINode *phi = LLVM_PHI(self); phi->addIncoming(LLVM_VAL(val), bb); return self; } VALUE llvm_builder_return(VALUE self, VALUE rv) { CHECK_TYPE(rv, cLLVMValue); DATA_GET_BUILDER return Data_Wrap_Struct(cLLVMReturnInst, NULL, NULL, builder->CreateRet(LLVM_VAL(rv))); } VALUE llvm_builder_br(VALUE self, VALUE rblock) { DATA_GET_BUILDER BasicBlock *bb; Data_Get_Struct(rblock, BasicBlock, bb); Value *branch_instr = builder->CreateBr(bb); return Data_Wrap_Struct(cLLVMBranchInst, NULL, NULL, branch_instr); } VALUE llvm_builder_cond_br(VALUE self, VALUE rcond, VALUE rtrue_block, VALUE rfalse_block) { DATA_GET_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); #if defined(USE_ASSERT_CHECK) if (cond->getType() != Type::Int1Ty) { rb_raise(rb_eRuntimeError, "May only branch on boolean predicates!"); } #endif Value *branch_instr = builder->CreateCondBr(cond, true_block, false_block); return Data_Wrap_Struct(cLLVMBranchInst, NULL, NULL, branch_instr); } VALUE llvm_builder_switch(VALUE self, VALUE rv, VALUE rdefault) { DATA_GET_BUILDER BasicBlock *deflt; Data_Get_Struct(rdefault, BasicBlock, deflt); Value *v; Data_Get_Struct(rv, Value, v); Instruction *switch_instr = builder->CreateSwitch(v, deflt); return llvm_instruction_wrap(switch_instr); } VALUE llvm_builder_invoke(int argc, VALUE *argv, VALUE self) { DATA_GET_BUILDER if(argc < 3) { rb_raise(rb_eArgError, "Expected at least three argument"); } int num_args = argc - 3; Value *callee = LLVM_VAL(argv[0]); BasicBlock *ndest; BasicBlock *udest; std::vector vecarg(num_args); Data_Get_Struct(argv[1], BasicBlock, ndest); Data_Get_Struct(argv[2], BasicBlock, udest); for (int i = 0; i < num_args; i++) { vecarg[i] = LLVM_VAL(argv[i + 3]); } return llvm_value_wrap(builder->CreateInvoke(callee, ndest, udest, vecarg.begin(), vecarg.end())); } VALUE llvm_builder_unwind(VALUE self) { DATA_GET_BUILDER return llvm_value_wrap(builder->CreateUnwind()); } VALUE llvm_builder_malloc(VALUE self, VALUE rtype, VALUE rsize) { DATA_GET_BUILDER const Type *type; Data_Get_Struct(rtype, Type, type); Value *size = ConstantInt::get(Type::Int32Ty, FIX2INT(rsize)); Instruction *v = builder->CreateMalloc(type, size); return llvm_instruction_wrap(v); } VALUE llvm_builder_free(VALUE self, VALUE rptr) { DATA_GET_BUILDER Value *v = LLVM_VAL(rptr); Instruction *free_inst = builder->CreateFree(v); return llvm_instruction_wrap(free_inst); } VALUE llvm_builder_alloca(VALUE self, VALUE rtype, VALUE rsize) { DATA_GET_BUILDER const Type* type; Data_Get_Struct(rtype, Type, type); Value *size = ConstantInt::get(Type::Int32Ty, FIX2INT(rsize)); Instruction *v = builder->CreateAlloca(type, size); return Data_Wrap_Struct(cLLVMAllocationInst, NULL, NULL, v); } VALUE llvm_builder_load(int argc, VALUE *argv, VALUE self) { DATA_GET_BUILDER VALUE rptr; VALUE isVolatile; Value *ptr; rb_scan_args(argc, argv, "11", &rptr, &isVolatile); Data_Get_Struct(rptr, Value, ptr); return Data_Wrap_Struct(cLLVMLoadInst, NULL, NULL, builder->CreateLoad(ptr, RTEST(isVolatile))); } VALUE llvm_builder_store(int argc, VALUE *argv, VALUE self) { DATA_GET_BUILDER Value *v, *ptr; VALUE rv; VALUE rptr; VALUE isVolatile; rb_scan_args(argc, argv, "21", &rv, &rptr, &isVolatile); Data_Get_Struct(rv, Value, v); Data_Get_Struct(rptr, Value, ptr); return Data_Wrap_Struct(cLLVMStoreInst, NULL, NULL, builder->CreateStore(v, ptr, RTEST(isVolatile))); } VALUE llvm_builder_icmp(VALUE self, VALUE pred, VALUE lhs, VALUE rhs) { DATA_GET_BUILDER CmpInst::Predicate p = (CmpInst::Predicate)FIX2INT(pred); Value *v = builder->CreateICmp(p, LLVM_VAL(lhs), LLVM_VAL(rhs)); return Data_Wrap_Struct(cLLVMICmpInst, NULL, NULL, v); } VALUE llvm_builder_fcmp(VALUE self, VALUE pred, VALUE lhs, VALUE rhs) { DATA_GET_BUILDER CmpInst::Predicate p = (CmpInst::Predicate)FIX2INT(pred); Value *v = builder->CreateFCmp(p, LLVM_VAL(lhs), LLVM_VAL(rhs)); return Data_Wrap_Struct(cLLVMFCmpInst, NULL, NULL, v); } VALUE llvm_builder_gep(VALUE self, VALUE rptr, VALUE ridx) { DATA_GET_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_struct_gep(VALUE self, VALUE rptr, VALUE ridx) { DATA_GET_BUILDER Value *ptr; Data_Get_Struct(rptr, Value, ptr); return llvm_value_wrap(builder->CreateStructGEP(ptr, FIX2INT(ridx))); } VALUE llvm_builder_cast(VALUE self, VALUE rop, VALUE rv, VALUE rdest_ty) { DATA_GET_BUILDER Instruction::CastOps op = (Instruction::CastOps)FIX2INT(rop); Value *v; Data_Get_Struct(rv, Value, v); Type *dest_ty; Data_Get_Struct(rdest_ty, Type, dest_ty); return llvm_value_wrap(builder->CreateCast(op, v, dest_ty)); } VALUE llvm_builder_int_cast(VALUE self, VALUE i, VALUE type, VALUE sign) { DATA_GET_BUILDER bool isSigned = (sign != Qnil && sign != Qfalse); return llvm_value_wrap(builder->CreateIntCast(LLVM_VAL(i), LLVM_TYPE(type), isSigned)); } VALUE llvm_builder_call(int argc, VALUE* argv, VALUE self) { DATA_GET_BUILDER Function *callee = LLVM_FUNCTION(argv[0]); int num_args = argc-1; Value** args = (Value**)alloca(num_args*sizeof(Value*)); #if defined(USE_ASSERT_CHECK) const FunctionType *FTy = cast(cast(callee->getType())->getElementType()); char message[255]; if (!((unsigned)num_args == FTy->getNumParams() || (FTy->isVarArg() && (unsigned) num_args > FTy->getNumParams()))) { snprintf(message, 255, "Calling a function with bad signature number of argument %d expect %d", num_args, FTy->getNumParams()); rb_raise(rb_eRuntimeError, message); } #endif for(int i = 0; i < num_args; ++i) { args[i] = LLVM_VAL(argv[i+1]); #if defined(USE_ASSERT_CHECK) if (FTy->getParamType(i) != args[i]->getType()) { snprintf(message, 255, "Calling a function with a bad signature in %d argument", i); rb_raise(rb_eRuntimeError, message); } #endif } return llvm_value_wrap(builder->CreateCall(callee, args, args+num_args)); } VALUE llvm_builder_insert_element(VALUE self, VALUE rv, VALUE rnv, VALUE ridx) { DATA_GET_BUILDER Value *v, *nv, *idx; Data_Get_Struct(rv, Value, v); Data_Get_Struct(rnv, Value, nv); Data_Get_Struct(ridx, Value, idx); return llvm_value_wrap(builder->CreateInsertElement(v, nv, idx)); } VALUE llvm_builder_extract_element(VALUE self, VALUE rv, VALUE ridx) { DATA_GET_BUILDER Value *v, *idx; Data_Get_Struct(rv, Value, v); Data_Get_Struct(ridx, Value, idx); return llvm_value_wrap(builder->CreateExtractElement(v, idx)); } VALUE llvm_builder_get_global(VALUE self) { GlobalVariable *g = new GlobalVariable(Type::Int64Ty, false, GlobalValue::ExternalLinkage, 0, "shakalaka"); return llvm_value_wrap(g); } VALUE llvm_builder_create_global_string_ptr(VALUE self, VALUE str) { DATA_GET_BUILDER Value *v = builder->CreateGlobalStringPtr(StringValuePtr(str)); return llvm_value_wrap(v); } } #include "llvmruby.h" #include extern "C" { VALUE llvm_function_wrap(Function *f) { return Data_Wrap_Struct(cLLVMFunction, NULL, NULL, f); } VALUE llvm_function_create_block(VALUE self) { BasicBlock *bb = BasicBlock::Create("bb", LLVM_FUNCTION(self)); return llvm_basic_block_wrap(bb); } VALUE llvm_function_arguments(VALUE self) { Function *f = LLVM_FUNCTION(self); VALUE arg_array = rb_ary_new(); Function::arg_iterator args = f->arg_begin(); while(args != f->arg_end()) { Value *arg = args++; rb_ary_push(arg_array, llvm_value_wrap(arg)); } return arg_array; } VALUE llvm_function_inspect(VALUE self) { Function *f = LLVM_FUNCTION(self); std::ostringstream strstrm; strstrm << *f; return rb_str_new2(strstrm.str().c_str()); } VALUE llvm_function_get_basic_block_list(VALUE self) { Function *f = LLVM_FUNCTION(self); VALUE bb_array = rb_ary_new(); Function::iterator bbs = f->begin(); while(bbs != f->end()) { BasicBlock *bb = bbs++; rb_ary_push(bb_array, llvm_basic_block_wrap(bb)); } return bb_array; } } #include "llvmruby.h" #include extern VALUE cLLVMInstruction; extern VALUE cLLVMBinaryOps; extern "C" { #define LAST_INSTRUCTION_NUM 100 VALUE gInstructionClasses[LAST_INSTRUCTION_NUM]; #define DATA_GET_INSTRUCTION Instruction *i; Data_Get_Struct(self, Instruction, i); VALUE llvm_instruction_wrap(Instruction* i) { return Data_Wrap_Struct(gInstructionClasses[i->getOpcode()], NULL, NULL, i); } VALUE llvm_instruction_inspect(VALUE self) { Instruction *i = LLVM_INSTRUCTION(self); std::ostringstream strstrm; strstrm << *i; return rb_str_new2(strstrm.str().c_str()); } VALUE llvm_instruction_get_opcode_name(VALUE self) { Instruction *i = LLVM_INSTRUCTION(self); std::string name = i->getOpcodeName(); return rb_str_new2(name.c_str()); } VALUE llvm_instruction_may_read_from_memory(VALUE self) { DATA_GET_INSTRUCTION return i->mayReadFromMemory() ? Qtrue : Qfalse; } VALUE llvm_instruction_may_write_to_memory(VALUE self) { DATA_GET_INSTRUCTION return i->mayWriteToMemory() ? Qtrue : Qfalse; } VALUE llvm_instruction_is_identical_to(VALUE self, VALUE ri2) { DATA_GET_INSTRUCTION CHECK_TYPE(ri2, cLLVMInstruction); Instruction *i2 = LLVM_INSTRUCTION(ri2); return i->isIdenticalTo(i2) ? Qtrue : Qfalse; } VALUE llvm_instruction_is_same_operation_as(VALUE self, VALUE ri2) { DATA_GET_INSTRUCTION CHECK_TYPE(ri2, cLLVMInstruction); Instruction *i2 = LLVM_INSTRUCTION(ri2); return i->isSameOperationAs(i2) ? Qtrue : Qfalse; } VALUE llvm_instruction_is_used_outside_of_block(VALUE self, VALUE rbb) { DATA_GET_INSTRUCTION CHECK_TYPE(rbb, cLLVMBasicBlock); BasicBlock *bb = LLVM_BASIC_BLOCK(rbb); return i->isUsedOutsideOfBlock(bb) ? Qtrue: Qfalse; } #define DATA_GET_TERMINATOR_INST TerminatorInst *ti; Data_Get_Struct(self, TerminatorInst, ti); VALUE llvm_terminator_inst_num_successors(VALUE self) { DATA_GET_TERMINATOR_INST return INT2FIX(ti->getNumSuccessors()); } VALUE llvm_terminator_inst_get_successor(VALUE self, VALUE ridx) { DATA_GET_TERMINATOR_INST BasicBlock *bb = ti->getSuccessor(FIX2INT(ridx)); return llvm_basic_block_wrap(bb); } VALUE llvm_terminator_inst_set_successor(VALUE self, VALUE ridx, VALUE rbb) { DATA_GET_TERMINATOR_INST BasicBlock *bb; Data_Get_Struct(rbb, BasicBlock, bb); ti->setSuccessor(FIX2INT(ridx), bb); return rbb; } #define DATA_GET_BRANCH_INST BranchInst *bi; Data_Get_Struct(self, BranchInst, bi); VALUE llvm_branch_inst_is_unconditional(VALUE self) { DATA_GET_BRANCH_INST return bi->isUnconditional() ? Qtrue : Qfalse; } VALUE llvm_branch_inst_is_conditional(VALUE self) { DATA_GET_BRANCH_INST return bi->isConditional() ? Qtrue : Qfalse; } VALUE llvm_branch_inst_get_condition(VALUE self) { DATA_GET_BRANCH_INST return llvm_value_wrap(bi->getCondition()); } VALUE llvm_branch_inst_set_condition(VALUE self, VALUE rv) { DATA_GET_BRANCH_INST Value *v; Data_Get_Struct(rv, Value, v); bi->setCondition(v); return rv; } #define DATA_GET_SWITCH_INST SwitchInst *si; Data_Get_Struct(self, SwitchInst, si); VALUE llvm_switch_inst_get_default_dest(VALUE self) { DATA_GET_SWITCH_INST BasicBlock *bb = si->getDefaultDest(); return llvm_basic_block_wrap(bb); } VALUE llvm_switch_inst_get_num_cases(VALUE self) { DATA_GET_SWITCH_INST return INT2FIX(si->getNumCases()); } VALUE llvm_switch_inst_add_case(VALUE self, VALUE rci, VALUE rbb) { DATA_GET_SWITCH_INST ConstantInt *ci; Data_Get_Struct(rci, ConstantInt, ci); BasicBlock *bb; Data_Get_Struct(rbb, BasicBlock, bb); si->addCase(ci, bb); return self; } #define DATA_GET_ALLOCATION_INST AllocationInst *ai; Data_Get_Struct(self, AllocationInst, ai); VALUE llvm_allocation_inst_is_array_allocation(VALUE self) { DATA_GET_ALLOCATION_INST return ai->isArrayAllocation() ? true : false; } VALUE llvm_allocation_inst_array_size(VALUE self) { DATA_GET_ALLOCATION_INST return llvm_value_wrap(ai->getArraySize()); } VALUE llvm_allocation_inst_allocated_type(VALUE self) { DATA_GET_ALLOCATION_INST Type *at = const_cast(ai->getAllocatedType()); return Data_Wrap_Struct(cLLVMType, NULL, NULL, at); } VALUE llvm_allocation_inst_alignment(VALUE self) { DATA_GET_ALLOCATION_INST return INT2FIX(ai->getAlignment()); } #define DEFINE_INST(type, name) rb_define_const(cLLVMInstruction, #name, INT2FIX(Instruction::name)); #define DEFINE_BINARY_INST(name) DEFINE_INST(cLLVMBinaryOps, name) #define DEFINE_PRED(name) rb_define_const(cLLVMInstruction, #name, INT2FIX(ICmpInst::name)); #define DEFINE_FPRED(name) rb_define_const(cLLVMInstruction, #name, INT2FIX(FCmpInst::name)); #define DEFINE_CAST(name) rb_define_const(cLLVMInstruction, #name, INT2FIX(Instruction::name)); void init_instructions() { for(int i = 0; i < LAST_INSTRUCTION_NUM; ++i) { gInstructionClasses[i] = cLLVMInstruction; } // Need to be able to quickly look up at runtime Ruby classes cooresponding to LLVM classes #define HANDLE_TERM_INST(Num, Opcode, Klass) gInstructionClasses[Num] = cLLVM##Klass; #define HANDLE_BINARY_INST(Num, Opcode, Klass) gInstructionClasses[Num] = cLLVM##Klass; #define HANDLE_MEMORY_INST(Num, Opcode, Klass) gInstructionClasses[Num] = cLLVM##Klass; #include "llvm/Instruction.def" // Standard binary operators DEFINE_BINARY_INST(Add) DEFINE_BINARY_INST(Sub) DEFINE_BINARY_INST(Mul) DEFINE_BINARY_INST(UDiv) DEFINE_BINARY_INST(SDiv) DEFINE_BINARY_INST(FDiv) DEFINE_BINARY_INST(URem) DEFINE_BINARY_INST(SRem) DEFINE_BINARY_INST(FRem) // Logical operators (integer operands) DEFINE_BINARY_INST(Shl) // Shift left (logical) DEFINE_BINARY_INST(LShr) // Shift right (logical) DEFINE_BINARY_INST(AShr) // shift right (arithmetic) DEFINE_BINARY_INST(And) DEFINE_BINARY_INST(Or) DEFINE_BINARY_INST(Xor) // Integer predicates DEFINE_PRED(ICMP_EQ) // equal DEFINE_PRED(ICMP_NE) // not equal DEFINE_PRED(ICMP_UGT) // unsigned greater than DEFINE_PRED(ICMP_UGE) // unsigned greater or equal DEFINE_PRED(ICMP_ULT) // unsigned less than DEFINE_PRED(ICMP_ULE) // unsigned less or equal DEFINE_PRED(ICMP_SGT) // signed greater than DEFINE_PRED(ICMP_SGE) // signed greater or equal DEFINE_PRED(ICMP_SLT) // signed less than DEFINE_PRED(ICMP_SLE) // signed less or equal DEFINE_FPRED(FCMP_OEQ) DEFINE_FPRED(FCMP_OGT) DEFINE_FPRED(FCMP_OGE) DEFINE_FPRED(FCMP_OLT) DEFINE_FPRED(FCMP_OLE) DEFINE_FPRED(FCMP_ONE) DEFINE_FPRED(FCMP_ORD) DEFINE_FPRED(FCMP_UNO) DEFINE_FPRED(FCMP_UEQ) DEFINE_FPRED(FCMP_UGT) DEFINE_FPRED(FCMP_UGE) DEFINE_FPRED(FCMP_ULT) DEFINE_FPRED(FCMP_ULE) DEFINE_FPRED(FCMP_UNE) DEFINE_CAST(Trunc) DEFINE_CAST(ZExt) DEFINE_CAST(SExt) DEFINE_CAST(FPToUI) DEFINE_CAST(FPToSI) DEFINE_CAST(UIToFP) DEFINE_CAST(SIToFP) DEFINE_CAST(FPTrunc) DEFINE_CAST(FPExt) DEFINE_CAST(PtrToInt) DEFINE_CAST(IntToPtr) DEFINE_CAST(BitCast) } } #include "llvmruby.h" #include "llvm/Assembly/Parser.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/System/DynamicLibrary.h" #include #include extern "C" { VALUE llvm_module_allocate(VALUE klass) { return Data_Wrap_Struct(klass, NULL, NULL, NULL); } VALUE llvm_module_initialize(VALUE self, VALUE rname) { Check_Type(rname, T_STRING); DATA_PTR(self) = new Module(StringValuePtr(rname)); return self; } VALUE llvm_module_get_or_insert_function(VALUE self, VALUE name, VALUE rtype) { Check_Type(name, T_STRING); CHECK_TYPE(rtype, cLLVMFunctionType); Module *m = LLVM_MODULE(self); FunctionType *type = LLVM_FUNC_TYPE(rtype); Constant *fn = m->getOrInsertFunction(StringValuePtr(name), type); #if defined(USE_ASSERT_CHECK) if (isa(fn) == 0) { rb_raise(rb_eRuntimeError, "cast(fn) argument of incompatible type !"); } #endif Function *f = cast(fn); return llvm_function_wrap(f); } VALUE llvm_module_get_function(VALUE self, VALUE name) { Check_Type(name, T_STRING); Module *m = LLVM_MODULE(self); Function *f = m->getFunction(StringValuePtr(name)); return llvm_function_wrap(f); } VALUE llvm_module_global_constant(VALUE self, VALUE rtype, VALUE rinitializer) { Module *m = LLVM_MODULE(self); Type *type = LLVM_TYPE(rtype); Constant *initializer = (Constant*)DATA_PTR(rinitializer); GlobalVariable *gv = new GlobalVariable(type, true, GlobalValue::InternalLinkage, initializer, "", m); return llvm_value_wrap(gv); } VALUE llvm_module_global_variable(VALUE self, VALUE rtype, VALUE rinitializer) { Module *m = LLVM_MODULE(self); Type *type = LLVM_TYPE(rtype); Constant *initializer = (Constant*)DATA_PTR(rinitializer); GlobalVariable *gv = new GlobalVariable(type, false, GlobalValue::InternalLinkage, initializer, "", m); return llvm_value_wrap(gv); } VALUE llvm_module_inspect(VALUE self) { Module *m = LLVM_MODULE(self); std::ostringstream strstrm; strstrm << *m; return rb_str_new2(strstrm.str().c_str()); } VALUE llvm_pass_manager_allocate(VALUE klass) { return Data_Wrap_Struct(klass, NULL, NULL, NULL); } VALUE llvm_pass_manager_initialize(VALUE self) { PassManager *pm = new PassManager; DATA_PTR(self) = pm; return self; } VALUE llvm_pass_manager_run(VALUE self, VALUE module) { PassManager *pm = (PassManager*) DATA_PTR(self); Module *m = LLVM_MODULE(module); pm->add(new TargetData(m)); pm->add(createVerifierPass()); pm->add(createLowerSetJmpPass()); pm->add(createRaiseAllocationsPass()); pm->add(createCFGSimplificationPass()); pm->add(createPromoteMemoryToRegisterPass()); pm->add(createGlobalOptimizerPass()); pm->add(createGlobalDCEPass()); pm->add(createFunctionInliningPass()); pm->run(*m); return Qtrue; } static ExecutionEngine *EE = NULL; VALUE llvm_execution_engine_get(VALUE klass, VALUE module) { CHECK_TYPE(module, cLLVMModule); #if defined(__CYGWIN__) // Load dll Modules for ruby sys::DynamicLibrary::LoadLibraryPermanently("cygwin1.dll"); sys::DynamicLibrary::LoadLibraryPermanently("cygruby190.dll"); #endif Module *m = LLVM_MODULE(module); ExistingModuleProvider *MP = new ExistingModuleProvider(m); if(EE == NULL) { EE = ExecutionEngine::create(MP, false); } else { EE->addModuleProvider(MP); } return Qtrue; } VALUE llvm_module_external_function(VALUE self, VALUE name, VALUE type) { Check_Type(name, T_STRING); CHECK_TYPE(type, cLLVMFunctionType); Module *module = LLVM_MODULE(self); Function *f = Function::Create( LLVM_FUNC_TYPE(type), Function::ExternalLinkage, StringValuePtr(name), module ); return Data_Wrap_Struct(cLLVMFunction, NULL, NULL, f); } VALUE llvm_module_read_assembly(VALUE self, VALUE assembly) { Check_Type(assembly, T_STRING); ParseError e; Module *module = ParseAssemblyString( StringValuePtr(assembly), LLVM_MODULE(self), &e ); //TODO How do we handle errors? return Data_Wrap_Struct(cLLVMModule, NULL, NULL, module); } VALUE llvm_module_read_bitcode(VALUE self, VALUE bitcode) { Check_Type(bitcode, T_STRING); #if defined(RSTRING_PTR) MemoryBuffer *buf = MemoryBuffer::getMemBufferCopy(RSTRING_PTR(bitcode),RSTRING_PTR(bitcode)+RSTRING_LEN(bitcode)); #else MemoryBuffer *buf = MemoryBuffer::getMemBufferCopy(RSTRING(bitcode)->ptr,RSTRING(bitcode)->ptr+RSTRING(bitcode)->len); #endif Module *module = ParseBitcodeFile(buf); delete buf; return Data_Wrap_Struct(cLLVMModule, NULL, NULL, module); } VALUE llvm_module_write_bitcode(VALUE self, VALUE file_name) { Check_Type(file_name, T_STRING); // Don't really know how to handle c++ streams well, // dumping all into string buffer and then saving std::ofstream file; file.open(StringValuePtr(file_name)); WriteBitcodeToFile(LLVM_MODULE(self), file); // Convert value into a string. return Qtrue; } VALUE llvm_execution_engine_run_function(int argc, VALUE *argv, VALUE klass) { if(argc < 1) { rb_raise(rb_eArgError, "Expected at least one argument"); } CHECK_TYPE(argv[0], cLLVMFunction); Function *func = LLVM_FUNCTION(argv[0]); // Using run function is much slower than getting C function pointer // and calling that, but it lets us pass in arbitrary numbers of // arguments easily for now, which is nice std::vector arg_values; for(int i = 1; i < argc; ++i) { GenericValue arg_val; arg_val.IntVal = APInt(sizeof(long)*8, argv[i]); arg_values.push_back(arg_val); } GenericValue v = EE->runFunction(func, arg_values); VALUE val = v.IntVal.getZExtValue(); return val; } /* For tests: assume no args, return uncoverted int and turn it into fixnum */ VALUE llvm_execution_engine_run_autoconvert(VALUE klass, VALUE func) { std::vector args; GenericValue v = EE->runFunction(LLVM_FUNCTION(func), args); VALUE val = INT2NUM(v.IntVal.getZExtValue()); return val; } } #include "llvmruby.h" extern "C" { VALUE llvm_use_wrap(Use *u) { return Data_Wrap_Struct(cLLVMUse, NULL, NULL, u); } } #include "llvmruby.h" extern "C" { VALUE llvm_user_wrap(User *u) { return Data_Wrap_Struct(cLLVMUser, NULL, NULL, u); } //llvm_user_get_operand_list VALUE llvm_user_get_operand_list(VALUE self) { User *usr = LLVM_USER(self); VALUE op_array = rb_ary_new(); User::op_iterator op = usr->op_begin(); while(op != usr->op_end()) { Use *u = op++; rb_ary_push(op_array, llvm_use_wrap(op)); } return op_array; } //llvm_user_set_operand VALUE llvm_user_set_operand(VALUE self, VALUE i, VALUE val) { User *u = LLVM_USER(self); Value *v; Data_Get_Struct(val, Value, v); u->setOperand(FIX2UINT(i),v); return Qtrue; } //llvm_user_get_operand VALUE llvm_user_get_operand(VALUE self, VALUE i) { User *u = LLVM_USER(self); return llvm_value_wrap(u->getOperand(FIX2UINT(i))); } //llvm_user_get_num_operands VALUE llvm_user_get_num_operands(VALUE self) { User *u = LLVM_USER(self); return INT2NUM(u->getNumOperands()); } //llvm_user_drop_all_references VALUE llvm_user_drop_all_references(VALUE self) { User *u = LLVM_USER(self); u->dropAllReferences(); return Qtrue; } //llvm_user_replace_uses_of_with VALUE llvm_user_replace_uses_of_with(VALUE self, VALUE from, VALUE to) { User *u = LLVM_USER(self); Value *v_from, *v_to; Data_Get_Struct(from, Value, v_from); Data_Get_Struct(to, Value, v_to); u->replaceUsesOfWith(v_from,v_to); return Qtrue; } } #include "llvmruby.h" extern "C" { VALUE llvm_value_wrap(Value* v) { return Data_Wrap_Struct(cLLVMValue, NULL, NULL, v); } VALUE llvm_value_name(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); if(v->hasName()) { const char *name = v->getNameStart(); int len = v->getNameLen(); return rb_str_new(name, len); } else { return Qnil; } } VALUE llvm_value_set_name(VALUE self, VALUE rname) { Value *v; Data_Get_Struct(self, Value, v); v->setName(RSTRING_PTR(rname), RSTRING_LEN(rname)); return rname; } VALUE llvm_value_type(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); const Type *t = v->getType(); return Data_Wrap_Struct(cLLVMType, NULL, NULL, (void*) t);; } VALUE llvm_value_num_uses(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); return INT2FIX(v->getNumUses()); } VALUE llvm_value_used_in_basic_block(VALUE self, VALUE rbb) { Value *v; Data_Get_Struct(self, Value, v); BasicBlock *bb; Data_Get_Struct(rbb, BasicBlock, bb); return v->isUsedInBasicBlock(bb) ? Qtrue : Qfalse; } VALUE llvm_value_replace_all_uses_with(VALUE self, VALUE rv2) { Value *v1, *v2; Data_Get_Struct(self, Value, v1); Data_Get_Struct(rv2, Value, v2); v1->replaceAllUsesWith(v2); return rv2; } VALUE llvm_value_get_constant(VALUE self, VALUE type, VALUE v) { return llvm_value_wrap(ConstantInt::get(LLVM_TYPE(type), FIX2INT(v))); } VALUE llvm_value_get_float_constant(VALUE self, VALUE v) { #if defined(RFLOAT_VALUE) return llvm_value_wrap(ConstantFP::get(Type::FloatTy, RFLOAT_VALUE(v))); #else return llvm_value_wrap(ConstantFP::get(Type::FloatTy, RFLOAT(v)->value)); #endif } VALUE llvm_value_get_double_constant(VALUE self, VALUE v) { #if defined(RFLOAT_VALUE) return llvm_value_wrap(ConstantFP::get(Type::DoubleTy, RFLOAT_VALUE(v))); #else return llvm_value_wrap(ConstantFP::get(Type::DoubleTy, RFLOAT(v)->value)); #endif } VALUE llvm_value_get_struct_constant(int argc, VALUE *argv, VALUE self) { StructType *t = (StructType*)DATA_PTR(argv[0]); std::vector vals; for(int i = 1; i < argc; ++i) { Constant *c = (Constant*)DATA_PTR(argv[i]); vals.push_back(c); } return llvm_value_wrap(ConstantStruct::get(t, vals)); } VALUE llvm_value_get_immediate_constant(VALUE self, VALUE v) { const IntegerType* type; if(sizeof(VALUE) == 4) { type = Type::Int32Ty; } else { type = Type::Int64Ty; } return llvm_value_wrap(ConstantInt::get(type, (long)v)); } VALUE llvm_value_is_constant(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); return isa(v) ? Qtrue : Qfalse; } VALUE llvm_value_is_int_constant(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); return isa(v) ? Qtrue : Qfalse; } VALUE llvm_value_is_float_constant(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); return isa(v) ? Qtrue : Qfalse; } VALUE llvm_value_get_int_constant_value(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); if (ConstantInt *C = dyn_cast(v)) { APInt val = C->getValue(); return LL2NUM(val.getLimitedValue()); } else { rb_raise(rb_eTypeError, "Argument not an integer constant"); } } VALUE llvm_value_get_float_constant_value(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); if (ConstantFP *C = dyn_cast(v)) { APFloat val = C->getValueAPF(); return rb_float_new(val.convertToFloat()); } else { rb_raise(rb_eTypeError, "Argument not a float constant"); } } VALUE llvm_value_is_null(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); if (Constant *C = dyn_cast(v)) return C->isNullValue() ? Qtrue : Qfalse; return Qfalse; } VALUE llvm_value_is_undef(VALUE self) { Value *v; Data_Get_Struct(self, Value, v); return isa(v) ? Qtrue : Qfalse; } 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 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 = VectorType::get(type, FIX2INT(size)); return Data_Wrap_Struct(cLLVMVectorType, NULL, NULL, type); } VALUE llvm_type_function(int argc, VALUE *argv, VALUE self) { VALUE rret_type, rarg_types, var_args; rb_scan_args(argc, argv, "21", &rret_type, &rarg_types, &var_args); std::vector arg_types; for(int i = 0; i < RARRAY_LEN(rarg_types); ++i) { VALUE v = RARRAY_PTR(rarg_types)[i]; arg_types.push_back(LLVM_TYPE(v)); } const Type *ret_type = LLVM_TYPE(rret_type); FunctionType *ftype = FunctionType::get(ret_type, arg_types, RTEST(var_args)); return Data_Wrap_Struct(cLLVMFunctionType, NULL, NULL, ftype); } VALUE llvm_type_to_s(VALUE self) { Type *type; Data_Get_Struct(self, Type, type); return rb_str_new2(type->getDescription().c_str()); } VALUE llvm_type_type_id(VALUE self) { Type *type; Data_Get_Struct(self, Type, type); return INT2FIX((int) type->getTypeID()); } void init_types() { rb_define_const(cLLVMType, "Int1Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::Int1Ty))); rb_define_const(cLLVMType, "Int8Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::Int8Ty))); rb_define_const(cLLVMType, "Int16Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::Int16Ty))); rb_define_const(cLLVMType, "Int32Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::Int32Ty))); rb_define_const(cLLVMType, "Int64Ty", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::Int64Ty))); rb_define_const(cLLVMType, "VoidTy", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::VoidTy))); rb_define_const(cLLVMType, "LabelTy", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::LabelTy))); rb_define_const(cLLVMType, "FloatTy", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::FloatTy))); rb_define_const(cLLVMType, "DoubleTy", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(Type::DoubleTy))); // Figure out details of the target machine const IntegerType *machine_word_type; if(sizeof(void*) == 4) { machine_word_type = Type::Int32Ty; } else { machine_word_type = Type::Int64Ty; } rb_define_const(cLLVMRuby, "MACHINE_WORD", Data_Wrap_Struct(cLLVMType, NULL, NULL, const_cast(machine_word_type))); } }