TypeVec getTypes() { TypeVec types; // init types with predefined species (if any) vector<string> species = strsplit(args.getCString("species")); for (size_t i = 0; i < species.size(); ++i) { types.push_back(Type(species[i].c_str(), types.size())); } return types; }
NNModule_(NNModule* o) : o_(o), context_(getGlobalContext()), module_("NNModule", context_), builder_(context_){ _mutex.lock(); if(!_initialized){ InitializeNativeTarget(); _initialized = true; } _mutex.unlock(); engine_ = EngineBuilder(&module_).setUseMCJIT(true).create(); TypeVec args; args.push_back(doubleType()); createExtern("llvm.exp.f64", doubleType(), args); }
static const TypeVec throwsException(const FunctionDecl *Func, llvm::SmallSet<const FunctionDecl *, 32> &CallStack) { if (CallStack.count(Func)) return TypeVec(); if (const Stmt *Body = Func->getBody()) { CallStack.insert(Func); const TypeVec Result = throwsException(Body, TypeVec(), CallStack); CallStack.erase(Func); return Result; } TypeVec Result; if (const auto *FPT = Func->getType()->getAs<FunctionProtoType>()) { for (const QualType Ex : FPT->exceptions()) { Result.push_back(Ex.getTypePtr()); } } return Result; }
static const TypeVec throwsException(const Stmt *St, const TypeVec &Caught, llvm::SmallSet<const FunctionDecl *, 32> &CallStack) { TypeVec Results; if (!St) return Results; if (const auto *Throw = dyn_cast<CXXThrowExpr>(St)) { if (const auto *ThrownExpr = Throw->getSubExpr()) { const auto *ThrownType = ThrownExpr->getType()->getUnqualifiedDesugaredType(); if (ThrownType->isReferenceType()) { ThrownType = ThrownType->castAs<ReferenceType>() ->getPointeeType() ->getUnqualifiedDesugaredType(); } if (const auto *TD = ThrownType->getAsTagDecl()) { if (TD->getDeclName().isIdentifier() && TD->getName() == "bad_alloc" && TD->isInStdNamespace()) return Results; } Results.push_back(ThrownExpr->getType()->getUnqualifiedDesugaredType()); } else { Results.append(Caught.begin(), Caught.end()); } } else if (const auto *Try = dyn_cast<CXXTryStmt>(St)) { TypeVec Uncaught = throwsException(Try->getTryBlock(), Caught, CallStack); for (unsigned i = 0; i < Try->getNumHandlers(); ++i) { const CXXCatchStmt *Catch = Try->getHandler(i); if (!Catch->getExceptionDecl()) { const TypeVec Rethrown = throwsException(Catch->getHandlerBlock(), Uncaught, CallStack); Results.append(Rethrown.begin(), Rethrown.end()); Uncaught.clear(); } else { const auto *CaughtType = Catch->getCaughtType()->getUnqualifiedDesugaredType(); if (CaughtType->isReferenceType()) { CaughtType = CaughtType->castAs<ReferenceType>() ->getPointeeType() ->getUnqualifiedDesugaredType(); } auto NewEnd = llvm::remove_if(Uncaught, [&CaughtType](const Type *ThrownType) { return ThrownType == CaughtType || isBaseOf(ThrownType, CaughtType); }); if (NewEnd != Uncaught.end()) { Uncaught.erase(NewEnd, Uncaught.end()); const TypeVec Rethrown = throwsException( Catch->getHandlerBlock(), TypeVec(1, CaughtType), CallStack); Results.append(Rethrown.begin(), Rethrown.end()); } } } Results.append(Uncaught.begin(), Uncaught.end()); } else if (const auto *Call = dyn_cast<CallExpr>(St)) { if (const FunctionDecl *Func = Call->getDirectCallee()) { TypeVec Excs = throwsException(Func, CallStack); Results.append(Excs.begin(), Excs.end()); } } else { for (const Stmt *Child : St->children()) { TypeVec Excs = throwsException(Child, Caught, CallStack); Results.append(Excs.begin(), Excs.end()); } } return Results; }
void HLIRTask::setFunction(const HLIRFunction& func){ auto& b = module_->builder(); auto& c = module_->context(); (*this)["function"] = func; TypeVec params = {module_->voidPtrTy}; auto funcType = FunctionType::get(module_->voidTy, params, false); Function* wrapperFunc = Function::Create(funcType, llvm::Function::ExternalLinkage, "hlir.task_wrapper", module_->module()); auto aitr = wrapperFunc->arg_begin(); aitr->setName("args.ptr"); Value* argsVoidPtr = aitr++; BasicBlock* entry = BasicBlock::Create(c, "entry", wrapperFunc); b.SetInsertPoint(entry); TypeVec fields; fields.push_back(module_->voidPtrTy); fields.push_back(module_->i32Ty); fields.push_back(func->getReturnType()); for(auto pitr = func->arg_begin(), pitrEnd = func->arg_end(); pitr != pitrEnd; ++pitr){ fields.push_back(pitr->getType()); } StructType* argsType = StructType::create(c, fields, "struct.func_args"); ValueVec args; Value* argsPtr = b.CreateBitCast(argsVoidPtr, PointerType::get(argsType, 0), "argsPtr"); size_t idx = 3; for(auto pitr = func->arg_begin(), pitrEnd = func->arg_end(); pitr != pitrEnd; ++pitr){ Value* arg = b.CreateStructGEP(nullptr, argsPtr, idx, "arg.ptr"); arg = b.CreateLoad(arg, "arg"); args.push_back(arg); ++idx; } Value* ret = b.CreateCall(func, args, "ret"); Value* retPtr = b.CreateStructGEP(nullptr, argsPtr, 2, "retPtr"); b.CreateStore(ret, retPtr); Function* releaseFunc = module_->getFunction("__ares_task_release_future", {module_->voidPtrTy}); args = {argsVoidPtr}; b.CreateCall(releaseFunc, args); b.CreateRetVoid(); (*this)["wrapperFunction"] = HLIRFunction(wrapperFunc); }
void HLIRModule::lowerTask_(HLIRTask* task){ auto& b = builder(); auto& c = context(); DataLayout layout(module_); Function* func = task->function(); Function* wrapperFunc = task->wrapperFunction(); for(auto itr = func->use_begin(), itrEnd = func->use_end(); itr != itrEnd; ++itr){ if(CallInst* ci = dyn_cast<CallInst>(itr->getUser())){ BasicBlock* parentBlock = ci->getParent(); Function* parentFunc = parentBlock->getParent(); if(parentFunc == wrapperFunc){ continue; } b.SetInsertPoint(ci); TypeVec fields; fields.push_back(voidPtrTy); fields.push_back(i32Ty); fields.push_back(func->getReturnType()); for(auto pitr = func->arg_begin(), pitrEnd = func->arg_end(); pitr != pitrEnd; ++pitr){ fields.push_back(pitr->getType()); } StructType* argsType = StructType::create(c, fields, "struct.func_args"); size_t size = layout.getTypeAllocSize(argsType); Function* allocFunc = getFunction("__ares_alloc", {i64Ty}, voidPtrTy); ValueVec args = {ConstantInt::get(i64Ty, size)}; Value* argsVoidPtr = b.CreateCall(allocFunc, args, "args.void.ptr"); Value* argsPtr = b.CreateBitCast(argsVoidPtr, PointerType::get(argsType, 0), "args.ptr"); Value* depth = b.CreateStructGEP(nullptr, argsPtr, 1, "depth.ptr"); depth = b.CreateLoad(depth, "depth"); size_t idx = 3; for(auto& arg : ci->arg_operands()){ Value* argPtr = b.CreateStructGEP(nullptr, argsPtr, idx, "arg.ptr"); b.CreateStore(arg, argPtr); ++idx; } Function* queueFunc = getFunction("__ares_task_queue", {voidPtrTy, voidPtrTy}); Value* funcVoidPtr = b.CreateBitCast(wrapperFunc, voidPtrTy, "funcVoidPtr"); args = {funcVoidPtr, argsVoidPtr}; b.CreateCall(queueFunc, args); for(auto itr = ci->use_begin(), itrEnd = ci->use_end(); itr != itrEnd; ++itr){ if(Instruction* i = dyn_cast<Instruction>(itr->getUser())){ b.SetInsertPoint(i); Function* awaitFunc = getFunction("__ares_task_await_future", {voidPtrTy}); args = {argsVoidPtr}; b.CreateCall(awaitFunc, args); Value* retPtr = b.CreateStructGEP(nullptr, argsPtr, 2, "retPtr"); Value* retVal = b.CreateLoad(retPtr, "retVal"); ci->replaceAllUsesWith(retVal); break; } } ci->eraseFromParent(); //parentFunc->dump(); } } }
static void DtoCreateNestedContextType(FuncDeclaration* fd) { Logger::println("DtoCreateNestedContextType for %s", fd->toChars()); LOG_SCOPE DtoDeclareFunction(fd); if (fd->ir.irFunc->nestedContextCreated) return; fd->ir.irFunc->nestedContextCreated = true; if (fd->nestedVars.empty()) { // fill nestedVars size_t nnest = fd->closureVars.dim; for (size_t i = 0; i < nnest; ++i) { VarDeclaration* vd = static_cast<VarDeclaration*>(fd->closureVars.data[i]); fd->nestedVars.insert(vd); } } // construct nested variables array if (!fd->nestedVars.empty()) { Logger::println("has nested frame"); // start with adding all enclosing parent frames until a static parent is reached LLStructType* innerFrameType = NULL; unsigned depth = -1; if (!fd->isStatic()) { if (FuncDeclaration* parfd = getParentFunc(fd, true)) { // Make sure the parent has already been analyzed. DtoCreateNestedContextType(parfd); innerFrameType = parfd->ir.irFunc->frameType; if (innerFrameType) depth = parfd->ir.irFunc->depth; } } fd->ir.irFunc->depth = ++depth; Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; typedef std::vector<LLType*> TypeVec; TypeVec types; if (depth != 0) { assert(innerFrameType); // Add frame pointer types for all but last frame if (depth > 1) { for (unsigned i = 0; i < (depth - 1); ++i) { types.push_back(innerFrameType->getElementType(i)); } } // Add frame pointer type for last frame types.push_back(LLPointerType::getUnqual(innerFrameType)); } if (Logger::enabled() && depth != 0) { Logger::println("Frame types: "); LOG_SCOPE; for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) Logger::cout() << **i << '\n'; } // Add the direct nested variables of this function, and update their indices to match. // TODO: optimize ordering for minimal space usage? for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { VarDeclaration* vd = *i; if (!vd->ir.irLocal) vd->ir.irLocal = new IrLocal(vd); vd->ir.irLocal->nestedIndex = types.size(); vd->ir.irLocal->nestedDepth = depth; if (vd->isParameter()) { // Parameters will have storage associated with them (to handle byref etc.), // so handle those cases specially by storing a pointer instead of a value. const IrParameter* irparam = vd->ir.irParam; const bool refout = vd->storage_class & (STCref | STCout); const bool lazy = vd->storage_class & STClazy; const bool byref = irparam->arg->byref; const bool isVthisPtr = irparam->isVthis && !byref; if (!(refout || (byref && !lazy)) || isVthisPtr) { // This will be copied to the nesting frame. if (lazy) types.push_back(irparam->value->getType()->getContainedType(0)); else types.push_back(DtoType(vd->type)); } else { types.push_back(irparam->value->getType()); } } else if (isSpecialRefVar(vd)) { types.push_back(DtoType(vd->type->pointerTo())); } else { types.push_back(DtoType(vd->type)); } if (Logger::enabled()) { Logger::cout() << "Nested var '" << vd->toChars() << "' of type " << *types.back() << "\n"; } } LLStructType* frameType = LLStructType::create(gIR->context(), types, std::string("nest.") + fd->toChars()); Logger::cout() << "frameType = " << *frameType << '\n'; // Store type in IrFunction fd->ir.irFunc->frameType = frameType; } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { // Propagate context arg properties if the context arg is passed on unmodified. DtoCreateNestedContextType(parFunc); fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } }
bool compile(const nstr& name, NNet& network, size_t threads){ RunNetwork* runNetwork = new RunNetwork; NNet::Layer* inputLayer = network.layer(0); size_t numLayers = network.numLayers(); RunLayer* lastRunLayer = 0; for(size_t l = 1; l < numLayers; ++l){ RunLayer* runLayer = new RunLayer; runLayer->queue = new Queue(threads); size_t inputLayerSize = inputLayer->size(); NNet::Layer* layer = network.layer(l); size_t layerSize = layer->size(); if(l > 1){ runLayer->inputVecStart = lastRunLayer->outputVecStart; runLayer->inputVec = lastRunLayer->outputVec; } if(l < numLayers - 1){ double* outputVecPtrStart; double* outputVecPtr; allocVector(layerSize, &outputVecPtrStart, &outputVecPtr); runLayer->outputVecStart = outputVecPtrStart; runLayer->outputVec = outputVecPtr; } TypeVec args; args.push_back(getPointer(doubleVecType(inputLayerSize))); args.push_back(getPointer(doubleVecType(inputLayerSize))); args.push_back(getPointer(doubleType())); args.push_back(int32Type()); FunctionType* ft = FunctionType::get(voidType(), args, false); Function* f = Function::Create(ft, Function::ExternalLinkage, name.c_str(), &module_); BasicBlock* entry = BasicBlock::Create(context_, "entry", f); builder_.SetInsertPoint(entry); auto aitr = f->arg_begin(); Value* inputVecPtr = aitr; inputVecPtr->setName("input_vec_ptr"); ++aitr; Value* weightVecPtr = aitr; weightVecPtr->setName("weight_vec_ptr"); ++aitr; Value* outputVecPtr = aitr; outputVecPtr->setName("output_vec_ptr"); ++aitr; Value* outputIndex = aitr; outputIndex->setName("output_index"); Value* inputVec = builder_.CreateLoad(inputVecPtr, "input_vec"); Value* weightVec = builder_.CreateLoad(weightVecPtr, "weight_vec"); Value* mulVec = builder_.CreateFMul(inputVec, weightVec, "mul_vec"); Value* sumActivation = builder_.CreateExtractElement(mulVec, getInt32(0), "sum_elem"); for(size_t i = 1; i < inputLayerSize; ++i){ Value* elem = builder_.CreateExtractElement(mulVec, getInt32(i), "sum_elem"); sumActivation = builder_.CreateFAdd(sumActivation, elem, "sum_activation"); } Value* output = getActivationOutput(layer->neuron(0), sumActivation); Value* outputElement = builder_.CreateGEP(outputVecPtr, outputIndex, "out_elem"); builder_.CreateStore(output, outputElement); builder_.CreateRetVoid(); runLayer->f = f; runLayer->fp = (void (*)(void*, void*, void*, int)) engine_->getPointerToFunction(f); for(size_t j = 0; j < layerSize; ++j){ NNet::Neuron* nj = layer->neuron(j); RunNeuron* runNeuron = new RunNeuron; runNeuron->layer = runLayer; runNeuron->outputIndex = j; double* weightVecPtrStart; double* weightVecPtr; allocVector(inputLayerSize, &weightVecPtrStart, &weightVecPtr); runNeuron->weightVecStart = weightVecPtrStart; runNeuron->weightVec = weightVecPtr; for(size_t i = 0; i < inputLayerSize; ++i){ NNet::Neuron* ni = inputLayer->neuron(i); weightVecPtr[i] = nj->weight(ni); } runLayer->queue->add(runNeuron); } runNetwork->layerVec.push_back(runLayer); inputLayer = layer; lastRunLayer = runLayer; } networkMap_.insert(make_pair(name, runNetwork)); return true; }