int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); if (OutputFilename == "-") { errs() << argv[0] << ": error: Can't update standard output\n"; return 1; } // Get the input data. OwningPtr<MemoryBuffer> In; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), In)) { errs() << argv[0] << ": error: Unable to get input '" << InputFilename << "': " << ec.message() << '\n'; return 1; } // Get the output data. OwningPtr<MemoryBuffer> Out; MemoryBuffer::getFile(OutputFilename.c_str(), Out); // If the output exists and the contents match, we are done. if (Out && In->getBufferSize() == Out->getBufferSize() && memcmp(In->getBufferStart(), Out->getBufferStart(), Out->getBufferSize()) == 0) { if (!Quiet) errs() << argv[0] << ": Not updating '" << OutputFilename << "', contents match input.\n"; return 0; } // Otherwise, overwrite the output. if (!Quiet) errs() << argv[0] << ": Updating '" << OutputFilename << "', contents changed.\n"; std::string ErrorStr; tool_output_file OutStream(OutputFilename.c_str(), ErrorStr, raw_fd_ostream::F_Binary); if (!ErrorStr.empty()) { errs() << argv[0] << ": Unable to write output '" << OutputFilename << "': " << ErrorStr << '\n'; return 1; } OutStream.os().write(In->getBufferStart(), In->getBufferSize()); // Declare success. OutStream.keep(); return 0; }
/// ExpandResponseFiles - Copy the contents of argv into newArgv, /// substituting the contents of the response files for the arguments /// of type @file. static void ExpandResponseFiles(unsigned argc, char** argv, std::vector<char*>& newArgv) { for (unsigned i = 1; i != argc; ++i) { char *arg = argv[i]; if (arg[0] == '@') { sys::PathWithStatus respFile(++arg); // Check that the response file is not empty (mmap'ing empty // files can be problematic). const sys::FileStatus *FileStat = respFile.getFileStatus(); if (FileStat && FileStat->getSize() != 0) { // If we could open the file, parse its contents, otherwise // pass the @file option verbatim. // TODO: we should also support recursive loading of response files, // since this is how gcc behaves. (From their man page: "The file may // itself contain additional @file options; any such options will be // processed recursively.") // Mmap the response file into memory. OwningPtr<MemoryBuffer> respFilePtr; if (!MemoryBuffer::getFile(respFile.c_str(), respFilePtr)) { ParseCStringVector(newArgv, respFilePtr->getBufferStart()); continue; } } } newArgv.push_back(strdup(arg)); } }
static void ExpandArgsFromBuf(const char *Arg, SmallVectorImpl<const char*> &ArgVector, std::set<std::string> &SavedStrings) { const char *FName = Arg + 1; OwningPtr<llvm::MemoryBuffer> MemBuf; if (llvm::MemoryBuffer::getFile(FName, MemBuf)) { ArgVector.push_back(SaveStringInSet(SavedStrings, Arg)); return; } const char *Buf = MemBuf->getBufferStart(); char InQuote = ' '; std::string CurArg; for (const char *P = Buf; ; ++P) { if (*P == '\0' || (isspace(*P) && InQuote == ' ')) { if (!CurArg.empty()) { if (CurArg[0] != '@') { ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg)); } else { ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings); } CurArg = ""; } if (*P == '\0') break; else continue; } if (isspace(*P)) { if (InQuote != ' ') CurArg.push_back(*P); continue; } if (*P == '"' || *P == '\'') { if (InQuote == *P) InQuote = ' '; else if (InQuote == ' ') InQuote = *P; else CurArg.push_back(*P); continue; } if (*P == '\\') { ++P; if (*P != '\0') CurArg.push_back(*P); continue; } CurArg.push_back(*P); } }
zlib::Status zlib::uncompress(StringRef InputBuffer, OwningPtr<MemoryBuffer> &UncompressedBuffer, size_t UncompressedSize) { OwningArrayPtr<char> TmpBuffer(new char[UncompressedSize]); Status Res = encodeZlibReturnValue( ::uncompress((Bytef *)TmpBuffer.get(), (uLongf *)&UncompressedSize, (const Bytef *)InputBuffer.data(), InputBuffer.size())); if (Res == StatusOK) { UncompressedBuffer.reset(MemoryBuffer::getMemBufferCopy( StringRef(TmpBuffer.get(), UncompressedSize))); // Tell MSan that memory initialized by zlib is valid. __msan_unpoison(UncompressedBuffer->getBufferStart(), UncompressedSize); } return Res; }
zlib::Status zlib::compress(StringRef InputBuffer, OwningPtr<MemoryBuffer> &CompressedBuffer, CompressionLevel Level) { unsigned long CompressedSize = ::compressBound(InputBuffer.size()); OwningArrayPtr<char> TmpBuffer(new char[CompressedSize]); int CLevel = encodeZlibCompressionLevel(Level); Status Res = encodeZlibReturnValue(::compress2( (Bytef *)TmpBuffer.get(), &CompressedSize, (const Bytef *)InputBuffer.data(), InputBuffer.size(), CLevel)); if (Res == StatusOK) { CompressedBuffer.reset(MemoryBuffer::getMemBufferCopy( StringRef(TmpBuffer.get(), CompressedSize))); // Tell MSan that memory initialized by zlib is valid. __msan_unpoison(CompressedBuffer->getBufferStart(), CompressedSize); } return Res; }
bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { // Open the module file. OwningPtr<llvm::MemoryBuffer> Buffer; Buffer.reset(FileMgr.getBufferForFile(File)); if (!Buffer) { return true; } // Initialize the input stream llvm::BitstreamReader InStreamFile; llvm::BitstreamCursor InStream; InStreamFile.init((const unsigned char *)Buffer->getBufferStart(), (const unsigned char *)Buffer->getBufferEnd()); InStream.init(InStreamFile); // Sniff for the signature. if (InStream.Read(8) != 'C' || InStream.Read(8) != 'P' || InStream.Read(8) != 'C' || InStream.Read(8) != 'H') { return true; } // Record this module file and assign it a unique ID (if it doesn't have // one already). unsigned ID = getModuleFileInfo(File).ID; // Search for the blocks and records we care about. enum { Other, ControlBlock, ASTBlock } State = Other; bool Done = false; while (!Done) { llvm::BitstreamEntry Entry = InStream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: Done = true; continue; case llvm::BitstreamEntry::Record: // In the 'other' state, just skip the record. We don't care. if (State == Other) { InStream.skipRecord(Entry.ID); continue; } // Handle potentially-interesting records below. break; case llvm::BitstreamEntry::SubBlock: if (Entry.ID == CONTROL_BLOCK_ID) { if (InStream.EnterSubBlock(CONTROL_BLOCK_ID)) return true; // Found the control block. State = ControlBlock; continue; } if (Entry.ID == AST_BLOCK_ID) { if (InStream.EnterSubBlock(AST_BLOCK_ID)) return true; // Found the AST block. State = ASTBlock; continue; } if (InStream.SkipBlock()) return true; continue; case llvm::BitstreamEntry::EndBlock: State = Other; continue; } // Read the given record. SmallVector<uint64_t, 64> Record; StringRef Blob; unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob); // Handle module dependencies. if (State == ControlBlock && Code == IMPORTS) { // Load each of the imported PCH files. unsigned Idx = 0, N = Record.size(); while (Idx < N) { // Read information about the AST file. // Skip the imported kind ++Idx; // Skip the import location ++Idx; // Retrieve the imported file name. unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, Record.begin() + Idx + Length); Idx += Length; // Find the imported module file. const FileEntry *DependsOnFile = FileMgr.getFile(ImportedFile); if (!DependsOnFile) return true; // Record the dependency. unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID; getModuleFileInfo(File).Dependencies.push_back(DependsOnID); } continue; } // Handle the identifier table if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) { typedef OnDiskChainedHashTable<InterestingASTIdentifierLookupTrait> InterestingIdentifierTable; llvm::OwningPtr<InterestingIdentifierTable> Table(InterestingIdentifierTable::Create( (const unsigned char *)Blob.data() + Record[0], (const unsigned char *)Blob.data())); for (InterestingIdentifierTable::data_iterator D = Table->data_begin(), DEnd = Table->data_end(); D != DEnd; ++D) { std::pair<StringRef, bool> Ident = *D; if (Ident.second) InterestingIdentifiers[Ident.first].push_back(ID); else (void)InterestingIdentifiers[Ident.first]; } } // FIXME: Handle the selector table. // We don't care about this record. } return false; }
/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename. static int AnalyzeBitcode() { // Read the input file. OwningPtr<MemoryBuffer> MemBuf; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), MemBuf)) return Error("Error reading '" + InputFilename + "': " + ec.message()); if (MemBuf->getBufferSize() & 3) return Error("Bitcode stream should be a multiple of 4 bytes in length"); const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart(); const 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, true)) 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"); unsigned BlockID = Stream.ReadSubBlockID(); if (ParseBlock(Stream, BlockID, 0)) return true; ++NumTopBlocks; } if (Dump) outs() << "\n\n"; uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT; // Print a summary of the read file. outs() << "Summary of " << InputFilename << ":\n"; outs() << " Total size: "; PrintSize(BufferSizeBits); outs() << "\n"; outs() << " Stream type: "; switch (CurStreamType) { case UnknownBitstream: outs() << "unknown\n"; break; case LLVMIRBitstream: outs() << "LLVM IR\n"; break; } outs() << " # Toplevel Blocks: " << NumTopBlocks << "\n"; outs() << "\n"; // Emit per-block stats. outs() << "Per-block Summary:\n"; for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(), E = BlockIDStats.end(); I != E; ++I) { outs() << " Block ID #" << I->first; if (const char *BlockName = GetBlockName(I->first, StreamFile)) outs() << " (" << BlockName << ")"; outs() << ":\n"; const PerBlockIDStats &Stats = I->second; outs() << " Num Instances: " << Stats.NumInstances << "\n"; outs() << " Total Size: "; PrintSize(Stats.NumBits); outs() << "\n"; double pct = (Stats.NumBits * 100.0) / BufferSizeBits; outs() << " Percent of file: " << format("%2.4f%%", pct) << "\n"; if (Stats.NumInstances > 1) { outs() << " Average Size: "; PrintSize(Stats.NumBits/(double)Stats.NumInstances); outs() << "\n"; outs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/" << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n"; outs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/" << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n"; outs() << " Tot/Avg Records: " << Stats.NumRecords << "/" << Stats.NumRecords/(double)Stats.NumInstances << "\n"; } else { outs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n"; outs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n"; outs() << " Num Records: " << Stats.NumRecords << "\n"; } if (Stats.NumRecords) { double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords; outs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n"; } outs() << "\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()); outs() << "\tRecord Histogram:\n"; outs() << "\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]; outs() << format("\t\t%7d %9lu", RecStats.NumInstances, (unsigned long)RecStats.TotalBits); if (RecStats.NumAbbrev) outs() << format("%7.2f ", (double)RecStats.NumAbbrev/RecStats.NumInstances*100); else outs() << " "; if (const char *CodeName = GetCodeName(FreqPairs[i].second, I->first, StreamFile)) outs() << CodeName << "\n"; else outs() << "UnknownCode" << FreqPairs[i].second << "\n"; } outs() << "\n"; } } return 0; }
CXDiagnosticSet DiagLoader::load(const char *file) { // Open the diagnostics file. std::string ErrStr; FileSystemOptions FO; FileManager FileMgr(FO); OwningPtr<llvm::MemoryBuffer> Buffer; Buffer.reset(FileMgr.getBufferForFile(file)); if (!Buffer) { reportBad(CXLoadDiag_CannotLoad, ErrStr); return 0; } llvm::BitstreamReader StreamFile; StreamFile.init((const unsigned char *)Buffer->getBufferStart(), (const unsigned char *)Buffer->getBufferEnd()); llvm::BitstreamCursor Stream; Stream.init(StreamFile); // Sniff for the signature. if (Stream.Read(8) != 'D' || Stream.Read(8) != 'I' || Stream.Read(8) != 'A' || Stream.Read(8) != 'G') { reportBad(CXLoadDiag_InvalidFile, "Bad header in diagnostics file"); return 0; } OwningPtr<CXLoadedDiagnosticSetImpl> Diags(new CXLoadedDiagnosticSetImpl()); while (true) { unsigned BlockID = 0; StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level", BlockID, true); switch (Res) { case Read_EndOfStream: return (CXDiagnosticSet) Diags.take(); case Read_Failure: return 0; case Read_Record: llvm_unreachable("Top-level does not have records"); case Read_BlockEnd: continue; case Read_BlockBegin: break; } switch (BlockID) { case serialized_diags::BLOCK_META: if (readMetaBlock(Stream)) return 0; break; case serialized_diags::BLOCK_DIAG: if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get())) return 0; break; default: if (!Stream.SkipBlock()) { reportInvalidFile("Malformed block at top-level of diagnostics file"); return 0; } break; } } }
// Write the entire archive to the file specified when the archive was created. // This writes to a temporary file first. Options are for creating a symbol // table, flattening the file names (no directories, 15 chars max) and // compressing each archive member. bool Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, std::string* ErrMsg) { // Make sure they haven't opened up the file, not loaded it, // but are now trying to write it which would wipe out the file. if (members.empty() && mapfile && mapfile->getBufferSize() > 8) { if (ErrMsg) *ErrMsg = "Can't write an archive not opened for writing"; return true; } // Create a temporary file to store the archive in sys::Path TmpArchive = archPath; if (TmpArchive.createTemporaryFileOnDisk(ErrMsg)) return true; // Make sure the temporary gets removed if we crash sys::RemoveFileOnSignal(TmpArchive); // Create archive file for output. std::ios::openmode io_mode = std::ios::out | std::ios::trunc | std::ios::binary; std::ofstream ArchiveFile(TmpArchive.c_str(), io_mode); // Check for errors opening or creating archive file. if (!ArchiveFile.is_open() || ArchiveFile.bad()) { TmpArchive.eraseFromDisk(); if (ErrMsg) *ErrMsg = "Error opening archive file: " + archPath.str(); return true; } // If we're creating a symbol table, reset it now if (CreateSymbolTable) { symTabSize = 0; symTab.clear(); } // Write magic string to archive. ArchiveFile << ARFILE_MAGIC; // Loop over all member files, and write them out. Note that this also // builds the symbol table, symTab. for (MembersList::iterator I = begin(), E = end(); I != E; ++I) { if (writeMember(*I, ArchiveFile, CreateSymbolTable, TruncateNames, ErrMsg)) { TmpArchive.eraseFromDisk(); ArchiveFile.close(); return true; } } // Close archive file. ArchiveFile.close(); // Write the symbol table if (CreateSymbolTable) { // At this point we have written a file that is a legal archive but it // doesn't have a symbol table in it. To aid in faster reading and to // ensure compatibility with other archivers we need to put the symbol // table first in the file. Unfortunately, this means mapping the file // we just wrote back in and copying it to the destination file. sys::Path FinalFilePath = archPath; // Map in the archive we just wrote. { OwningPtr<MemoryBuffer> arch; if (error_code ec = MemoryBuffer::getFile(TmpArchive.c_str(), arch)) { if (ErrMsg) *ErrMsg = ec.message(); return true; } const char* base = arch->getBufferStart(); // Open another temporary file in order to avoid invalidating the // mmapped data if (FinalFilePath.createTemporaryFileOnDisk(ErrMsg)) return true; sys::RemoveFileOnSignal(FinalFilePath); std::ofstream FinalFile(FinalFilePath.c_str(), io_mode); if (!FinalFile.is_open() || FinalFile.bad()) { TmpArchive.eraseFromDisk(); if (ErrMsg) *ErrMsg = "Error opening archive file: " + FinalFilePath.str(); return true; } // Write the file magic number FinalFile << ARFILE_MAGIC; // If there is a foreign symbol table, put it into the file now. Most // ar(1) implementations require the symbol table to be first but llvm-ar // can deal with it being after a foreign symbol table. This ensures // compatibility with other ar(1) implementations as well as allowing the // archive to store both native .o and LLVM .bc files, both indexed. if (foreignST) { if (writeMember(*foreignST, FinalFile, false, false, ErrMsg)) { FinalFile.close(); TmpArchive.eraseFromDisk(); return true; } } // Put out the LLVM symbol table now. writeSymbolTable(FinalFile); // Copy the temporary file contents being sure to skip the file's magic // number. FinalFile.write(base + sizeof(ARFILE_MAGIC)-1, arch->getBufferSize()-sizeof(ARFILE_MAGIC)+1); // Close up shop FinalFile.close(); } // free arch. // Move the final file over top of TmpArchive if (FinalFilePath.renamePathOnDisk(TmpArchive, ErrMsg)) return true; } // Before we replace the actual archive, we need to forget all the // members, since they point to data in that old archive. We need to do // this because we cannot replace an open file on Windows. cleanUpMemory(); if (TmpArchive.renamePathOnDisk(archPath, ErrMsg)) return true; // Set correct read and write permissions after temporary file is moved // to final destination path. if (archPath.makeReadableOnDisk(ErrMsg)) return true; if (archPath.makeWriteableOnDisk(ErrMsg)) return true; return false; }
void BenchmarkIRParsing() { outs() << "Benchmarking IR parsing...\n"; OwningPtr<MemoryBuffer> FileBuf; error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), FileBuf); if (ec) { report_fatal_error("Could not open input file: " + ec.message()); } size_t BufSize = FileBuf->getBufferSize(); const uint8_t *BufPtr = reinterpret_cast<const uint8_t*>(FileBuf->getBufferStart()); const uint8_t *EndBufPtr = reinterpret_cast<const uint8_t*>(FileBuf->getBufferEnd()); // Since MemoryBuffer may use mmap, make sure to first touch all bytes in the // input buffer to make sure it's actually in memory. volatile uint8_t *Slot = new uint8_t; for (const uint8_t *S = BufPtr; S != EndBufPtr; ++S) { *Slot = *S; } delete Slot; outs() << "Read bitcode into buffer. Size=" << BufSize << "\n"; // Trivial copy into a new buffer with a cascading XOR that simulates // "touching" every byte in the buffer in a simple way. { TimingOperationBlock T("Simple XOR copy", BufSize); volatile uint8_t *OutBuf = new uint8_t[BufSize]; OutBuf[0] = 1; size_t N = 1; // Run over the input buffer from start to end-1; run over the output buffer // from 1 to end. for (const uint8_t *S = BufPtr; S != EndBufPtr - 1; ++S, ++N) { OutBuf[N] = OutBuf[N - 1] ^ *S; } delete[] OutBuf; } // Bitcode parsing without any additional operations. This is the minimum // required to actually extract information from PNaCl bitcode. { TimingOperationBlock T("Bitcode block parsing", BufSize); NaClBitcodeHeader Header; if (Header.Read(BufPtr, EndBufPtr)) { report_fatal_error("Invalid PNaCl bitcode header"); } if (!Header.IsSupported()) { errs() << "Warning: " << Header.Unsupported() << "\n"; } if (!Header.IsReadable()) { report_fatal_error("Bitcode file is not readable"); } NaClBitstreamReader StreamFile(BufPtr, EndBufPtr); NaClBitstreamCursor Stream(StreamFile); StreamFile.CollectBlockInfoNames(); DummyBitcodeParser Parser(Stream); while (!Stream.AtEndOfStream()) { if (Parser.Parse()) { report_fatal_error("Parsing failed"); } } } // Actual LLVM IR parsing and formation from the bitcode { TimingOperationBlock T("LLVM IR parsing", BufSize); SMDiagnostic Err; Module *M = NaClParseIRFile(InputFilename, PNaClFormat, Err, getGlobalContext()); if (!M) { report_fatal_error("Unable to NaClParseIRFile"); } } }
/// claim_file_hook - called by gold to see whether this file is one that /// our plugin can handle. We'll try to open it and register all the symbols /// with add_symbol if possible. static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { lto_module_t M; const void *view; OwningPtr<MemoryBuffer> buffer; if (get_view) { if (get_view(file->handle, &view) != LDPS_OK) { (*message)(LDPL_ERROR, "Failed to get a view of %s", file->name); return LDPS_ERR; } } else { int64_t offset = 0; // Gold has found what might be IR part-way inside of a file, such as // an .a archive. if (file->offset) { offset = file->offset; } if (error_code ec = MemoryBuffer::getOpenFileSlice( file->fd, file->name, buffer, file->filesize, offset)) { (*message)(LDPL_ERROR, ec.message().c_str()); return LDPS_ERR; } view = buffer->getBufferStart(); } if (!lto_module_is_object_file_in_memory(view, file->filesize)) return LDPS_OK; M = lto_module_create_from_memory(view, file->filesize); if (!M) { if (const char* msg = lto_get_error_message()) { (*message)(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module: %s", msg); return LDPS_ERR; } return LDPS_OK; } *claimed = 1; Modules.resize(Modules.size() + 1); claimed_file &cf = Modules.back(); if (!options::triple.empty()) lto_module_set_target_triple(M, options::triple.c_str()); cf.handle = file->handle; unsigned sym_count = lto_module_get_num_symbols(M); cf.syms.reserve(sym_count); for (unsigned i = 0; i != sym_count; ++i) { lto_symbol_attributes attrs = lto_module_get_symbol_attribute(M, i); if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) continue; cf.syms.push_back(ld_plugin_symbol()); ld_plugin_symbol &sym = cf.syms.back(); sym.name = const_cast<char *>(lto_module_get_symbol_name(M, i)); sym.name = strdup(sym.name); sym.version = NULL; int scope = attrs & LTO_SYMBOL_SCOPE_MASK; bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; if (!CanBeHidden) CannotBeHidden.insert(sym.name); switch (scope) { case LTO_SYMBOL_SCOPE_HIDDEN: sym.visibility = LDPV_HIDDEN; break; case LTO_SYMBOL_SCOPE_PROTECTED: sym.visibility = LDPV_PROTECTED; break; case 0: // extern case LTO_SYMBOL_SCOPE_DEFAULT: case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: sym.visibility = LDPV_DEFAULT; break; default: (*message)(LDPL_ERROR, "Unknown scope attribute: %d", scope); return LDPS_ERR; } int definition = attrs & LTO_SYMBOL_DEFINITION_MASK; sym.comdat_key = NULL; switch (definition) { case LTO_SYMBOL_DEFINITION_REGULAR: sym.def = LDPK_DEF; break; case LTO_SYMBOL_DEFINITION_UNDEFINED: sym.def = LDPK_UNDEF; break; case LTO_SYMBOL_DEFINITION_TENTATIVE: sym.def = LDPK_COMMON; break; case LTO_SYMBOL_DEFINITION_WEAK: sym.comdat_key = sym.name; sym.def = LDPK_WEAKDEF; break; case LTO_SYMBOL_DEFINITION_WEAKUNDEF: sym.def = LDPK_WEAKUNDEF; break; default: (*message)(LDPL_ERROR, "Unknown definition attribute: %d", definition); return LDPS_ERR; } sym.size = 0; sym.resolution = LDPR_UNKNOWN; } cf.syms.reserve(cf.syms.size()); if (!cf.syms.empty()) { if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) { (*message)(LDPL_ERROR, "Unable to add symbols!"); return LDPS_ERR; } } if (code_gen) { if (lto_codegen_add_module(code_gen, M)) { (*message)(LDPL_ERROR, "Error linking module: %s", lto_get_error_message()); return LDPS_ERR; } } lto_module_dispose(M); return LDPS_OK; }
bool JSONImporter::runOnScop(Scop &scop) { S = &scop; Region &R = S->getRegion(); Dependences *D = &getAnalysis<Dependences>(); std::string FileName = ImportDir + "/" + getFileName(S); std::string FunctionName = R.getEntry()->getParent()->getName(); errs() << "Reading JScop '" << R.getNameStr() << "' in function '" << FunctionName << "' from '" << FileName << "'.\n"; OwningPtr<MemoryBuffer> result; error_code ec = MemoryBuffer::getFile(FileName, result); if (ec) { errs() << "File could not be read: " << ec.message() << "\n"; return false; } Json::Reader reader; Json::Value jscop; bool parsingSuccessful = reader.parse(result->getBufferStart(), jscop); if (!parsingSuccessful) { errs() << "JSCoP file could not be parsed\n"; return false; } isl_set *OldContext = S->getContext(); isl_set *NewContext = isl_set_read_from_str(S->getIslCtx(), jscop["context"].asCString()); for (unsigned i = 0; i < isl_set_dim(OldContext, isl_dim_param); i++) { isl_id *id = isl_set_get_dim_id(OldContext, isl_dim_param, i); NewContext = isl_set_set_dim_id(NewContext, isl_dim_param, i, id); } isl_set_free(OldContext); S->setContext(NewContext); StatementToIslMapTy &NewScattering = *(new StatementToIslMapTy()); int index = 0; for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) { Json::Value schedule = jscop["statements"][index]["schedule"]; isl_map *m = isl_map_read_from_str(S->getIslCtx(), schedule.asCString()); isl_space *Space = (*SI)->getDomainSpace(); // Copy the old tuple id. This is necessary to retain the user pointer, // that stores the reference to the ScopStmt this scattering belongs to. m = isl_map_set_tuple_id(m, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set)); isl_space_free(Space); NewScattering[*SI] = m; index++; } if (!D->isValidScattering(&NewScattering)) { errs() << "JScop file contains a scattering that changes the " << "dependences. Use -disable-polly-legality to continue anyways\n"; return false; } for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) { ScopStmt *Stmt = *SI; if (NewScattering.find(Stmt) != NewScattering.end()) Stmt->setScattering(NewScattering[Stmt]); } int statementIdx = 0; for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) { ScopStmt *Stmt = *SI; int memoryAccessIdx = 0; for (ScopStmt::memacc_iterator MI = Stmt->memacc_begin(), ME = Stmt->memacc_end(); MI != ME; ++MI) { Json::Value accesses = jscop["statements"][statementIdx]["accesses"][ memoryAccessIdx]["relation"]; isl_map *newAccessMap = isl_map_read_from_str(S->getIslCtx(), accesses.asCString()); isl_map *currentAccessMap = (*MI)->getAccessRelation(); if (isl_map_dim(newAccessMap, isl_dim_param) != isl_map_dim(currentAccessMap, isl_dim_param)) { errs() << "JScop file changes the number of parameter dimensions\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } // We need to copy the isl_ids for the parameter dimensions to the new // map. Without doing this the current map would have different // ids then the new one, even though both are named identically. for (unsigned i = 0; i < isl_map_dim(currentAccessMap, isl_dim_param); i++) { isl_id *id = isl_map_get_dim_id(currentAccessMap, isl_dim_param, i); newAccessMap = isl_map_set_dim_id(newAccessMap, isl_dim_param, i, id); } // Copy the old tuple id. This is necessary to retain the user pointer, // that stores the reference to the ScopStmt this access belongs to. isl_id *Id = isl_map_get_tuple_id(currentAccessMap, isl_dim_in); newAccessMap = isl_map_set_tuple_id(newAccessMap, isl_dim_in, Id); if (!isl_map_has_equal_space(currentAccessMap, newAccessMap)) { errs() << "JScop file contains access function with incompatible " << "dimensions\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } if (isl_map_dim(newAccessMap, isl_dim_out) != 1) { errs() << "New access map in JScop file should be single dimensional\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } if (!isl_map_is_equal(newAccessMap, currentAccessMap)) { // Statistics. ++NewAccessMapFound; newAccessStrings.push_back(accesses.asCString()); (*MI)->setNewAccessRelation(newAccessMap); } else { isl_map_free(newAccessMap); } isl_map_free(currentAccessMap); memoryAccessIdx++; } statementIdx++; } return false; }