line_iterator::line_iterator(const MemoryBuffer &Buffer, char CommentMarker) : Buffer(Buffer.getBufferSize() ? &Buffer : nullptr), CommentMarker(CommentMarker), LineNumber(1), CurrentLine(Buffer.getBufferSize() ? Buffer.getBufferStart() : nullptr, 0) { // Ensure that if we are constructed on a non-empty memory buffer that it is // a null terminated buffer. if (Buffer.getBufferSize()) { assert(Buffer.getBufferEnd()[0] == '\0'); advance(); } }
line_iterator::line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks, char CommentMarker) : Buffer(Buffer.getBufferSize() ? &Buffer : nullptr), CommentMarker(CommentMarker), SkipBlanks(SkipBlanks), LineNumber(1), CurrentLine(Buffer.getBufferSize() ? Buffer.getBufferStart() : nullptr, 0) { // Ensure that if we are constructed on a non-empty memory buffer that it is // a null terminated buffer. if (Buffer.getBufferSize()) { assert(Buffer.getBufferEnd()[0] == '\0'); // Make sure we don't skip a leading newline if we're keeping blanks if (SkipBlanks || !isAtLineEnd(Buffer.getBufferStart())) advance(); } }
void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { Module *M = AuxModule.get(); // Create the new section name, it will consist of the reserved prefix // concatenated with the triple. std::string SectionName = OFFLOAD_BUNDLER_MAGIC_STR; SectionName += CurrentTriple; // Create the constant with the content of the section. For the input we are // bundling into (the host input), this is just a place-holder, so a single // byte is sufficient. assert(HostInputIndex != ~0u && "Host input index undefined??"); Constant *Content; if (NumberOfProcessedInputs == HostInputIndex + 1) { uint8_t Byte[] = {0}; Content = ConstantDataArray::get(VMContext, Byte); } else Content = ConstantDataArray::get( VMContext, ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>( Input.getBufferStart()), Input.getBufferSize())); // Create the global in the desired section. We don't want these globals in // the symbol table, so we mark them private. auto *GV = new GlobalVariable(*M, Content->getType(), /*IsConstant=*/true, GlobalVariable::PrivateLinkage, Content); GV->setSection(SectionName); }
bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { if (DataBuffer.getBufferSize() < sizeof(uint64_t)) return false; uint64_t Magic = *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); return RawInstrProf::getMagic<IntPtrT>() == Magic || sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic; }
bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) { // Verify that this really looks like plain ASCII text by checking a // 'reasonable' number of characters (up to profile magic size). size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t)); StringRef buffer = Buffer.getBufferStart(); return count == 0 || std::all_of(buffer.begin(), buffer.begin() + count, [](char c) { return ::isprint(c) || ::isspace(c); }); }
bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { if (DataBuffer.getBufferSize() < 8) return false; using namespace support; uint64_t Magic = endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart()); return Magic == IndexedInstrProf::Magic; }
static void printFile(const sys::Path *err) { std::string ErrMsg; ErrMsg.clear(); MemoryBuffer *buf = MemoryBuffer::getFile(err->c_str(), &ErrMsg); errs().write(buf->getBufferStart(), buf->getBufferSize()); delete buf; }
// Write one member out to the file. bool Archive::writeMember( const ArchiveMember& member, raw_fd_ostream& ARFile, std::string* ErrMsg ) { uint64_t filepos = ARFile.tell(); filepos -= 8; // Get the data and its size either from the // member's in-memory data or directly from the file. size_t fSize = member.getSize(); const char *data = (const char*)member.getData(); MemoryBuffer *mFile = 0; if (!data) { ErrorOr<std::unique_ptr<MemoryBuffer> > FileOrErr = MemoryBuffer::getFile(member.getPath()); if (!FileOrErr) { if (ErrMsg) *ErrMsg = FileOrErr.getError().message(); return true; } mFile = FileOrErr.get().release(); data = mFile->getBufferStart(); fSize = mFile->getBufferSize(); } int hdrSize = fSize; // Compute the fields of the header ArchiveMemberHeader Hdr; bool writeLongName = fillHeader(member,Hdr,hdrSize); // Write header to archive file ARFile.write((char*)&Hdr, sizeof(Hdr)); // Write the long filename if its long if (writeLongName) { StringRef Name = sys::path::filename(member.getPath()); ARFile.write(Name.data(), Name.size()); } // Write the (possibly compressed) member's content to the file. ARFile.write(data,fSize); // Make sure the member is an even length if ((ARFile.tell() & 1) == 1) ARFile << ARFILE_PAD; // Close the mapped file if it was opened delete mFile; return false; }
void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { // If the current section has size one, that means that the content we are // interested in is the file itself. Otherwise it is the content of the // section. // // TODO: Instead of copying the input file as is, deactivate the section // that is no longer needed. StringRef Content; CurrentSection->getContents(Content); if (Content.size() < 2) OS.write(Input.getBufferStart(), Input.getBufferSize()); else OS.write(Content.data(), Content.size()); }
void LicenseInHeaderRule::run(const ast_matchers::MatchFinder::MatchResult& result) { const TranslationUnitDecl* translationUnitDeclaration = result.Nodes.getNodeAs<TranslationUnitDecl>("translationUnitDecl"); if (translationUnitDeclaration == nullptr) return; if (m_context.licenseTemplateLines.empty()) return; SourceManager& sourceManager = *result.SourceManager; FileID mainFileID = m_context.sourceLocationHelper.GetMainFileID(sourceManager); MemoryBuffer* buffer = sourceManager.getBuffer(mainFileID); const char* bufferChars = buffer->getBufferStart(); int bufferSize = buffer->getBufferSize(); if (bufferSize == 0) return; int bufferPos = 0; int lineNumber = 0; for (const auto& licenseLine : m_context.licenseTemplateLines) { ++lineNumber; StringRef line = GetNextBufferLine(bufferChars, bufferPos, bufferSize); bufferPos += line.size(); bufferPos += 1; // newline character if (line != licenseLine) { StringRef fileName = m_context.sourceLocationHelper.GetCleanFilename(mainFileID, sourceManager); m_context.outputPrinter->PrintRuleViolation( "license header", Severity::Style, boost::str(boost::format("File doesn't have proper license header; expected line was '%s'") % licenseLine), fileName, lineNumber); break; } } }
/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename. static int AnalyzeBitcode() { // Read the input file. MemoryBuffer *MemBuf = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str()); if (MemBuf == 0) return Error("Error reading '" + InputFilename + "'."); if (MemBuf->getBufferSize() & 3) return Error("Bitcode stream should be a multiple of 4 bytes in length"); unsigned char *BufPtr = (unsigned char *)MemBuf->getBufferStart(); unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize(); // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. if (isBitcodeWrapper(BufPtr, EndBufPtr)) if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr)) return Error("Invalid bitcode wrapper header"); BitstreamReader StreamFile(BufPtr, EndBufPtr); BitstreamCursor Stream(StreamFile); StreamFile.CollectBlockInfoNames(); // Read the stream signature. char Signature[6]; Signature[0] = Stream.Read(8); Signature[1] = Stream.Read(8); Signature[2] = Stream.Read(4); Signature[3] = Stream.Read(4); Signature[4] = Stream.Read(4); Signature[5] = Stream.Read(4); // Autodetect the file contents, if it is one we know. CurStreamType = UnknownBitstream; if (Signature[0] == 'B' && Signature[1] == 'C' && Signature[2] == 0x0 && Signature[3] == 0xC && Signature[4] == 0xE && Signature[5] == 0xD) CurStreamType = LLVMIRBitstream; unsigned NumTopBlocks = 0; // Parse the top-level structure. We only allow blocks at the top-level. while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code != bitc::ENTER_SUBBLOCK) return Error("Invalid record at top-level"); if (ParseBlock(Stream, 0)) return true; ++NumTopBlocks; } if (Dump) errs() << "\n\n"; uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT; // Print a summary of the read file. errs() << "Summary of " << InputFilename << ":\n"; errs() << " Total size: "; PrintSize(BufferSizeBits); errs() << "\n"; errs() << " Stream type: "; switch (CurStreamType) { default: assert(0 && "Unknown bitstream type"); case UnknownBitstream: errs() << "unknown\n"; break; case LLVMIRBitstream: errs() << "LLVM IR\n"; break; } errs() << " # Toplevel Blocks: " << NumTopBlocks << "\n"; errs() << "\n"; // Emit per-block stats. errs() << "Per-block Summary:\n"; for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(), E = BlockIDStats.end(); I != E; ++I) { errs() << " Block ID #" << I->first; if (const char *BlockName = GetBlockName(I->first, StreamFile)) errs() << " (" << BlockName << ")"; errs() << ":\n"; const PerBlockIDStats &Stats = I->second; errs() << " Num Instances: " << Stats.NumInstances << "\n"; errs() << " Total Size: "; PrintSize(Stats.NumBits); errs() << "\n"; double pct = (Stats.NumBits * 100.0) / BufferSizeBits; errs() << " Percent of file: " << format("%2.4f%%", pct) << "\n"; if (Stats.NumInstances > 1) { errs() << " Average Size: "; PrintSize(Stats.NumBits/(double)Stats.NumInstances); errs() << "\n"; errs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/" << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n"; errs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/" << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n"; errs() << " Tot/Avg Records: " << Stats.NumRecords << "/" << Stats.NumRecords/(double)Stats.NumInstances << "\n"; } else { errs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n"; errs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n"; errs() << " Num Records: " << Stats.NumRecords << "\n"; } if (Stats.NumRecords) { double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords; errs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n"; } errs() << "\n"; // Print a histogram of the codes we see. if (!NoHistogram && !Stats.CodeFreq.empty()) { std::vector<std::pair<unsigned, unsigned> > FreqPairs; // <freq,code> for (unsigned i = 0, e = Stats.CodeFreq.size(); i != e; ++i) if (unsigned Freq = Stats.CodeFreq[i].NumInstances) FreqPairs.push_back(std::make_pair(Freq, i)); std::stable_sort(FreqPairs.begin(), FreqPairs.end()); std::reverse(FreqPairs.begin(), FreqPairs.end()); errs() << "\tRecord Histogram:\n"; fprintf(stderr, "\t\t Count # Bits %% Abv Record Kind\n"); for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) { const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second]; fprintf(stderr, "\t\t%7d %9llu ", RecStats.NumInstances, (unsigned long long)RecStats.TotalBits); if (RecStats.NumAbbrev) fprintf(stderr, "%7.2f ", (double)RecStats.NumAbbrev/RecStats.NumInstances*100); else fprintf(stderr, " "); if (const char *CodeName = GetCodeName(FreqPairs[i].second, I->first, StreamFile)) fprintf(stderr, "%s\n", CodeName); else fprintf(stderr, "UnknownCode%d\n", FreqPairs[i].second); } errs() << "\n"; } } return 0; }
// Write one member out to the file. bool Archive::writeMember( const ArchiveMember& member, std::ofstream& ARFile, bool CreateSymbolTable, bool TruncateNames, bool ShouldCompress, std::string* ErrMsg ) { unsigned filepos = ARFile.tellp(); filepos -= 8; // Get the data and its size either from the // member's in-memory data or directly from the file. size_t fSize = member.getSize(); const char *data = (const char*)member.getData(); MemoryBuffer *mFile = 0; if (!data) { mFile = MemoryBuffer::getFile(member.getPath().c_str(), ErrMsg); if (mFile == 0) return true; data = mFile->getBufferStart(); fSize = mFile->getBufferSize(); } // Now that we have the data in memory, update the // symbol table if its a bitcode file. if (CreateSymbolTable && member.isBitcode()) { std::vector<std::string> symbols; std::string FullMemberName = archPath.str() + "(" + member.getPath().str() + ")"; Module* M = GetBitcodeSymbols((const unsigned char*)data,fSize, FullMemberName, Context, symbols, ErrMsg); // If the bitcode parsed successfully if ( M ) { for (std::vector<std::string>::iterator SI = symbols.begin(), SE = symbols.end(); SI != SE; ++SI) { std::pair<SymTabType::iterator,bool> Res = symTab.insert(std::make_pair(*SI,filepos)); if (Res.second) { symTabSize += SI->length() + numVbrBytes(SI->length()) + numVbrBytes(filepos); } } // We don't need this module any more. delete M; } else { delete mFile; if (ErrMsg) *ErrMsg = "Can't parse bitcode member: " + member.getPath().str() + ": " + *ErrMsg; return true; } } int hdrSize = fSize; // Compute the fields of the header ArchiveMemberHeader Hdr; bool writeLongName = fillHeader(member,Hdr,hdrSize,TruncateNames); // Write header to archive file ARFile.write((char*)&Hdr, sizeof(Hdr)); // Write the long filename if its long if (writeLongName) { ARFile.write(member.getPath().str().data(), member.getPath().str().length()); } // Write the (possibly compressed) member's content to the file. ARFile.write(data,fSize); // Make sure the member is an even length if ((ARFile.tellp() & 1) == 1) ARFile << ARFILE_PAD; // Close the mapped file if it was opened delete mFile; return false; }
int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); SourceMgr SM; // Read the expected strings from the check file. std::vector<CheckString> CheckStrings; if (ReadCheckFile(SM, CheckStrings)) return 2; // Open the file to check and add it to SourceMgr. OwningPtr<MemoryBuffer> File; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), File)) { errs() << "Could not open input file '" << InputFilename << "': " << ec.message() << '\n'; return 2; } MemoryBuffer *F = File.take(); if (F->getBufferSize() == 0) { errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; return 2; } // Remove duplicate spaces in the input file if requested. // Remove DOS style line endings. F = CanonicalizeInputFile(F, NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); /// VariableTable - This holds all the current filecheck variables. StringMap<StringRef> VariableTable; // Check that we have all of the expected strings, in order, in the input // file. StringRef Buffer = F->getBuffer(); const char *LastMatch = Buffer.data(); for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) { const CheckString &CheckStr = CheckStrings[StrNo]; StringRef SearchFrom = Buffer; // Find StrNo in the file. size_t MatchLen = 0; size_t MatchPos = CheckStr.Pat.Match(Buffer, MatchLen, VariableTable); Buffer = Buffer.substr(MatchPos); // If we didn't find a match, reject the input. if (MatchPos == StringRef::npos) { PrintCheckFailed(SM, CheckStr, SearchFrom, VariableTable); return 1; } StringRef SkippedRegion(LastMatch, Buffer.data()-LastMatch); // If this check is a "CHECK-NEXT", verify that the previous match was on // the previous line (i.e. that there is one newline between them). if (CheckStr.IsCheckNext) { // Count the number of newlines between the previous match and this one. assert(LastMatch != F->getBufferStart() && "CHECK-NEXT can't be the first check in a file"); unsigned NumNewLines = CountNumNewlinesBetween(SkippedRegion); if (NumNewLines == 0) { SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error, CheckPrefix+"-NEXT: is on the same line as previous match"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, "'next' match was here"); SM.PrintMessage(SMLoc::getFromPointer(LastMatch), SourceMgr::DK_Note, "previous match was here"); return 1; } if (NumNewLines != 1) { SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error, CheckPrefix+ "-NEXT: is not on the line after the previous match"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, "'next' match was here"); SM.PrintMessage(SMLoc::getFromPointer(LastMatch), SourceMgr::DK_Note, "previous match was here"); return 1; } } // If this match had "not strings", verify that they don't exist in the // skipped region. for (unsigned ChunkNo = 0, e = CheckStr.NotStrings.size(); ChunkNo != e; ++ChunkNo) { size_t MatchLen = 0; size_t Pos = CheckStr.NotStrings[ChunkNo].second.Match(SkippedRegion, MatchLen, VariableTable); if (Pos == StringRef::npos) continue; SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos), SourceMgr::DK_Error, CheckPrefix+"-NOT: string occurred!"); SM.PrintMessage(CheckStr.NotStrings[ChunkNo].first, SourceMgr::DK_Note, CheckPrefix+"-NOT: pattern specified here"); return 1; } // Otherwise, everything is good. Step over the matched text and remember // the position after the match as the end of the last match. Buffer = Buffer.substr(MatchLen); LastMatch = Buffer.data(); } return 0; }
void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { OS.write(Input.getBufferStart(), Input.getBufferSize()); }
/// LinkInFile - opens a bitcode file and links in all objects which /// provide symbols that are currently undefined. /// /// Inputs: /// File - The pathname of the bitcode file. /// /// Outputs: /// ErrorMessage - A C++ string detailing what error occurred, if any. /// /// Return Value: /// TRUE - An error occurred. /// FALSE - No errors. /// bool Linker::LinkInFile(const sys::Path &File, bool &is_native) { is_native = false; // Check for a file of name "-", which means "read standard input" if (File.str() == "-") { std::auto_ptr<Module> M; MemoryBuffer *Buffer = MemoryBuffer::getSTDIN(); if (!Buffer->getBufferSize()) { delete Buffer; Error = "standard input is empty"; } else { M.reset(ParseBitcodeFile(Buffer, Context, &Error)); delete Buffer; if (M.get()) if (!LinkInModule(M.get(), &Error)) return false; } return error("Cannot link stdin: " + Error); } // Make sure we can at least read the file if (!File.canRead()) return error("Cannot find linker input '" + File.str() + "'"); // If its an archive, try to link it in std::string Magic; File.getMagicNumber(Magic, 64); switch (sys::IdentifyFileType(Magic.c_str(), 64)) { default: llvm_unreachable("Bad file type identification"); case sys::Unknown_FileType: return warning("Ignoring file '" + File.str() + "' because does not contain bitcode."); case sys::Archive_FileType: // A user may specify an ar archive without -l, perhaps because it // is not installed as a library. Detect that and link the archive. if (LinkInArchive(File, is_native)) return true; break; case sys::Bitcode_FileType: { verbose("Linking bitcode file '" + File.str() + "'"); std::auto_ptr<Module> M(LoadObject(File)); if (M.get() == 0) return error("Cannot load file '" + File.str() + "': " + Error); if (LinkInModule(M.get(), &Error)) return error("Cannot link file '" + File.str() + "': " + Error); verbose("Linked in file '" + File.str() + "'"); break; } case sys::ELF_Relocatable_FileType: case sys::ELF_SharedObject_FileType: case sys::Mach_O_Object_FileType: case sys::Mach_O_FixedVirtualMemorySharedLib_FileType: case sys::Mach_O_DynamicallyLinkedSharedLib_FileType: case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType: case sys::COFF_FileType: is_native = true; break; } return false; }
/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename. static int AnalyzeBitcode() { // Read the input file. MemoryBuffer *Buffer; if (InputFilename == "-") Buffer = MemoryBuffer::getSTDIN(); else Buffer = MemoryBuffer::getFile(&InputFilename[0], InputFilename.size()); if (Buffer == 0) return Error("Error reading '" + InputFilename + "'."); if (Buffer->getBufferSize() & 3) return Error("Bitcode stream should be a multiple of 4 bytes in length"); unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart(); BitstreamReader Stream(BufPtr, BufPtr+Buffer->getBufferSize()); // Read the stream signature. char Signature[6]; Signature[0] = Stream.Read(8); Signature[1] = Stream.Read(8); Signature[2] = Stream.Read(4); Signature[3] = Stream.Read(4); Signature[4] = Stream.Read(4); Signature[5] = Stream.Read(4); // Autodetect the file contents, if it is one we know. CurStreamType = UnknownBitstream; if (Signature[0] == 'B' && Signature[1] == 'C' && Signature[2] == 0x0 && Signature[3] == 0xC && Signature[4] == 0xE && Signature[5] == 0xD) CurStreamType = LLVMIRBitstream; unsigned NumTopBlocks = 0; // Parse the top-level structure. We only allow blocks at the top-level. while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code != bitc::ENTER_SUBBLOCK) return Error("Invalid record at top-level"); if (ParseBlock(Stream, 0)) return true; ++NumTopBlocks; } if (Dump) std::cerr << "\n\n"; uint64_t BufferSizeBits = Buffer->getBufferSize()*8; // Print a summary of the read file. std::cerr << "Summary of " << InputFilename << ":\n"; std::cerr << " Total size: "; PrintSize(BufferSizeBits); std::cerr << "\n"; std::cerr << " Stream type: "; switch (CurStreamType) { default: assert(0 && "Unknown bitstream type"); case UnknownBitstream: std::cerr << "unknown\n"; break; case LLVMIRBitstream: std::cerr << "LLVM IR\n"; break; } std::cerr << " # Toplevel Blocks: " << NumTopBlocks << "\n"; std::cerr << "\n"; // Emit per-block stats. std::cerr << "Per-block Summary:\n"; for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(), E = BlockIDStats.end(); I != E; ++I) { std::cerr << " Block ID #" << I->first; if (const char *BlockName = GetBlockName(I->first)) std::cerr << " (" << BlockName << ")"; std::cerr << ":\n"; const PerBlockIDStats &Stats = I->second; std::cerr << " Num Instances: " << Stats.NumInstances << "\n"; std::cerr << " Total Size: "; PrintSize(Stats.NumBits); std::cerr << "\n"; std::cerr << " % of file: " << Stats.NumBits/(double)BufferSizeBits*100 << "\n"; if (Stats.NumInstances > 1) { std::cerr << " Average Size: "; PrintSize(Stats.NumBits/(double)Stats.NumInstances); std::cerr << "\n"; std::cerr << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/" << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n"; std::cerr << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/" << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n"; std::cerr << " Tot/Avg Records: " << Stats.NumRecords << "/" << Stats.NumRecords/(double)Stats.NumInstances << "\n"; } else { std::cerr << " Num SubBlocks: " << Stats.NumSubBlocks << "\n"; std::cerr << " Num Abbrevs: " << Stats.NumAbbrevs << "\n"; std::cerr << " Num Records: " << Stats.NumRecords << "\n"; } if (Stats.NumRecords) std::cerr << " % Abbrev Recs: " << (Stats.NumAbbreviatedRecords/ (double)Stats.NumRecords)*100 << "\n"; std::cerr << "\n"; // Print a histogram of the codes we see. if (!NoHistogram && !Stats.CodeFreq.empty()) { std::vector<std::pair<unsigned, unsigned> > FreqPairs; // <freq,code> for (unsigned i = 0, e = Stats.CodeFreq.size(); i != e; ++i) if (unsigned Freq = Stats.CodeFreq[i]) FreqPairs.push_back(std::make_pair(Freq, i)); std::stable_sort(FreqPairs.begin(), FreqPairs.end()); std::reverse(FreqPairs.begin(), FreqPairs.end()); std::cerr << "\tCode Histogram:\n"; for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) { std::cerr << "\t\t" << FreqPairs[i].first << "\t"; if (const char *CodeName = GetCodeName(FreqPairs[i].second, I->first)) std::cerr << CodeName << "\n"; else std::cerr << "UnknownCode" << FreqPairs[i].second << "\n"; } std::cerr << "\n"; } } return 0; }
int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, " BrainF compiler\n"); if (InputFilename == "") { errs() << "Error: You must specify the filename of the program to " "be compiled. Use --help to see the options.\n"; abort(); } // Read the input file. MemoryBuffer *Code = MemoryBuffer::getFileOrSTDIN(InputFilename); const uint8_t *CodeBegin = (const uint8_t*)(Code->getBufferStart()); // Create a new buffer to hold the preprocessed code. MemoryBuffer *ParsedCode = MemoryBuffer::getNewMemBuffer(sizeof(opcode_func_t) * (Code->getBufferSize()+1)); BytecodeArray = (opcode_func_t*)(ParsedCode->getBufferStart()); size_t BytecodeOffset = 0; // Create JumpMap, a special on-the-side data array used to implement // efficient jumps in the interpreter. JumpMap = new size_t[Code->getBufferSize()]; memset(JumpMap, 0, sizeof(size_t) * Code->getBufferSize()); std::vector<size_t> Stack; // Preprocess the input source code, performing three tasks: // 1 - Remove non-instruction characters // 2 - Replace character literals with opcode function pointers // 3 - Precompute the jump targets for [ and ] instructions in JumpMap for (size_t i = 0; i < Code->getBufferSize(); ++i) { uint8_t opcode = CodeBegin[i]; switch (opcode) { case '>': BytecodeArray[BytecodeOffset++] = &op_right; break; case '<': BytecodeArray[BytecodeOffset++] = &op_left; break; case '+': BytecodeArray[BytecodeOffset++] = &op_plus; break; case '-': BytecodeArray[BytecodeOffset++] = &op_minus; break; case '.': BytecodeArray[BytecodeOffset++] = &op_put; break; case ',': BytecodeArray[BytecodeOffset++] = &op_get; break; case '[': Stack.push_back(BytecodeOffset); BytecodeArray[BytecodeOffset++] = &op_if; break; case ']': // Special case: [-] --> 0 if (CodeBegin[i-1] == '-' && CodeBegin[i-2] == '[') { Stack.pop_back(); BytecodeOffset -= 2; BytecodeArray[BytecodeOffset++] = &op_set_zero; } else { JumpMap[Stack.back()] = BytecodeOffset; JumpMap[BytecodeOffset] = Stack.back(); Stack.pop_back(); BytecodeArray[BytecodeOffset++] = &op_back; } break; default: continue; } } // Fill in the suffix of the preprocessed source for op_exit. // Thus, if we reach the end of the source, the program will terminate. while (BytecodeOffset < Code->getBufferSize()+1) { BytecodeArray[BytecodeOffset++] = &op_end; } // Setup the array. uint8_t *BrainFArray = new uint8_t[32768]; memset(BrainFArray, 0, 32768); // Setup the trace recorder. Recorder = new BrainFTraceRecorder(); // Main interpreter loop. // Note the lack of a explicit loop: every opcode is a tail-recursive // function that calls its own successor by indexing into BytecodeArray. uint8_t* data = BrainFArray; BytecodeArray[0](0, data); //Clean up delete Recorder; delete Code; delete ParsedCode; delete[] BrainFArray; delete[] JumpMap; return 0; }