llvm::Value* CreateExpr::build(FuncBuilder& builder) { auto llvmTypePtr = ctor->getLlvmType(builder.modBuilder); auto llvmType = llvmTypePtr->getTypeAtIndex(0u); auto BB = builder.ir.GetInsertBlock(); auto sizeOf = llvm::ConstantExpr::getSizeOf(llvmType); auto alloc = llvm::CallInst::CreateMalloc( BB, sizeOf->getType(), llvmType, sizeOf); BB->getInstList().push_back(alloc); for(auto i = 0u; i < parameters.size(); ++i) { auto slot = builder.ir.CreateStructGEP(alloc, i + 2); auto value = parameters[i]->build(builder); builder.ir.CreateStore(value, slot); } auto rcSlot = builder.ir.CreateStructGEP(alloc, 0); builder.ir.CreateStore(builder.ir.getInt32(1), rcSlot); auto tagSlot = builder.ir.CreateStructGEP(alloc, 1); builder.ir.CreateStore(builder.ir.getInt32(ctor->tag), tagSlot); return builder.ir.CreateBitCast(alloc, type->llvmType(builder.modBuilder)); }
// make a copy of all blocks and instructions in srcblocks // - map values to clones // - redirect srcTarget to continueWith // - set "funclet" attribute inside catch/cleanup pads // - inside funclets, replace "unreachable" with "branch cleanupret" void cloneBlocks(const std::vector<llvm::BasicBlock *> &srcblocks, std::vector<llvm::BasicBlock *> &blocks, llvm::BasicBlock *continueWith, llvm::BasicBlock *unwindTo, llvm::Value *funclet) { llvm::ValueToValueMapTy VMap; // map the terminal branch to the new target if (continueWith) if (auto term = srcblocks.back()->getTerminator()) if (auto succ = term->getSuccessor(0)) VMap[succ] = continueWith; for (auto bb : srcblocks) { llvm::Function *F = bb->getParent(); auto nbb = llvm::BasicBlock::Create(bb->getContext(), bb->getName()); // Loop over all instructions, and copy them over. for (auto &II : *bb) { llvm::Instruction *Inst = &II; llvm::Instruction *newInst = nullptr; if (funclet && !llvm::isa<llvm::DbgInfoIntrinsic>(Inst)) { // IntrinsicInst? if (auto IInst = llvm::dyn_cast<llvm::InvokeInst>(Inst)) { auto invoke = llvm::InvokeInst::Create( IInst, llvm::OperandBundleDef("funclet", funclet)); newInst = invoke; } else if (auto CInst = llvm::dyn_cast<llvm::CallInst>(Inst)) { auto call = llvm::CallInst::Create( CInst, llvm::OperandBundleDef("funclet", funclet)); newInst = call; } else if (funclet && llvm::isa<llvm::UnreachableInst>(Inst)) { newInst = llvm::BranchInst::Create(continueWith); // to cleanupret } } if (!newInst) newInst = Inst->clone(); nbb->getInstList().push_back(newInst); VMap[Inst] = newInst; // Add instruction map to value. if (unwindTo) if (auto dest = getUnwindDest(Inst)) VMap[dest] = unwindTo; } nbb->insertInto(F, continueWith); VMap[bb] = nbb; blocks.push_back(nbb); } remapBlocks(blocks, VMap); }
std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id) { Guard g{x_cacheMutex}; if (g_mode != CacheMode::on && g_mode != CacheMode::read) return nullptr; // TODO: Disabled because is not thread-safe. //if (g_listener) // g_listener->stateChanged(ExecState::CacheLoad); DLOG(cache) << id << ": search\n"; if (!CHECK(!g_lastObject)) g_lastObject = nullptr; llvm::SmallString<256> cachePath{getVersionedCacheDir()}; llvm::sys::path::append(cachePath, id); if (auto r = llvm::MemoryBuffer::getFile(cachePath, -1, false)) g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) DLOG(cache) << r.getError().message(); // TODO: Add warning log if (g_lastObject) // if object found create fake module { DLOG(cache) << id << ": found\n"; auto&& context = llvm::getGlobalContext(); auto module = llvm::make_unique<llvm::Module>(id, context); auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); bb->getInstList().push_back(new llvm::UnreachableInst{context}); return module; } DLOG(cache) << id << ": not found\n"; return nullptr; }