예제 #1
0
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;
}
예제 #2
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));
  }
}
예제 #3
0
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);
  }
}
예제 #4
0
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;
}
예제 #5
0
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;
}
예제 #6
0
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;
}
예제 #7
0
/// 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;
}
예제 #8
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;
    }
  }
}
예제 #9
0
// 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");
    }
  }
}
예제 #11
0
/// 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;
}
예제 #12
0
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;
}