void BlockBuilder::setup() { std::vector<const Type*> ftypes; ftypes.push_back(ls_->ptr_type("VM")); ftypes.push_back(ls_->ptr_type("CallFrame")); ftypes.push_back(ls_->ptr_type("BlockEnvironment")); ftypes.push_back(ls_->ptr_type("Arguments")); ftypes.push_back(ls_->ptr_type("BlockInvocation")); FunctionType* ft = FunctionType::get(ls_->ptr_type("Object"), ftypes, false); std::stringstream ss; ss << std::string("_X_") << ls_->enclosure_name(info_.method()) << "#" << ls_->symbol_cstr(info_.method()->name()) << "$block@" << ls_->add_jitted_method(); func = Function::Create(ft, GlobalValue::ExternalLinkage, ss.str().c_str(), ls_->module()); Function::arg_iterator ai = func->arg_begin(); vm = ai++; vm->setName("state"); prev = ai++; prev->setName("previous"); block_env = ai++; block_env->setName("env"); args = ai++; args->setName("args"); block_inv = ai++; block_inv->setName("invocation"); BasicBlock* block = BasicBlock::Create(ls_->ctx(), "entry", func); b().SetInsertPoint(block); info_.set_function(func); info_.set_vm(vm); info_.set_args(args); info_.set_previous(prev); info_.set_entry(block); BasicBlock* body = BasicBlock::Create(ls_->ctx(), "block_body", func); pass_one(body); info_.set_counter(b().CreateAlloca(ls_->Int32Ty, 0, "counter_alloca")); counter2_ = b().CreateAlloca(ls_->Int32Ty, 0, "counter2"); // The 3 here is because we store {ip, sp, type} per unwind. info_.set_unwind_info(b().CreateAlloca(ls_->Int32Ty, ConstantInt::get(ls_->Int32Ty, rubinius::kMaxUnwindInfos * 3), "unwind_info")); valid_flag = b().CreateAlloca(ls_->Int1Ty, 0, "valid_flag"); Value* cfstk = b().CreateAlloca(obj_type, ConstantInt::get(ls_->Int32Ty, (sizeof(CallFrame) / sizeof(Object*)) + vmm_->stack_size), "cfstk"); call_frame = b().CreateBitCast( cfstk, llvm::PointerType::getUnqual(cf_type), "call_frame"); info_.set_out_args(b().CreateAlloca(ls_->type("Arguments"), 0, "out_args")); if(ls_->include_profiling()) { method_entry_ = b().CreateAlloca(ls_->Int8Ty, ConstantInt::get(ls_->Int32Ty, sizeof(tooling::MethodEntry)), "method_entry"); info_.set_profiling_entry(method_entry_); } info_.set_call_frame(call_frame); stk = b().CreateConstGEP1_32(cfstk, sizeof(CallFrame) / sizeof(Object*), "stack"); info_.set_stack(stk); Value* var_mem = b().CreateAlloca(obj_type, ConstantInt::get(ls_->Int32Ty, (sizeof(StackVariables) / sizeof(Object*)) + vmm_->number_of_locals), "var_mem"); vars = b().CreateBitCast( var_mem, llvm::PointerType::getUnqual(stack_vars_type), "vars"); info_.set_variables(vars); initialize_frame(vmm_->stack_size); nil_stack(vmm_->stack_size, constant(Qnil, obj_type)); setup_block_scope(); if(ls_->config().version >= 19) { import_args_19_style(); } if(ls_->include_profiling()) { Value* test = b().CreateLoad(ls_->profiling(), "profiling"); BasicBlock* setup_profiling = BasicBlock::Create(ls_->ctx(), "setup_profiling", func); BasicBlock* cont = BasicBlock::Create(ls_->ctx(), "continue", func); b().CreateCondBr(test, setup_profiling, cont); b().SetInsertPoint(setup_profiling); Signature sig(ls_, ls_->VoidTy); sig << "VM"; sig << llvm::PointerType::getUnqual(ls_->Int8Ty); sig << "BlockEnvironment"; sig << "Module"; sig << "CompiledMethod"; Value* call_args[] = { vm, method_entry_, block_env, module_, method }; sig.call("rbx_begin_profiling_block", call_args, 5, "", b()); b().CreateBr(cont); b().SetInsertPoint(cont); } b().CreateBr(body); b().SetInsertPoint(body); }
void MethodBuilder::import_args() { setup_scope(); if(vmm_->post_args > 0) { import_args_19_style(); return; } // Import the arguments Value* offset = b().CreateConstGEP2_32(info_.args(), 0, offset::args_ary, "arg_ary_pos"); Value* arg_ary = b().CreateLoad(offset, "arg_ary"); // If there are a precise number of args, easy. if(vmm_->required_args == vmm_->total_args) { for(int i = 0; i < vmm_->required_args; i++) { Value* int_pos = cint(i); Value* arg_val_offset = b().CreateConstGEP1_32(arg_ary, i, "arg_val_offset"); Value* arg_val = b().CreateLoad(arg_val_offset, "arg_val"); Value* idx2[] = { cint(0), cint(offset::vars_tuple), int_pos }; Value* pos = b().CreateGEP(vars, idx2, "var_pos"); b().CreateStore(arg_val, pos); } // Otherwise, we must loop in the generate code because we don't know // how many they've actually passed in. } else { Value* loop_i = info_.counter(); BasicBlock* top = info_.new_block("arg_loop_top"); BasicBlock* body = info_.new_block("arg_loop_body"); BasicBlock* after = info_.new_block("arg_loop_cont"); Value* limit; // Because of a splat, there can be more args given than // vmm->total_args, so we need to use vmm->total_args as a max. if(vmm_->splat_position >= 0) { Value* static_total = cint(vmm_->total_args); limit = b().CreateSelect( b().CreateICmpSLT(static_total, arg_total), static_total, arg_total); } else { // Because of arity checks, arg_total is less than or equal // to vmm->total_args. limit = arg_total; } b().CreateStore(cint(0), loop_i); b().CreateBr(top); b().SetInsertPoint(top); // now at the top of block, check if we should continue... Value* loop_val = b().CreateLoad(loop_i, "loop_val"); Value* cmp = b().CreateICmpSLT(loop_val, limit, "loop_test"); b().CreateCondBr(cmp, body, after); // Now, the body b().SetInsertPoint(body); Value* arg_val_offset = b().CreateGEP(arg_ary, loop_val, "arg_val_offset"); Value* arg_val = b().CreateLoad(arg_val_offset, "arg_val"); Value* idx2[] = { cint(0), cint(offset::vars_tuple), loop_val }; Value* pos = b().CreateGEP(vars, idx2, "var_pos"); b().CreateStore(arg_val, pos); Value* plus_one = b().CreateAdd(loop_val, cint(1), "add"); b().CreateStore(plus_one, loop_i); b().CreateBr(top); b().SetInsertPoint(after); } // Setup the splat. if(vmm_->splat_position >= 0) { Signature sig(ls_, "Object"); sig << "VM"; sig << "Arguments"; sig << ls_->Int32Ty; sig << ls_->Int32Ty; Value* call_args[] = { info_.vm(), info_.args(), cint(vmm_->total_args), cint(vmm_->total_args) }; Function* func = sig.function("rbx_construct_splat"); func->setOnlyReadsMemory(true); func->setDoesNotThrow(true); CallInst* splat_val = sig.call("rbx_construct_splat", call_args, 4, "splat_val", b()); splat_val->setOnlyReadsMemory(true); splat_val->setDoesNotThrow(true); Value* idx3[] = { cint(0), cint(offset::vars_tuple), cint(vmm_->splat_position) }; Value* pos = b().CreateGEP(vars, idx3, "splat_pos"); b().CreateStore(splat_val, pos); } }
void BlockBuilder::setup() { std::vector<const Type*> ftypes; ftypes.push_back(ls_->ptr_type("VM")); ftypes.push_back(ls_->ptr_type("CallFrame")); ftypes.push_back(ls_->ptr_type("BlockEnvironment")); ftypes.push_back(ls_->ptr_type("Arguments")); ftypes.push_back(ls_->ptr_type("BlockInvocation")); FunctionType* ft = FunctionType::get(ls_->ptr_type("Object"), ftypes, false); std::ostringstream ss; ss << std::string("_X_") << ls_->enclosure_name(info_.method()) << "#" << ls_->symbol_debug_str(info_.method()->name()) << "$block@" << ls_->add_jitted_method(); llvm::Function* func = Function::Create(ft, GlobalValue::ExternalLinkage, ss.str().c_str(), ls_->module()); Function::arg_iterator ai = func->arg_begin(); llvm::Value* vm = ai++; vm->setName("state"); llvm::Value* prev = ai++; prev->setName("previous"); block_env = ai++; block_env->setName("env"); llvm::Value* args = ai++; args->setName("args"); block_inv = ai++; block_inv->setName("invocation"); BasicBlock* block = BasicBlock::Create(ls_->ctx(), "entry", func); b().SetInsertPoint(block); info_.context().set_function(func); info_.set_vm(vm); info_.set_args(args); info_.set_previous(prev); info_.set_entry(block); alloc_frame("block_body"); initialize_frame(vmm_->stack_size); nil_stack(vmm_->stack_size, constant(Qnil, obj_type)); setup_block_scope(); if(ls_->config().version >= 19) { import_args_19_style(); } if(ls_->include_profiling()) { Value* test = b().CreateLoad(ls_->profiling(), "profiling"); BasicBlock* setup_profiling = BasicBlock::Create(ls_->ctx(), "setup_profiling", func); BasicBlock* cont = BasicBlock::Create(ls_->ctx(), "continue", func); b().CreateCondBr(test, setup_profiling, cont); b().SetInsertPoint(setup_profiling); Signature sig(ls_, ls_->VoidTy); sig << "VM"; sig << llvm::PointerType::getUnqual(ls_->Int8Ty); sig << "BlockEnvironment"; sig << "Module"; sig << "CompiledMethod"; Value* call_args[] = { vm, method_entry_, block_env, module_, method }; sig.call("rbx_begin_profiling_block", call_args, 5, "", b()); b().CreateBr(cont); b().SetInsertPoint(cont); } b().CreateBr(body_); b().SetInsertPoint(body_); }