llvm::BasicBlock *CleanupScope::runCopying(IRState &irs, llvm::BasicBlock *sourceBlock, llvm::BasicBlock *continueWith, llvm::BasicBlock *unwindTo, llvm::Value *funclet) { if (isCatchSwitchBlock(beginBlock())) return continueWith; if (exitTargets.empty()) { if (!endBlock()->getTerminator()) // Set up the unconditional branch at the end of the cleanup llvm::BranchInst::Create(continueWith, endBlock()); } else { // check whether we have an exit target with the same continuation for (CleanupExitTarget &tgt : exitTargets) if (tgt.branchTarget == continueWith) { tgt.sourceBlocks.push_back(sourceBlock); return tgt.cleanupBlocks.front(); } } // reuse the original IR if not unwinding and not already used bool useOriginal = unwindTo == nullptr && funclet == nullptr; for (CleanupExitTarget &tgt : exitTargets) { if (tgt.cleanupBlocks.front() == beginBlock()) { useOriginal = false; break; } } // append new target exitTargets.emplace_back(continueWith); auto &exitTarget = exitTargets.back(); exitTarget.sourceBlocks.push_back(sourceBlock); if (useOriginal) { // change the continuation target if the initial branch was created // by another instance with unwinding if (continueWith) if (auto term = endBlock()->getTerminator()) if (auto succ = term->getSuccessor(0)) if (succ != continueWith) remapBlocksValue(blocks, succ, continueWith); exitTarget.cleanupBlocks = blocks; } else { // clone the code cloneBlocks(blocks, exitTarget.cleanupBlocks, continueWith, unwindTo, funclet); } return exitTarget.cleanupBlocks.front(); }
static void parseBlock( const Block *block ) { startBlock(block); auto p = block->chunk->getData(); auto header = p; SKIP(uint32_t, version, p); SKIP(uint256_t, prevBlkHash, p); SKIP(uint256_t, blkMerkleRoot, p); SKIP(uint32_t, blkTime, p); SKIP(uint32_t, blkBits, p); SKIP(uint32_t, blkNonce, p); #if defined PROTOSHARES SKIP(uint32_t, nBirthdayA, p); SKIP(uint32_t, nBirthdayB, p); #endif startTXs(p); LOAD_VARINT(nbTX, p); for(uint64_t txIndex=0; likely(txIndex<nbTX); ++txIndex) { parseTX<false>(block, p); } endTXs(p); #if defined(PEERCOIN) || defined(CLAM) || defined(JUMBUCKS) LOAD_VARINT(vchBlockSigSize, p); p += vchBlockSigSize; #endif block->chunk->releaseData(); endBlock(block); }
static void parseBlock( const Block *block ) { startBlock(block); const uint8_t *p = block->data; const uint8_t *header = p; SKIP(uint32_t, version, p); SKIP(uint256_t, prevBlkHash, p); SKIP(uint256_t, blkMerkleRoot, p); SKIP(uint32_t, blkTime, p); SKIP(uint32_t, blkBits, p); SKIP(uint32_t, blkNonce, p); LOAD_VARINT(nbTX, p); for(uint64_t txIndex=0; likely(txIndex<nbTX); ++txIndex) parseTX<false>(p); endBlock(block); }
void Context::endFunction() { endBlock(); addLine(); }
llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock, llvm::BasicBlock *continueWith) { #if LDC_LLVM_VER >= 308 if (useMSVCEH()) return runCopying(irs, sourceBlock, continueWith); #endif if (exitTargets.empty() || (exitTargets.size() == 1 && exitTargets[0].branchTarget == continueWith)) { // We didn't need a branch selector before and still don't need one. assert(!branchSelector); // Set up the unconditional branch at the end of the cleanup if we have // not done so already. if (exitTargets.empty()) { exitTargets.emplace_back(continueWith); llvm::BranchInst::Create(continueWith, endBlock()); } exitTargets.front().sourceBlocks.push_back(sourceBlock); return beginBlock(); } // We need a branch selector if we are here... if (!branchSelector) { // ... and have not created one yet, so do so now. branchSelector = new llvm::AllocaInst(llvm::Type::getInt32Ty(irs.context()), #if LDC_LLVM_VER >= 500 irs.module.getDataLayout().getAllocaAddrSpace(), #endif llvm::Twine("branchsel.") + beginBlock()->getName(), irs.topallocapoint()); // Now we also need to store 0 to it to keep the paths that go to the // only existing branch target the same. for (auto bb : exitTargets.front().sourceBlocks) { new llvm::StoreInst(DtoConstUint(0), branchSelector, bb->getTerminator()); } // And convert the BranchInst to the existing branch target to a // SelectInst so we can append the other cases to it. endBlock()->getTerminator()->eraseFromParent(); llvm::Value *sel = new llvm::LoadInst(branchSelector, "", endBlock()); llvm::SwitchInst::Create( sel, exitTargets[0].branchTarget, 1, // Expected number of branches, only for pre-allocating. endBlock()); } // If we already know this branch target, figure out the branch selector // value and simply insert the store into the source block (prior to the // last instruction, which is the branch to the first cleanup). for (unsigned i = 0; i < exitTargets.size(); ++i) { CleanupExitTarget &t = exitTargets[i]; if (t.branchTarget == continueWith) { new llvm::StoreInst(DtoConstUint(i), branchSelector, sourceBlock->getTerminator()); // Note: Strictly speaking, keeping this up to date would not be // needed right now, because we never to any optimizations that // require changes to the source blocks after the initial conversion // from one to two branch targets. Keeping this around for now to // ease future development, but may be removed to save some work. t.sourceBlocks.push_back(sourceBlock); return beginBlock(); } } // We don't know this branch target yet, so add it to the SwitchInst... llvm::ConstantInt *const selectorVal = DtoConstUint(exitTargets.size()); llvm::cast<llvm::SwitchInst>(endBlock()->getTerminator()) ->addCase(selectorVal, continueWith); // ... insert the store into the source block... new llvm::StoreInst(selectorVal, branchSelector, sourceBlock->getTerminator()); // ... and keep track of it (again, this is unnecessary right now as // discussed in the above note). exitTargets.emplace_back(continueWith); exitTargets.back().sourceBlocks.push_back(sourceBlock); return beginBlock(); }
static void buildBlockHeaders() { info("pass 1 -- walk all blocks and build headers ..."); size_t nbBlocks = 0; size_t baseOffset = 0; size_t earlyMissCnt = 0; uint8_t buf[8+gHeaderSize]; const auto sz = sizeof(buf); const auto startTime = usecs(); const auto oneMeg = 1024 * 1024; for(const auto &map : mapVec) { startMap(0); while(1) { auto nbRead = read(map.fd, buf, sz); if(nbRead<(signed)sz) { break; } startBlock((uint8_t*)0); uint8_t *hash = 0; Block *prevBlock = 0; size_t blockSize = 0; getBlockHeader(blockSize, prevBlock, hash, earlyMissCnt, buf); if(unlikely(0==hash)) { break; } auto where = lseek(map.fd, (blockSize + 8) - sz, SEEK_CUR); auto blockOffset = where - blockSize; if(where<0) { break; } auto block = Block::alloc(); block->init(hash, &map, blockSize, prevBlock, blockOffset); gBlockMap[hash] = block; endBlock((uint8_t*)0); ++nbBlocks; } baseOffset += map.size; auto now = usecs(); auto elapsed = now - startTime; auto bytesPerSec = baseOffset / (elapsed*1e-6); auto bytesLeft = gChainSize - baseOffset; auto secsLeft = bytesLeft / bytesPerSec; fprintf( stderr, "%.2f%% (%.2f/%.2f Gigs) -- %6d blocks -- %.2f Megs/sec -- ETA %.0f secs -- ELAPSED %.0f secs \r", (100.0*baseOffset)/gChainSize, baseOffset/(1000.0*oneMeg), gChainSize/(1000.0*oneMeg), (int)nbBlocks, bytesPerSec*1e-6, secsLeft, elapsed*1e-6 ); fflush(stderr); endMap(0); } if(0==nbBlocks) { warning("found no blocks - giving up"); exit(1); } char msg[128]; msg[0] = 0; if(0<earlyMissCnt) { sprintf(msg, ", %d early link misses", (int)earlyMissCnt); } auto elapsed = 1e-6*(usecs() - startTime); info( "pass 1 -- took %.0f secs, %6d blocks, %.2f Gigs, %.2f Megs/secs %s ", elapsed, (int)nbBlocks, (gChainSize * 1e-9), (gChainSize * 1e-6) / elapsed, msg ); }