llvm::Type* LLVMCodeGenerator::_llvm_type(SLTypePtr type) { switch (type->type()) { case SLTypeTypeNullPointer: return llvm::Type::getInt8Ty(_context)->getPointerTo(); case SLTypeTypePointer: case SLTypeTypeReference: // llvm doesn't do void pointers return type->pointed_to_type()->type() == SLTypeTypeVoid ? llvm::Type::getInt8Ty(_context)->getPointerTo() : _llvm_type(type->pointed_to_type())->getPointerTo(); case SLTypeTypeAuto: assert(false); case SLTypeTypeVoid: return llvm::Type::getVoidTy(_context); case SLTypeTypeBool: return llvm::Type::getInt1Ty(_context); case SLTypeTypeInt8: return llvm::Type::getInt8Ty(_context); case SLTypeTypeInt32: return llvm::Type::getInt32Ty(_context); case SLTypeTypeInt64: return llvm::Type::getInt64Ty(_context); case SLTypeTypeDouble: return llvm::Type::getDoubleTy(_context); case SLTypeTypeFunction: assert(false); // TODO: ??? case SLTypeTypeStruct: { llvm::StructType* ret = nullptr; if (!_named_types.count(type->global_name())) { _named_types[type->global_name()] = ret = llvm::StructType::create(_context, type->global_name()); } else { auto t = _named_types[type->global_name()]; assert(t->isStructTy()); ret = (llvm::StructType*)t; } if (ret->isOpaque() && type->is_defined()) { std::vector<llvm::Type*> elements; auto& member_vars = type->struct_definition().member_vars(); for (auto& var : member_vars) { elements.push_back(_llvm_type(var.type)); } ret->setBody(elements, true); } return ret; } } assert(false); return llvm::Type::getVoidTy(_context); }
/** * @brief Converts indices of LLVM getelementptr instruction. * * @param[in] base Pointed operand of LLVM getelementptr instruction converted * to an expression in BIR. * @param[in] start First index of LLVM getelementptr instruction to be converted. * @param[in] end End of iterator through LLVM getelementptr instruction indices. */ ShPtr<Expression> LLVMInstructionConverter::convertGEPIndices(ShPtr<Expression> base, llvm::gep_type_iterator start, llvm::gep_type_iterator end) { auto indexOp = base; for (auto i = start; i != end; ++i) { auto index = getConverter()->convertValueToExpression(i.getOperand()); if (i->isStructTy()) { auto indexInt = ucast<ConstInt>(index); indexOp = StructIndexOpExpr::create(indexOp, indexInt); } else { indexOp = ArrayIndexOpExpr::create(indexOp, index); } } return AddressOpExpr::create(indexOp); }
/** * @brief Generates access to aggregate type as a part of conversion of LLVM * instruction insertvalue or extractvalue. * * @param[in] type Type of aggregate type. * @param[in] base Base expression. * @param[in] indices Array of indices. */ ShPtr<Expression> LLVMInstructionConverter::generateAccessToAggregateType( llvm::CompositeType *type, const ShPtr<Expression> &base, const llvm::ArrayRef<unsigned> &indices) { auto typeIt = type; auto access = base; for (const auto &index: indices) { auto indexBir = ConstInt::create(index, COMPOSITE_TYPE_INDEX_SIZE_BITS); if (typeIt->isStructTy()) { access = StructIndexOpExpr::create(access, indexBir); } else if (typeIt->isArrayTy()) { access = ArrayIndexOpExpr::create(access, indexBir); } typeIt = llvm::dyn_cast<llvm::CompositeType>(typeIt->getTypeAtIndex(index)); } return access; }
Continuation* CodeGen::emit_spawn(Continuation* continuation) { assert(continuation->num_args() >= SPAWN_NUM_ARGS && "required arguments are missing"); auto kernel = continuation->arg(SPAWN_ARG_BODY)->as<Global>()->init()->as_continuation(); const size_t num_kernel_args = continuation->num_args() - SPAWN_NUM_ARGS; // build parallel-function signature Array<llvm::Type*> par_args(num_kernel_args); for (size_t i = 0; i < num_kernel_args; ++i) { auto type = continuation->arg(i + SPAWN_NUM_ARGS)->type(); par_args[i] = convert(type); } // fetch values and create a unified struct which contains all values (closure) auto closure_type = convert(world_.tuple_type(continuation->arg_fn_type()->ops().skip_front(SPAWN_NUM_ARGS))); llvm::Value* closure = nullptr; if (closure_type->isStructTy()) { closure = llvm::UndefValue::get(closure_type); for (size_t i = 0; i < num_kernel_args; ++i) closure = irbuilder_.CreateInsertValue(closure, lookup(continuation->arg(i + SPAWN_NUM_ARGS)), unsigned(i)); } else { closure = lookup(continuation->arg(0 + SPAWN_NUM_ARGS)); } // allocate closure object and write values into it auto ptr = irbuilder_.CreateAlloca(closure_type, nullptr); irbuilder_.CreateStore(closure, ptr, false); // create wrapper function and call the runtime // wrapper(void* closure) llvm::Type* wrapper_arg_types[] = { irbuilder_.getInt8PtrTy(0) }; auto wrapper_ft = llvm::FunctionType::get(irbuilder_.getVoidTy(), wrapper_arg_types, false); auto wrapper_name = kernel->unique_name() + "_spawn_thread"; auto wrapper = (llvm::Function*)module_->getOrInsertFunction(wrapper_name, wrapper_ft); auto call = runtime_->spawn_thread(ptr, wrapper); // set insert point to the wrapper function auto old_bb = irbuilder_.GetInsertBlock(); auto bb = llvm::BasicBlock::Create(*context_, wrapper_name, wrapper); irbuilder_.SetInsertPoint(bb); // extract all arguments from the closure auto wrapper_args = wrapper->arg_begin(); auto load_ptr = irbuilder_.CreateBitCast(&*wrapper_args, llvm::PointerType::get(closure_type, 0)); auto val = irbuilder_.CreateLoad(load_ptr); std::vector<llvm::Value*> target_args(num_kernel_args); if (val->getType()->isStructTy()) { for (size_t i = 0; i < num_kernel_args; ++i) target_args[i] = irbuilder_.CreateExtractValue(val, { unsigned(i) }); } else { target_args[0] = val; } // call kernel body auto par_type = llvm::FunctionType::get(irbuilder_.getVoidTy(), llvm_ref(par_args), false); auto kernel_par_func = (llvm::Function*)module_->getOrInsertFunction(kernel->unique_name(), par_type); irbuilder_.CreateCall(kernel_par_func, target_args); irbuilder_.CreateRetVoid(); // restore old insert point irbuilder_.SetInsertPoint(old_bb); // bind parameter of continuation to received handle auto cont = continuation->arg(SPAWN_ARG_RETURN)->as_continuation(); emit_result_phi(cont->param(1), call); return cont; }