<commit_before>//===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to the lld driver. This is a thin wrapper which
// dispatches to the given platform specific driver.
//
// If there is -flavor option, it is dispatched according to the arguments.
// If the flavor parameter is not present, then it is dispatched according
// to argv[0].
//
//===----------------------------------------------------------------------===//

#include "lld/Driver/Driver.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"

using namespace lld;
using namespace llvm;
using namespace llvm::sys;

enum Flavor {
  Invalid,
  Gnu,     // -flavor gnu
  WinLink, // -flavor link
  Darwin,  // -flavor darwin
};

LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
  errs() << S << "\n";
  exit(1);
}

static Flavor getFlavor(StringRef S) {
  return StringSwitch<Flavor>(S)
      .Case("ld", Gnu)
      .Case("ld.lld", Gnu)
      .Case("gnu", Gnu)
      .Case("link", WinLink)
      .Case("darwin", Darwin)
      .Default(Invalid);
}

static Flavor parseProgname(StringRef Progname) {
#if __APPLE__
  // Use Darwin driver for "ld" on Darwin.
  if (Progname == "ld")
    return Darwin;
#endif

#if LLVM_ON_UNIX
  // Use GNU driver for "ld" on other Unix-like system.
  if (Progname == "ld")
    return Gnu;
#endif

  // Progname may be something like "lld-gnu". Parse it.
  SmallVector<StringRef, 3> V;
  Progname.split(V, "-");
  for (StringRef S : V)
    if (Flavor F = getFlavor(S))
      return F;
  return Invalid;
}

static Flavor parseFlavor(std::vector<const char *> &V) {
  // Parse -flavor option.
  if (V.size() > 1 && V[1] == StringRef("-flavor")) {
    if (V.size() <= 2)
      die("missing arg value for '-flavor'");
    Flavor F = getFlavor(V[2]);
    if (F == Invalid)
      die("Unknown flavor: " + StringRef(V[2]));
    V.erase(V.begin() + 1, V.begin() + 3);
    return F;
  }

  // Deduct the flavor from argv[0].
  StringRef Arg0 = path::filename(V[0]);
  if (Arg0.endswith_lower(".exe"))
    Arg0 = Arg0.drop_back(4);
  return parseProgname(Arg0);
}

/// Universal linker main(). This linker emulates the gnu, darwin, or
/// windows linker based on the argv[0] or -flavor option.
int main(int Argc, const char **Argv) {
  // Standard set up, so program fails gracefully.
  sys::PrintStackTraceOnErrorSignal();
  PrettyStackTraceProgram StackPrinter(Argc, Argv);
  llvm_shutdown_obj Shutdown;

  std::vector<const char *> Args(Argv, Argv + Argc);
  switch (parseFlavor(Args)) {
  case Gnu:
    return !elf::link(Args);
  case WinLink:
    return !coff::link(Args);
  case Darwin:
    return !mach_o::link(Args);
  default:
    die("-flavor option is missing. Available flavors are "
        "gnu, darwin or link.");
  }
}
<commit_msg>Remove unused include. NFC.<commit_after>//===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to the lld driver. This is a thin wrapper which
// dispatches to the given platform specific driver.
//
// If there is -flavor option, it is dispatched according to the arguments.
// If the flavor parameter is not present, then it is dispatched according
// to argv[0].
//
//===----------------------------------------------------------------------===//

#include "lld/Driver/Driver.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"

using namespace lld;
using namespace llvm;
using namespace llvm::sys;

enum Flavor {
  Invalid,
  Gnu,     // -flavor gnu
  WinLink, // -flavor link
  Darwin,  // -flavor darwin
};

LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
  errs() << S << "\n";
  exit(1);
}

static Flavor getFlavor(StringRef S) {
  return StringSwitch<Flavor>(S)
      .Case("ld", Gnu)
      .Case("ld.lld", Gnu)
      .Case("gnu", Gnu)
      .Case("link", WinLink)
      .Case("darwin", Darwin)
      .Default(Invalid);
}

static Flavor parseProgname(StringRef Progname) {
#if __APPLE__
  // Use Darwin driver for "ld" on Darwin.
  if (Progname == "ld")
    return Darwin;
#endif

#if LLVM_ON_UNIX
  // Use GNU driver for "ld" on other Unix-like system.
  if (Progname == "ld")
    return Gnu;
#endif

  // Progname may be something like "lld-gnu". Parse it.
  SmallVector<StringRef, 3> V;
  Progname.split(V, "-");
  for (StringRef S : V)
    if (Flavor F = getFlavor(S))
      return F;
  return Invalid;
}

static Flavor parseFlavor(std::vector<const char *> &V) {
  // Parse -flavor option.
  if (V.size() > 1 && V[1] == StringRef("-flavor")) {
    if (V.size() <= 2)
      die("missing arg value for '-flavor'");
    Flavor F = getFlavor(V[2]);
    if (F == Invalid)
      die("Unknown flavor: " + StringRef(V[2]));
    V.erase(V.begin() + 1, V.begin() + 3);
    return F;
  }

  // Deduct the flavor from argv[0].
  StringRef Arg0 = path::filename(V[0]);
  if (Arg0.endswith_lower(".exe"))
    Arg0 = Arg0.drop_back(4);
  return parseProgname(Arg0);
}

/// Universal linker main(). This linker emulates the gnu, darwin, or
/// windows linker based on the argv[0] or -flavor option.
int main(int Argc, const char **Argv) {
  // Standard set up, so program fails gracefully.
  sys::PrintStackTraceOnErrorSignal();
  PrettyStackTraceProgram StackPrinter(Argc, Argv);
  llvm_shutdown_obj Shutdown;

  std::vector<const char *> Args(Argv, Argv + Argc);
  switch (parseFlavor(Args)) {
  case Gnu:
    return !elf::link(Args);
  case WinLink:
    return !coff::link(Args);
  case Darwin:
    return !mach_o::link(Args);
  default:
    die("-flavor option is missing. Available flavors are "
        "gnu, darwin or link.");
  }
}
<|endoftext|>


<commit_before>#include "Cercle.h"

Cercle::Cercle()
{
    //ctor
}

Cercle::Cercle(double cX, double cY, double r)
{
    this->c.setX(cX);
    this->c.setY(cY);
    this->r = r;
}

double Cercle::getCx()
{
    return this->c.getX();
}

double Cercle::getCy()
{
    return this->c.getY();
}

double Cercle::getRadius()
{
    return this->r;
}

Point& Cercle::getCenter()
{
    return this->c;
}

void Cercle::setRadius(double r)
{
    this->r = r;
}

void Cercle::setCenter(Point c)
{
    this->c = c;
}

Cercle::~Cercle()
{
    //dtor
}
<commit_msg>Delete Cercle.cpp<commit_after><|endoftext|>


<commit_before>/** Utility for augmenting MARC records with links to a local full-text database.

  10535 http://swbplus.bsz-bw.de                  Done!
   4774 http://digitool.hbz-nrw.de:1801           Done!
   2977 http://www.gbv.de                         PDF's
   1070 http://bvbr.bib-bvb.de:8991               Done!
    975 http://deposit.d-nb.de                    HTML
    772 http://d-nb.info                          PDF's (Images => Need to OCR this?)
    520 http://www.ulb.tu-darmstadt.de            (Frau Gwinner arbeitet daran?)
    236 http://media.obvsg.at                     HTML
    167 http://www.loc.gov                        Done!
    133 http://deposit.ddb.de
    127 http://www.bibliothek.uni-regensburg.de
     57 http://nbn-resolving.de
     43 http://www.verlagdrkovac.de
     35 http://search.ebscohost.com
     25 http://idb.ub.uni-tuebingen.de
     22 http://link.springer.com
     18 http://heinonline.org
     15 http://www.waxmann.com
     13 https://www.destatis.de
     10 http://www.tandfonline.com
     10 http://dx.doi.org
      9 http://tocs.ub.uni-mainz.de
      8 http://www.onlinelibrary.wiley.com
      8 http://bvbm1.bib-bvb.de
      6 http://www.wvberlin.de
      6 http://www.jstor.org
      6 http://www.emeraldinsight.com
      6 http://www.destatis.de
      5 http://www.univerlag.uni-goettingen.de
      5 http://www.sciencedirect.com
      5 http://www.netread.com
      5 http://www.gesis.org
      5 http://content.ub.hu-berlin.de

*/
#include <iostream>
#include <map>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <kchashdb.h>
#include <libgen.h>
#include <strings.h>
#include "Downloader.h"
#include "ExecUtil.h"
#include "FileUtil.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "PdfUtil.h"
#include "RegexMatcher.h"
#include "SharedBuffer.h"
#include "SmartDownloader.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "TextUtil.h"
#include "util.h"

void Usage() {
    std::cerr << "Usage: " << progname << "[--max-record-count count] marc_input marc_output full_text_db\n";
    std::exit(EXIT_FAILURE);
}

// Here "word" simply means a sequence of characters not containing a space.
std::string GetLastWordAfterSpace(const std::string &text) {
    const size_t last_space_pos(text.rfind(' '));
    if (last_space_pos == std::string::npos)
	return "";

    const std::string last_word(text.substr(last_space_pos + 1));
    return last_word;
}

void ThreadSafeComposeAndWriteRecord(FILE * const output, const std::vector<DirectoryEntry> &dir_entries,
				     const std::vector<std::string> &field_data, Leader * const leader)
{
    static std::mutex marc_writer_mutex;
    std::unique_lock<std::mutex> mutex_locker(marc_writer_mutex);
    MarcUtil::ComposeAndWriteRecord(output, dir_entries, field_data, leader);
}

/** Writes "media_type" and "document" to "db" and returns the unique key that was generated for the write. */
std::string ThreadSafeWriteDocumentWithMediaType(const std::string &media_type, const std::string &document,
						 kyotocabinet::HashDB * const db)
{
    static std::mutex simple_db_writer_mutex;
    std::unique_lock<std::mutex> mutex_locker(simple_db_writer_mutex);
    static unsigned key;
    ++key;
    const std::string key_as_string(std::to_string(key));
    db->add(key_as_string, "Content-type: " + media_type + "\r\n\r\n" + document);
    return key_as_string;
}

static std::map<std::string, std::string> marc_to_tesseract_language_codes_map {
    { "fre", "fra" },
    { "eng", "eng" },
    { "ger", "deu" },
    { "ita", "ita" },
    { "dut", "nld" },
    { "swe", "swe" },
    { "dan", "dan" },
    { "nor", "nor" },
    { "rus", "rus" },
    { "fin", "fin" },
    { "por", "por" },
    { "pol", "pol" },
    { "slv", "slv" },
    { "hun", "hun" },
    { "cze", "ces" },
    { "bul", "bul" },
};

std::string GetTesseractLanguageCode(const std::vector<DirectoryEntry> &dir_entries,
                                     const std::vector<std::string> &field_data)
{
    const auto map_iter(marc_to_tesseract_language_codes_map.find(
        MarcUtil::GetLanguageCode(dir_entries, field_data)));
    return (map_iter == marc_to_tesseract_language_codes_map.cend()) ? "" : map_iter->second;
}

// Checks subfields "3" and "z" to see if they start w/ "Rezension".
bool IsProbablyAReview(const Subfields &subfields) {
    const auto _3_begin_end(subfields.getIterators('3'));
    if (_3_begin_end.first != _3_begin_end.second) {
	if (StringUtil::StartsWith(_3_begin_end.first->second, "Rezension"))
	    return true;
    } else {
	const auto z_begin_end(subfields.getIterators('z'));
	if (z_begin_end.first != z_begin_end.second
	    and StringUtil::StartsWith(z_begin_end.first->second, "Rezension"))
	    return true;
    }

    return false;
}

bool GetDocumentAndMediaType(const std::string &url, std::string * const document, std::string * const media_type) {
    if (not SmartDownload(url, document)) {
	std::cerr << "Failed to download the document for " << url << "\n";
	return false;
    }

    *media_type = MediaTypeUtil::GetMediaType(*document, /* auto_simplify = */ false);
    if (media_type->empty())
	return false;

    return true;
}

bool GetTextFromImagePDF(const std::string &document, const std::string &media_type,
			 const std::vector<DirectoryEntry> &dir_entries, const std::vector<std::string> &field_data,
			 const std::string &pdf_images_script, std::string * const extracted_text)
{
    if (not StringUtil::StartsWith(media_type, "application/pdf") or not PdfDocContainsNoText(document))
	return false;

    extracted_text->clear();
    std::cerr << "Found a PDF w/ no text.\n";

    const AutoTempFile auto_temp_file;
    const std::string &input_filename(auto_temp_file.getFilePath());
    if (not WriteString(input_filename, document))
	Error("failed to write the PDF to a temp file!");

    const AutoTempFile auto_temp_file2;
    const std::string &output_filename(auto_temp_file2.getFilePath());
    const std::string language_code(GetTesseractLanguageCode(dir_entries, field_data));
    const unsigned TIMEOUT(20); // in seconds
    if (Exec(pdf_images_script, { input_filename, output_filename, language_code }, "",
	     TIMEOUT) != 0)
    {
	Warning("failed to execute conversion script \"" + pdf_images_script + "\" w/in "
		+ std::to_string(TIMEOUT) + " seconds !");
	return true;
    }

    std::string plain_text;
    if (not ReadFile(output_filename, extracted_text))
	Error("failed to read OCR output!");

    if (extracted_text->empty())
	std::cerr << "Warning: OCR output is empty!\n";

    std::cerr << "Whoohoo, got OCR'ed text.\n";

    return true;
}

void ProcessRecords(const unsigned long max_record_count, const std::string &pdf_images_script,
		    FILE * const input, FILE * const output, kyotocabinet::HashDB * const db)
{
    Leader *raw_leader;
    std::vector<DirectoryEntry> dir_entries;
    std::vector<std::string> field_data;
    std::string err_msg;
    unsigned long total_record_count(0), records_with_relevant_links_count(0), relevant_links_count(0),
	          failed_count(0);

    while (MarcUtil::ReadNextRecord(input, &raw_leader, &dir_entries, &field_data, &err_msg)) {
	if (total_record_count == max_record_count)
	    break;
	++total_record_count;

	std::cout << "Processing record #" << total_record_count << ".\n";
	std::unique_ptr<Leader> leader(raw_leader);

	ssize_t _856_index(MarcUtil::GetFieldIndex(dir_entries, "856"));
	if (_856_index == -1) {
	    ThreadSafeComposeAndWriteRecord(output, dir_entries, field_data, leader.get());
	    continue;
	}

	bool found_at_least_one(false);
	for (/* Empty! */;
	     static_cast<size_t>(_856_index) < dir_entries.size() and dir_entries[_856_index].getTag() == "856";
	     ++_856_index)
	{
	    Subfields subfields(field_data[_856_index]);
	    const auto u_begin_end(subfields.getIterators('u'));
	    if (u_begin_end.first == u_begin_end.second) // No subfield 'u'.
		continue;

	    if (IsProbablyAReview(subfields))
		continue;

	    // If we get here, we have an 856u subfield that is not a review.
	    ++relevant_links_count;
	    if (not found_at_least_one) {
		++records_with_relevant_links_count;
		found_at_least_one = true;
	    }

	    std::string document, media_type;
	    if (not GetDocumentAndMediaType(u_begin_end.first->second, &document, &media_type)) {
		++failed_count;
		continue;
	    }

	    std::string extracted_text, key;
	    if (GetTextFromImagePDF(document, media_type, dir_entries, field_data, pdf_images_script,
				    &extracted_text))
		key = ThreadSafeWriteDocumentWithMediaType("text/plain", extracted_text, db);
	    else
		key = ThreadSafeWriteDocumentWithMediaType(media_type, document, db);

	    subfields.addSubfield('e', "http://localhost/cgi-bin/full_text_lookup?id=" + key);
	    const std::string new_856_field(subfields.toString());
	    MarcUtil::UpdateField(_856_index, new_856_field, leader.get(), &dir_entries, &field_data);
	}

	ThreadSafeComposeAndWriteRecord(output, dir_entries, field_data, leader.get());
    }

    if (not err_msg.empty())
	Error(err_msg);
    std::cerr << "Read " << total_record_count << " records.\n";
    std::cerr << "Found " << records_with_relevant_links_count << " records w/ relevant 856u fields.\n";
    std::cerr << failed_count << " failed downloads, media type determinations or text extractions.\n";
    std::cerr << (100.0 * (relevant_links_count - failed_count) / double(relevant_links_count)) << "% successes.\n";

    std::fclose(input);
}

const std::string BASH_HELPER("pdf_images_to_text.sh");

std::string GetPathToPdfImagesScript(const char * const argv0) {
    char path[std::strlen(argv0) + 1];
    std::strcpy(path, argv0);
    const std::string pdf_images_script_path(std::string(::dirname(path)) + "/" + BASH_HELPER);
    if (::access(pdf_images_script_path.c_str(), X_OK) != 0)
	Error("can't execute \"" + pdf_images_script_path + "\"!");
    return pdf_images_script_path;
}

int main(int argc, char *argv[]) {
    progname = argv[0];

    if (argc != 4 and argc != 6)
	Usage();

    unsigned long max_record_count(ULONG_MAX);
    if (argc == 6) {
	if (std::strcmp(argv[1], "--max-record-count") != 0)
	    Usage();
	if (not StringUtil::ToUnsignedLong(argv[2], &max_record_count))
	    Error(std::string(argv[2]) + " is not a valid max. record count!");
	argc -= 2, argv += 2;
    }

    const std::string marc_input_filename(argv[1]);
    FILE *marc_input = std::fopen(marc_input_filename.c_str(), "rb");
    if (marc_input == NULL)
	Error("can't open \"" + marc_input_filename + "\" for reading!");

    const std::string marc_output_filename(argv[2]);
    FILE *marc_output = std::fopen(marc_output_filename.c_str(), "wb");
    if (marc_output == NULL)
	Error("can't open \"" + marc_output_filename + "\" for writing!");

    kyotocabinet::HashDB db;
    if (not db.open(argv[3],
		    kyotocabinet::HashDB::OWRITER | kyotocabinet::HashDB::OCREATE
		    | kyotocabinet::HashDB::OTRUNCATE))
	Error("Failed to open database \"" + std::string(argv[1]) + "\" for writing ("
	      + std::string(db.error().message()) + ")!");

    try {
	ProcessRecords(max_record_count, GetPathToPdfImagesScript(argv[0]), marc_input, marc_output, &db);
    } catch (const std::exception &e) {
	Error("Caught exception: " + std::string(e.what()));
    }
}
<commit_msg>Added an optional --skip-count flag which can be useful to debug hangs.<commit_after>/** Utility for augmenting MARC records with links to a local full-text database.

  10535 http://swbplus.bsz-bw.de                  Done!
   4774 http://digitool.hbz-nrw.de:1801           Done!
   2977 http://www.gbv.de                         PDF's
   1070 http://bvbr.bib-bvb.de:8991               Done!
    975 http://deposit.d-nb.de                    HTML
    772 http://d-nb.info                          PDF's (Images => Need to OCR this?)
    520 http://www.ulb.tu-darmstadt.de            (Frau Gwinner arbeitet daran?)
    236 http://media.obvsg.at                     HTML
    167 http://www.loc.gov                        Done!
    133 http://deposit.ddb.de
    127 http://www.bibliothek.uni-regensburg.de
     57 http://nbn-resolving.de
     43 http://www.verlagdrkovac.de
     35 http://search.ebscohost.com
     25 http://idb.ub.uni-tuebingen.de
     22 http://link.springer.com
     18 http://heinonline.org
     15 http://www.waxmann.com
     13 https://www.destatis.de
     10 http://www.tandfonline.com
     10 http://dx.doi.org
      9 http://tocs.ub.uni-mainz.de
      8 http://www.onlinelibrary.wiley.com
      8 http://bvbm1.bib-bvb.de
      6 http://www.wvberlin.de
      6 http://www.jstor.org
      6 http://www.emeraldinsight.com
      6 http://www.destatis.de
      5 http://www.univerlag.uni-goettingen.de
      5 http://www.sciencedirect.com
      5 http://www.netread.com
      5 http://www.gesis.org
      5 http://content.ub.hu-berlin.de

*/
#include <iostream>
#include <map>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <kchashdb.h>
#include <libgen.h>
#include <strings.h>
#include "Downloader.h"
#include "ExecUtil.h"
#include "FileUtil.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "PdfUtil.h"
#include "RegexMatcher.h"
#include "SharedBuffer.h"
#include "SmartDownloader.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "TextUtil.h"
#include "util.h"

void Usage() {
    std::cerr << "Usage: " << progname << "[(--max-record-count | --skip-count) count] marc_input marc_output "
	      << "full_text_db\n";
    std::exit(EXIT_FAILURE);
}

// Here "word" simply means a sequence of characters not containing a space.
std::string GetLastWordAfterSpace(const std::string &text) {
    const size_t last_space_pos(text.rfind(' '));
    if (last_space_pos == std::string::npos)
	return "";

    const std::string last_word(text.substr(last_space_pos + 1));
    return last_word;
}

void ThreadSafeComposeAndWriteRecord(FILE * const output, const std::vector<DirectoryEntry> &dir_entries,
				     const std::vector<std::string> &field_data, Leader * const leader)
{
    static std::mutex marc_writer_mutex;
    std::unique_lock<std::mutex> mutex_locker(marc_writer_mutex);
    MarcUtil::ComposeAndWriteRecord(output, dir_entries, field_data, leader);
}

/** Writes "media_type" and "document" to "db" and returns the unique key that was generated for the write. */
std::string ThreadSafeWriteDocumentWithMediaType(const std::string &media_type, const std::string &document,
						 kyotocabinet::HashDB * const db)
{
    static std::mutex simple_db_writer_mutex;
    std::unique_lock<std::mutex> mutex_locker(simple_db_writer_mutex);
    static unsigned key;
    ++key;
    const std::string key_as_string(std::to_string(key));
    db->add(key_as_string, "Content-type: " + media_type + "\r\n\r\n" + document);
    return key_as_string;
}

static std::map<std::string, std::string> marc_to_tesseract_language_codes_map {
    { "fre", "fra" },
    { "eng", "eng" },
    { "ger", "deu" },
    { "ita", "ita" },
    { "dut", "nld" },
    { "swe", "swe" },
    { "dan", "dan" },
    { "nor", "nor" },
    { "rus", "rus" },
    { "fin", "fin" },
    { "por", "por" },
    { "pol", "pol" },
    { "slv", "slv" },
    { "hun", "hun" },
    { "cze", "ces" },
    { "bul", "bul" },
};

std::string GetTesseractLanguageCode(const std::vector<DirectoryEntry> &dir_entries,
                                     const std::vector<std::string> &field_data)
{
    const auto map_iter(marc_to_tesseract_language_codes_map.find(
        MarcUtil::GetLanguageCode(dir_entries, field_data)));
    return (map_iter == marc_to_tesseract_language_codes_map.cend()) ? "" : map_iter->second;
}

// Checks subfields "3" and "z" to see if they start w/ "Rezension".
bool IsProbablyAReview(const Subfields &subfields) {
    const auto _3_begin_end(subfields.getIterators('3'));
    if (_3_begin_end.first != _3_begin_end.second) {
	if (StringUtil::StartsWith(_3_begin_end.first->second, "Rezension"))
	    return true;
    } else {
	const auto z_begin_end(subfields.getIterators('z'));
	if (z_begin_end.first != z_begin_end.second
	    and StringUtil::StartsWith(z_begin_end.first->second, "Rezension"))
	    return true;
    }

    return false;
}

bool GetDocumentAndMediaType(const std::string &url, std::string * const document, std::string * const media_type) {
    if (not SmartDownload(url, document)) {
	std::cerr << "Failed to download the document for " << url << "\n";
	return false;
    }

    *media_type = MediaTypeUtil::GetMediaType(*document, /* auto_simplify = */ false);
    if (media_type->empty())
	return false;

    return true;
}

bool GetTextFromImagePDF(const std::string &document, const std::string &media_type,
			 const std::vector<DirectoryEntry> &dir_entries, const std::vector<std::string> &field_data,
			 const std::string &pdf_images_script, std::string * const extracted_text)
{
    if (not StringUtil::StartsWith(media_type, "application/pdf") or not PdfDocContainsNoText(document))
	return false;

    extracted_text->clear();
    std::cerr << "Found a PDF w/ no text.\n";

    const AutoTempFile auto_temp_file;
    const std::string &input_filename(auto_temp_file.getFilePath());
    if (not WriteString(input_filename, document))
	Error("failed to write the PDF to a temp file!");

    const AutoTempFile auto_temp_file2;
    const std::string &output_filename(auto_temp_file2.getFilePath());
    const std::string language_code(GetTesseractLanguageCode(dir_entries, field_data));
    const unsigned TIMEOUT(20); // in seconds
    if (Exec(pdf_images_script, { input_filename, output_filename, language_code }, "",
	     TIMEOUT) != 0)
    {
	Warning("failed to execute conversion script \"" + pdf_images_script + "\" w/in "
		+ std::to_string(TIMEOUT) + " seconds !");
	return true;
    }

    std::string plain_text;
    if (not ReadFile(output_filename, extracted_text))
	Error("failed to read OCR output!");

    if (extracted_text->empty())
	std::cerr << "Warning: OCR output is empty!\n";

    std::cerr << "Whoohoo, got OCR'ed text.\n";

    return true;
}

void ProcessRecords(const unsigned max_record_count, const unsigned skip_count, const std::string &pdf_images_script,
		    FILE * const input, FILE * const output, kyotocabinet::HashDB * const db)
{
    Leader *raw_leader;
    std::vector<DirectoryEntry> dir_entries;
    std::vector<std::string> field_data;
    std::string err_msg;
    unsigned total_record_count(0), records_with_relevant_links_count(0), relevant_links_count(0), failed_count(0);

    while (MarcUtil::ReadNextRecord(input, &raw_leader, &dir_entries, &field_data, &err_msg)) {
	if (total_record_count == max_record_count)
	    break;
	++total_record_count;
	if (total_record_count < skip_count)
	    continue;

	std::cout << "Processing record #" << total_record_count << ".\n";
	std::unique_ptr<Leader> leader(raw_leader);

	ssize_t _856_index(MarcUtil::GetFieldIndex(dir_entries, "856"));
	if (_856_index == -1) {
	    ThreadSafeComposeAndWriteRecord(output, dir_entries, field_data, leader.get());
	    continue;
	}

	bool found_at_least_one(false);
	for (/* Empty! */;
	     static_cast<size_t>(_856_index) < dir_entries.size() and dir_entries[_856_index].getTag() == "856";
	     ++_856_index)
	{
	    Subfields subfields(field_data[_856_index]);
	    const auto u_begin_end(subfields.getIterators('u'));
	    if (u_begin_end.first == u_begin_end.second) // No subfield 'u'.
		continue;

	    if (IsProbablyAReview(subfields))
		continue;

	    // If we get here, we have an 856u subfield that is not a review.
	    ++relevant_links_count;
	    if (not found_at_least_one) {
		++records_with_relevant_links_count;
		found_at_least_one = true;
	    }

	    std::string document, media_type;
	    if (not GetDocumentAndMediaType(u_begin_end.first->second, &document, &media_type)) {
		++failed_count;
		continue;
	    }

	    std::string extracted_text, key;
	    if (GetTextFromImagePDF(document, media_type, dir_entries, field_data, pdf_images_script,
				    &extracted_text))
		key = ThreadSafeWriteDocumentWithMediaType("text/plain", extracted_text, db);
	    else
		key = ThreadSafeWriteDocumentWithMediaType(media_type, document, db);

	    subfields.addSubfield('e', "http://localhost/cgi-bin/full_text_lookup?id=" + key);
	    const std::string new_856_field(subfields.toString());
	    MarcUtil::UpdateField(_856_index, new_856_field, leader.get(), &dir_entries, &field_data);
	}

	ThreadSafeComposeAndWriteRecord(output, dir_entries, field_data, leader.get());
    }

    if (not err_msg.empty())
	Error(err_msg);
    std::cerr << "Read " << total_record_count << " records.\n";
    std::cerr << "Found " << records_with_relevant_links_count << " records w/ relevant 856u fields.\n";
    std::cerr << failed_count << " failed downloads, media type determinations or text extractions.\n";
    std::cerr << (100.0 * (relevant_links_count - failed_count) / double(relevant_links_count)) << "% successes.\n";

    std::fclose(input);
}

const std::string BASH_HELPER("pdf_images_to_text.sh");

std::string GetPathToPdfImagesScript(const char * const argv0) {
    char path[std::strlen(argv0) + 1];
    std::strcpy(path, argv0);
    const std::string pdf_images_script_path(std::string(::dirname(path)) + "/" + BASH_HELPER);
    if (::access(pdf_images_script_path.c_str(), X_OK) != 0)
	Error("can't execute \"" + pdf_images_script_path + "\"!");
    return pdf_images_script_path;
}

int main(int argc, char *argv[]) {
    progname = argv[0];

    if (argc != 4 and argc != 6)
	Usage();

    unsigned max_record_count(UINT_MAX), skip_count(0);
    if (argc == 6) {
	if (std::strcmp(argv[1], "--max-record-count") != 0 and std::strcmp(argv[1], "--skip-count") != 0)
	    Usage();
	if (std::strcmp(argv[1], "--max-record-count") == 0) {
	    if (not StringUtil::ToUnsigned(argv[2], &max_record_count))
		Error(std::string(argv[2]) + " is not a valid max. record count!");
	} else {
	    if (not StringUtil::ToUnsigned(argv[2], &skip_count))
		Error(std::string(argv[2]) + " is not a valid skip count!");
	}
	argc -= 2, argv += 2;
    }

    const std::string marc_input_filename(argv[1]);
    FILE *marc_input = std::fopen(marc_input_filename.c_str(), "rb");
    if (marc_input == NULL)
	Error("can't open \"" + marc_input_filename + "\" for reading!");

    const std::string marc_output_filename(argv[2]);
    FILE *marc_output = std::fopen(marc_output_filename.c_str(), "wb");
    if (marc_output == NULL)
	Error("can't open \"" + marc_output_filename + "\" for writing!");

    kyotocabinet::HashDB db;
    if (not db.open(argv[3],
		    kyotocabinet::HashDB::OWRITER | kyotocabinet::HashDB::OCREATE
		    | kyotocabinet::HashDB::OTRUNCATE))
	Error("Failed to open database \"" + std::string(argv[1]) + "\" for writing ("
	      + std::string(db.error().message()) + ")!");

    try {
	ProcessRecords(max_record_count, skip_count, GetPathToPdfImagesScript(argv[0]), marc_input, marc_output, &db);
    } catch (const std::exception &e) {
	Error("Caught exception: " + std::string(e.what()));
    }
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <set>
#include <string>
#include <assert.h>

using namespace std;

set<string> done;

void dump_header(string header) {
    if (done.find(header) != done.end()) return;
    done.insert(header);

    FILE *f = fopen(header.c_str(), "r");

    if (f == NULL) {
      fprintf(stderr, "Could not open header %s.\n", header.c_str());
      exit(1);
    }

    char line[1024];

    while (fgets(line, 1024, f)) {
        if (strncmp(line, "#include \"", 10) == 0) {
            char *sub_header = line + 10;
            for (int i = 0; i < 1014; i++) {
                if (sub_header[i] == '"') sub_header[i] = 0;
            }
            size_t slash_pos = header.rfind('/');
            std::string path;
            if (slash_pos != std::string::npos)
                path = header.substr(0, slash_pos + 1);
            dump_header(path + sub_header);
        } else {
            fputs(line, stdout);
        }
    }

    fclose(f);
}

int main(int argc, char **headers) {
    for (int i = 1; i < argc; i++) {
        dump_header(headers[i]);
    }

    return 0;
}
<commit_msg>Remove dependency on importing std into global namespace.<commit_after>#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <set>
#include <string>
#include <assert.h>

std::set<std::string> done;

void dump_header(std::string header) {
    if (done.find(header) != done.end()) return;
    done.insert(header);

    FILE *f = fopen(header.c_str(), "r");

    if (f == NULL) {
      fprintf(stderr, "Could not open header %s.\n", header.c_str());
      exit(1);
    }

    char line[1024];

    while (fgets(line, 1024, f)) {
        if (strncmp(line, "#include \"", 10) == 0) {
            char *sub_header = line + 10;
            for (int i = 0; i < 1014; i++) {
                if (sub_header[i] == '"') sub_header[i] = 0;
            }
            size_t slash_pos = header.rfind('/');
            std::string path;
            if (slash_pos != std::string::npos)
                path = header.substr(0, slash_pos + 1);
            dump_header(path + sub_header);
        } else {
            fputs(line, stdout);
        }
    }

    fclose(f);
}

int main(int argc, char **headers) {
    for (int i = 1; i < argc; i++) {
        dump_header(headers[i]);
    }

    return 0;
}
<|endoftext|>


<commit_before>/** \file translation_db_tool.cc
 *  \brief A tool for reading/editing of the "translations" SQL table.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <set>
#include <cstdlib>
#include <cstring>
#include "Compiler.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "IniFile.h"
#include "SimpleXmlParser.h"
#include "StringUtil.h"
#include "TranslationUtil.h"
#include "util.h"

void Usage() {
    std::cerr << "Usage: " << progname << " command [args]\n\n";
    std::cerr << "       Possible commands are:\n";
    std::cerr << "       get_missing language_code\n";
    std::cerr << "       insert index language_code category text\n";
    std::exit(EXIT_FAILURE);
}

void ExecSqlOrDie(const std::string &select_statement, DbConnection * const connection) {
    if (unlikely(not connection->query(select_statement)))
        Error("SQL Statement failed: " + select_statement + " (" + connection->getLastErrorMessage() + ")");
}

// Replaces a comma with "\," and a slash with "\\".
std::string EscapeCommasAndBackslashes(const std::string &text) {
    std::string escaped_text;
    for (const auto ch : text) {
        if (unlikely(ch == ',' or ch == '\\'))
            escaped_text += '\\';
        escaped_text += ch;
    }

    return escaped_text;
}

void GetMissing(DbConnection * const connection, const std::string &language_code) {
    // Find an ID where "language_code" is missing:
    ExecSqlOrDie("SELECT id FROM translations WHERE id NOT IN (SELECT id FROM translations "
                 "WHERE language_code = \"" + language_code + "\") LIMIT 1", connection);
    DbResultSet id_result_set(connection->getLastResultSet());
    if (id_result_set.empty()) // The language code whose absence we're looking for exists for all ID's.!
        return;

    // Print the contents of all rows with the ID from the last query on stdout:
    const std::string matching_id(id_result_set.getNextRow()["id"]);
    ExecSqlOrDie("SELECT * FROM translations WHERE id=" + matching_id, connection);
    DbResultSet result_set(connection->getLastResultSet());
    if (not result_set.empty()) {
        const DbRow row = result_set.getNextRow();
        std::cout << row["id"] << ',' << row["language_code"] << ',' << EscapeCommasAndBackslashes(row["text"]) << ','
                  << row["category"] << '\n';
    }
}

void Insert(DbConnection * const connection, const unsigned index, const std::string &language_code,
            const std::string &category, const std::string &text)
{
    const std::string ID(std::to_string(index));
    if (category == "vufind_translations") {
        // First get the token that we need for the INSERT:
        const std::string SELECT_STMT("SELECT token FROM translations WHERE category='vufind_translations' AND id='"
                                      + ID + "'");
        ExecSqlOrDie(SELECT_STMT, connection);
        DbResultSet result_set(connection->getLastResultSet());
        if (result_set.empty())
            Error("Select unexpectedly returned an empty result set: " + SELECT_STMT);
        const DbRow row = result_set.getNextRow();
        const std::string token(row[0]);

        ExecSqlOrDie("INSERT INTO translations SET id=" + ID + ",language_code=\"" + language_code + "\",text=\""
                     + connection->escapeString(text) + "\", category='vufind_translations', token='" + token
                     + "', preexists=FALSE", connection);
    } else
        ExecSqlOrDie("INSERT INTO translations SET id=" + ID + ",language_code=\"" + language_code + "\",text=\""
                     + connection->escapeString(text) + "\", category='" + category + "', preexists=FALSE",
                     connection);
}

void GetPossibleCategories(DbConnection * const connection, std::set<std::string> * const categories) {
    categories->clear();

    ExecSqlOrDie("SELECT DISTINCT category FROM translations", connection);
    DbResultSet categories_result_set(connection->getLastResultSet());
    while (const DbRow row = categories_result_set.getNextRow())
        categories->insert(row[0]);
}

const std::string CONF_FILE_PATH("/var/lib/tuelib/translations.conf");

int main(int argc, char *argv[]) {
    progname = argv[0];

    try {
        if (argc < 2)
            Usage();

        const IniFile ini_file(CONF_FILE_PATH);
        const std::string sql_database(ini_file.getString("", "sql_database"));
        const std::string sql_username(ini_file.getString("", "sql_username"));
        const std::string sql_password(ini_file.getString("", "sql_password"));
        DbConnection db_connection("vufind", sql_username, sql_password);

        if (std::strcmp(argv[1], "get_missing") == 0) {
            if (argc != 3)
                Error("\"get_missing\" requires exactly one argument: language_code!");
            const std::string language_code(argv[2]);
            if (not TranslationUtil::IsValidGerman3LetterCode(language_code))
                Error("\"" + language_code + "\" is not a valid 3-letter language code!");
            GetMissing(&db_connection, language_code);
        } else if (std::strcmp(argv[1], "insert") == 0) {
            if (argc != 6)
                Error("\"insert\" requires exactly four arguments: index, language_code, category, and text!");

            unsigned index;
            if (not StringUtil::ToUnsigned(argv[2], &index))
                Error("\"" + std::string(argv[2])  + "\" is not a valid index!");

            const std::string language_code(argv[3]);
            if (not TranslationUtil::IsValidGerman3LetterCode(language_code))
                Error("\"" + language_code + "\" is not a valid German 3-letter language code!");

            std::set<std::string> valid_categories;
            GetPossibleCategories(&db_connection, &valid_categories);
            const std::string category(argv[4]);
            if (valid_categories.find(category) == valid_categories.cend())
                Error("\"" + category + "\" is not a valid category, valid categories are: "
                      + StringUtil::Join(valid_categories, ", ") + ".");

            Insert(&db_connection, index, language_code, category, argv[5]);
        } else
            Error("unknown command \"" + std::string(argv[1]) + "\"!");
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Adapted to Oli's new two table strategy.<commit_after>/** \file translation_db_tool.cc
 *  \brief A tool for reading/editing of the "translations" SQL table.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <set>
#include <cstdlib>
#include <cstring>
#include "Compiler.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "IniFile.h"
#include "SimpleXmlParser.h"
#include "StringUtil.h"
#include "TranslationUtil.h"
#include "util.h"

void Usage() {
    std::cerr << "Usage: " << progname << " command [args]\n\n";
    std::cerr << "       Possible commands are:\n";
    std::cerr << "       get_missing language_code\n";
    std::cerr << "       insert index language_code category text\n";
    std::exit(EXIT_FAILURE);
}

void ExecSqlOrDie(const std::string &select_statement, DbConnection * const connection) {
    if (unlikely(not connection->query(select_statement)))
        Error("SQL Statement failed: " + select_statement + " (" + connection->getLastErrorMessage() + ")");
}

// Replaces a comma with "\," and a slash with "\\".
std::string EscapeCommasAndBackslashes(const std::string &text) {
    std::string escaped_text;
    for (const auto ch : text) {
        if (unlikely(ch == ',' or ch == '\\'))
            escaped_text += '\\';
        escaped_text += ch;
    }

    return escaped_text;
}

unsigned GetMissingVuFindTranslations(DbConnection * const connection, const std::string &language_code) {
    // Find an ID where "language_code" is missing:
    ExecSqlOrDie("SELECT id FROM vufind_translations WHERE id NOT IN (SELECT id FROM vufind_translations "
                 "WHERE language_code = \"" + language_code + "\") LIMIT 1", connection);
    DbResultSet id_result_set(connection->getLastResultSet());
    if (id_result_set.empty()) // The language code whose absence we're looking for exists for all ID's.!
        return 0;

    // Print the contents of all rows with the ID from the last query on stdout:
    const std::string matching_id(id_result_set.getNextRow()["id"]);
    ExecSqlOrDie("SELECT * FROM vufind_translations WHERE id=" + matching_id, connection);
    DbResultSet result_set(connection->getLastResultSet());
    if (not result_set.empty()) {
        const DbRow row = result_set.getNextRow();
        std::cout << row["id"] << ',' << row["language_code"] << ',' << EscapeCommasAndBackslashes(row["text"]) << ','
                  << "vufind_translations\n";
    }

    return result_set.size();
}

unsigned GetMissingKeywordTranslations(DbConnection * const connection, const std::string &language_code) {
    // Find an ID where "language_code" is missing:
    ExecSqlOrDie("SELECT id FROM keyword_translations WHERE id NOT IN (SELECT id FROM keyword_translations "
                 "WHERE language_code = \"" + language_code + "\") LIMIT 1", connection);
    DbResultSet id_result_set(connection->getLastResultSet());
    if (id_result_set.empty()) // The language code whose absence we're looking for exists for all ID's.!
        return 0;

    // Print the contents of all rows with the ID from the last query on stdout:
    const std::string matching_id(id_result_set.getNextRow()["id"]);
    ExecSqlOrDie("SELECT * FROM keyword_translations WHERE id=" + matching_id, connection);
    DbResultSet result_set(connection->getLastResultSet());
    if (not result_set.empty()) {
        const DbRow row = result_set.getNextRow();
        std::cout << row["id"] << ',' << row["language_code"] << ',' << EscapeCommasAndBackslashes(row["text"]) << ','
                  << "keywords\n";
    }

    return result_set.size();
}

void InsertIntoVuFindTranslations(DbConnection * const connection, const unsigned index,
                                  const std::string &language_code, const std::string &text)
{
    const std::string ID(std::to_string(index));

    // First get the token that we need for the INSERT:
    const std::string SELECT_STMT("SELECT token FROM vufind_translations WHERE category='vufind_translations' "
                                  "AND id='" + ID + "'");
    ExecSqlOrDie(SELECT_STMT, connection);
    DbResultSet result_set(connection->getLastResultSet());
    if (result_set.empty())
        Error("Select unexpectedly returned an empty result set: " + SELECT_STMT);
    const DbRow row = result_set.getNextRow();
    const std::string token(row[0]);

    ExecSqlOrDie("INSERT INTO vufind_translations SET id=" + ID + ",language_code=\"" + language_code
                 + "\",text=\"" + connection->escapeString(text) + "\", token='" + token + "'", connection);
}

void InsertIntoKeywordTranslations(DbConnection * const connection, const unsigned index,
                                   const std::string &language_code, const std::string &text)
{
    const std::string ID(std::to_string(index));
    ExecSqlOrDie("INSERT INTO keyword_translations SET id=" + ID + ",language_code=\"" + language_code + "\",text=\""
                 + connection->escapeString(text) + "\"", connection);
}

const std::string CONF_FILE_PATH("/var/lib/tuelib/translations.conf");

int main(int argc, char *argv[]) {
    progname = argv[0];

    try {
        if (argc < 2)
            Usage();

        const IniFile ini_file(CONF_FILE_PATH);
        const std::string sql_database(ini_file.getString("", "sql_database"));
        const std::string sql_username(ini_file.getString("", "sql_username"));
        const std::string sql_password(ini_file.getString("", "sql_password"));
        DbConnection db_connection("vufind", sql_username, sql_password);

        if (std::strcmp(argv[1], "get_missing") == 0) {
            if (argc != 3)
                Error("\"get_missing\" requires exactly one argument: language_code!");
            const std::string language_code(argv[2]);
            if (not TranslationUtil::IsValidGerman3LetterCode(language_code))
                Error("\"" + language_code + "\" is not a valid 3-letter language code!");
            if (GetMissingVuFindTranslations(&db_connection, language_code))
                GetMissingKeywordTranslations(&db_connection, language_code);
        } else if (std::strcmp(argv[1], "insert") == 0) {
            if (argc != 6)
                Error("\"insert\" requires exactly four arguments: index, language_code, category, and text!");

            unsigned index;
            if (not StringUtil::ToUnsigned(argv[2], &index))
                Error("\"" + std::string(argv[2])  + "\" is not a valid index!");

            const std::string language_code(argv[3]);
            if (not TranslationUtil::IsValidGerman3LetterCode(language_code))
                Error("\"" + language_code + "\" is not a valid German 3-letter language code!");

            const std::string category(argv[4]);
            if (category != "vufind_translations" and category != "keyword")
                Error("\"" + category + "\" is not a valid category, valid categories are: 'vufind_translations' "
                      " and 'keywords'.");

            if (category == "vufind_translations")
                InsertIntoVuFindTranslations(&db_connection, index, language_code, argv[5]);
            else
                InsertIntoKeywordTranslations(&db_connection, index, language_code, argv[5]);
        } else
            Error("unknown command \"" + std::string(argv[1]) + "\"!");
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
// LLVM 'OPT' UTILITY
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Transforms/ConstantMerge.h"
#include "llvm/Transforms/CleanupGCCOutput.h"
#include "llvm/Transforms/LevelChange.h"
#include "llvm/Transforms/FunctionInlining.h"
#include "llvm/Transforms/ChangeAllocations.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/IPO/SimpleStructMutation.h"
#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "llvm/Transforms/IPO/PoolAllocate.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Transforms/Instrumentation/TraceValues.h"
#include "llvm/Transforms/Instrumentation/ProfilePaths.h"
#include "llvm/Transforms/Instrumentation/EmitFunctions.h"
#include "llvm/Target/TargetData.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <fstream>
#include <memory>

using std::cerr;

// FIXME: This should be parameterizable eventually for different target
// types...
static TargetData TD("opt target");

// Opts enum - All of the transformations we can do...
enum Opts {
  // Basic optimizations
  dce, die, constprop, gcse, licm, inlining, constmerge,
  strip, mstrip, mergereturn, simplifycfg,

  // Miscellaneous Transformations
  raiseallocs, lowerallocs, funcresolve, cleangcc, lowerrefs,

  // Printing and verifying...
  print, printm, verify,

  // More powerful optimizations
  indvars, instcombine, sccp, adce, raise, reassociate, mem2reg, pinodes,

  // Instrumentation
  trace, tracem, paths, emitfuncs,

  // Interprocedural optimizations...
  internalize, globaldce, swapstructs, sortstructs, poolalloc,
};

static Pass *createPrintFunctionPass() {
  return new PrintFunctionPass("Current Function: \n", &cerr);
}

static Pass *createPrintModulePass() {
  return new PrintModulePass(&cerr);
}

static Pass *createLowerAllocationsPassNT() {
  return createLowerAllocationsPass(TD);
}

// OptTable - Correlate enum Opts to Pass constructors...
//
struct {
  enum Opts OptID;
  Pass * (*PassCtor)();
} OptTable[] = {
  { dce        , createDeadCodeEliminationPass    },
  { die        , createDeadInstEliminationPass    },
  { constprop  , createConstantPropogationPass    },
  { gcse       , createGCSEPass                   },
  { licm       , createLICMPass                   },
  { inlining   , createFunctionInliningPass       },
  { constmerge , createConstantMergePass          },
  { strip      , createSymbolStrippingPass        },
  { mstrip     , createFullSymbolStrippingPass    },
  { mergereturn, createUnifyFunctionExitNodesPass },
  { simplifycfg, createCFGSimplificationPass      },

  { indvars    , createIndVarSimplifyPass         },
  { instcombine, createInstructionCombiningPass   },
  { sccp       , createSCCPPass                   },
  { adce       , createAggressiveDCEPass          },
  { raise      , createRaisePointerReferencesPass },
  /* { reassociate, createReassociatePass            },*/
  { mem2reg    , createPromoteMemoryToRegister    },
  { pinodes    , createPiNodeInsertionPass        },
  { lowerrefs  , createDecomposeMultiDimRefsPass  },

  { trace      , createTraceValuesPassForBasicBlocks },
  { tracem     , createTraceValuesPassForFunction    },
  { paths      , createProfilePathsPass              },
  { emitfuncs  , createEmitFunctionTablePass },
  { print      , createPrintFunctionPass },
  { printm     , createPrintModulePass   },
  { verify     , createVerifierPass      },

  { raiseallocs, createRaiseAllocationsPass   },
  { lowerallocs, createLowerAllocationsPassNT },
  { cleangcc   , createCleanupGCCOutputPass   },
  { funcresolve, createFunctionResolvingPass  },

  { internalize, createInternalizePass  },
  { globaldce  , createGlobalDCEPass    },
  { swapstructs, createSwapElementsPass },
  { sortstructs, createSortElementsPass },
  { poolalloc  , createPoolAllocatePass },
};

// Command line option handling code...
//
static cl::opt<string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));

static cl::opt<string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
PrintEachXForm("p", cl::desc("Print module after each transformation"));

static cl::opt<bool>
Quiet("q", cl::desc("Don't print modifying pass names"));

static cl::alias
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));

static cl::list<enum Opts>
OptimizationList(cl::desc("Optimizations available:"), cl::values(
  clEnumVal(dce        , "Dead Code Elimination"),
  clEnumVal(die        , "Dead Instruction Elimination"),
  clEnumVal(constprop  , "Simple constant propogation"),
  clEnumVal(gcse       , "Global Common Subexpression Elimination"),
  clEnumVal(licm       , "Loop Invariant Code Motion"),
 clEnumValN(inlining   , "inline", "Function integration"),
  clEnumVal(constmerge , "Merge identical global constants"),
  clEnumVal(strip      , "Strip symbols"),
  clEnumVal(mstrip     , "Strip module symbols"),
  clEnumVal(mergereturn, "Unify function exit nodes"),
  clEnumVal(simplifycfg, "CFG Simplification"),

  clEnumVal(indvars    , "Simplify Induction Variables"),
  clEnumVal(instcombine, "Combine redundant instructions"),
  clEnumVal(sccp       , "Sparse Conditional Constant Propogation"),
  clEnumVal(adce       , "Aggressive DCE"),
  clEnumVal(reassociate, "Reassociate expressions"),
  clEnumVal(mem2reg    , "Promote alloca locations to registers"),
  clEnumVal(pinodes    , "Insert Pi nodes after definitions"),

  clEnumVal(internalize, "Mark all fn's internal except for main"),
  clEnumVal(globaldce  , "Remove unreachable globals"),
  clEnumVal(swapstructs, "Swap structure types around"),
  clEnumVal(sortstructs, "Sort structure elements"),
  clEnumVal(poolalloc  , "Pool allocate disjoint datastructures"),

  clEnumVal(raiseallocs, "Raise allocations from calls to instructions"),
  clEnumVal(lowerallocs, "Lower allocations from instructions to calls (TD)"),
  clEnumVal(cleangcc   , "Cleanup GCC Output"),
  clEnumVal(funcresolve, "Resolve calls to foo(...) to foo(<concrete types>)"),
  clEnumVal(raise      , "Raise to Higher Level"),
  clEnumVal(trace      , "Insert BB and Function trace code"),
  clEnumVal(tracem     , "Insert Function trace code only"),
  clEnumVal(paths      , "Insert path profiling instrumentation"),
  clEnumVal(emitfuncs  , "Insert function pointer table"),
  clEnumVal(print      , "Print working function to stderr"),
  clEnumVal(printm     , "Print working module to stderr"),
  clEnumVal(verify     , "Verify module is well formed"),
  clEnumVal(lowerrefs  , "Decompose multi-dimensional structure/array refs to use one index per instruction"),
0));

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << "Error opening '" << OutputFilename << "': File exists!\n"
           << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      cerr << "Error opening " << OutputFilename << "!\n";
      return 1;
    }

    // Make sure that the Output file gets unlink'd from the disk if we get a
    // SIGINT
    RemoveFileOnSignal(OutputFilename);
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    enum Opts Opt = OptimizationList[i];
    for (unsigned j = 0; j < sizeof(OptTable)/sizeof(OptTable[0]); ++j)
      if (Opt == OptTable[j].OptID) {
        Passes.add(OptTable[j].PassCtor());
        break;
      }

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&std::cerr));
  }

  // Check that the module is well formed on completion of optimization
  Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(*M.get()) && !Quiet)
    cerr << "Program modified.\n";

  return 0;
}
<commit_msg>Use the pass registration mechanism to populate command line options for opt, not huge explicit gross tables.<commit_after>//===----------------------------------------------------------------------===//
// LLVM 'OPT' UTILITY
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Target/TargetData.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <fstream>
#include <memory>
#include <algorithm>

using std::cerr;

//===----------------------------------------------------------------------===//
// PassNameParser class - Make use of the pass registration mechanism to
// automatically add a command line argument to opt for each pass.
//
namespace {  // anonymous namespace for local class...
class PassNameParser : public PassRegistrationListener,
                       public cl::parser<const PassInfo*> {
  cl::Option *Opt;
public:
  PassNameParser() : Opt(0) {}

  void initialize(cl::Option &O) {
    Opt = &O;
    cl::parser<const PassInfo*>::initialize(O);

    // Add all of the passes to the map that got initialized before 'this' did.
    enumeratePasses();
  }

  static inline bool ignorablePass(const PassInfo *P) {
    // Ignore non-selectable and non-constructible passes!
    return P->getPassArgument() == 0 ||
          (P->getNormalCtor() == 0 && P->getDataCtor() == 0);
  }

  // Implement the PassRegistrationListener callbacks used to populate our map
  //
  virtual void passRegistered(const PassInfo *P) {
    if (ignorablePass(P) || !Opt) return;
    assert(findOption(P->getPassArgument()) == getNumOptions() &&
           "Two passes with the same argument attempted to be registered!");
    addLiteralOption(P->getPassArgument(), P, P->getPassName());
    Opt->addArgument(P->getPassArgument());
  }
  virtual void passEnumerate(const PassInfo *P) { passRegistered(P); }

  virtual void passUnregistered(const PassInfo *P) {
    if (ignorablePass(P) || !Opt) return;
    assert(findOption(P->getPassArgument()) != getNumOptions() &&
           "Registered Pass not in the pass map!");
    removeLiteralOption(P->getPassArgument());
    Opt->removeArgument(P->getPassArgument());
  }

  // ValLessThan - Provide a sorting comparator for Values elements...
  typedef std::pair<const char*,
                    std::pair<const PassInfo*, const char*> > ValType;
  static bool ValLessThan(const ValType &VT1, const ValType &VT2) {
    return std::string(VT1.first) < std::string(VT2.first);
  }

  // printOptionInfo - Print out information about this option.  Override the
  // default implementation to sort the table before we print...
  virtual void printOptionInfo(const cl::Option &O, unsigned GlobalWidth) const{
    PassNameParser *PNP = const_cast<PassNameParser*>(this);
    std::sort(PNP->Values.begin(), PNP->Values.end(), ValLessThan);
    cl::parser<const PassInfo*>::printOptionInfo(O, GlobalWidth);
  }
};
} // end anonymous namespace

// The OptimizationList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool, PassNameParser>
OptimizationList(cl::desc("Optimizations available:"));

// Other command line options...
//
static cl::opt<string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));

static cl::opt<string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
PrintEachXForm("p", cl::desc("Print module after each transformation"));

static cl::opt<bool>
Quiet("q", cl::desc("Don't print modifying pass names"));

static cl::alias
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));

//===----------------------------------------------------------------------===//
// main for opt
//
int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  // FIXME: This should be parameterizable eventually for different target
  // types...
  TargetData TD("opt target");

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << "Error opening '" << OutputFilename << "': File exists!\n"
           << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      cerr << "Error opening " << OutputFilename << "!\n";
      return 1;
    }

    // Make sure that the Output file gets unlink'd from the disk if we get a
    // SIGINT
    RemoveFileOnSignal(OutputFilename);
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    const PassInfo *Opt = OptimizationList[i];

    if (Opt->getNormalCtor())
      Passes.add(Opt->getNormalCtor()());
    else if (Opt->getDataCtor())
      Passes.add(Opt->getDataCtor()(TD));  // Pass dummy target data...
    else
      cerr << "Cannot create pass: " << Opt->getPassName() << "\n";

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&cerr));
  }

  // Check that the module is well formed on completion of optimization
  Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(*M.get()) && !Quiet)
    cerr << "Program modified.\n";

  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ali Saidi
 */

/** @file
 * Implementiation of a PL390 GIC
 */

#ifndef __DEV_ARM_GIC_PL390_H__
#define __DEV_ARM_GIC_PL390_H__

#include "base/bitunion.hh"
#include "cpu/intr_control.hh"
#include "dev/arm/base_gic.hh"
#include "dev/io_device.hh"
#include "dev/platform.hh"
#include "params/Pl390.hh"

/** @todo this code only assumes one processor for now. Low word
 * of intEnabled and pendingInt need to be replicated per CPU.
 * bottom 31 interrupts (7 words) need to be replicated for
 * for interrupt priority register, processor target registers
 * interrupt config registers  */

class Pl390 : public BaseGic
{
  protected:
    // distributor memory addresses
    static const int ICDDCR     = 0x000; // control register
    static const int ICDICTR    = 0x004; // controller type
    static const int ICDIIDR    = 0x008; // implementer id
    static const int ICDISER_ST = 0x100; // interrupt set enable
    static const int ICDISER_ED = 0x17c;
    static const int ICDICER_ST = 0x180; // interrupt clear enable
    static const int ICDICER_ED = 0x1fc;
    static const int ICDISPR_ST = 0x200; // set pending interrupt
    static const int ICDISPR_ED = 0x27c;
    static const int ICDICPR_ST = 0x280; // clear pending interrupt
    static const int ICDICPR_ED = 0x2fc;
    static const int ICDABR_ST  = 0x300; // active bit registers
    static const int ICDABR_ED  = 0x37c;
    static const int ICDIPR_ST  = 0x400; // interrupt priority registers
    static const int ICDIPR_ED  = 0x7f8;
    static const int ICDIPTR_ST = 0x800; // processor target registers
    static const int ICDIPTR_ED = 0xbf8;
    static const int ICDICFR_ST = 0xc00; // interrupt config registers
    static const int ICDICFR_ED = 0xcfc;
    static const int ICDSGIR    = 0xf00; // software generated interrupt
    static const int DIST_SIZE  = 0xfff;

    // cpu memory addressesa
    static const int ICCICR  = 0x00; // CPU control register
    static const int ICCPMR  = 0x04; // Interrupt priority mask
    static const int ICCBPR  = 0x08; // binary point register
    static const int ICCIAR  = 0x0C; // interrupt ack register
    static const int ICCEOIR = 0x10; // end of interrupt
    static const int ICCRPR  = 0x14; // runing priority
    static const int ICCHPIR = 0x18; // highest pending interrupt
    static const int ICCABPR = 0x1c; // aliased binary point
    static const int ICCIIDR = 0xfc; // cpu interface id register
    static const int CPU_SIZE  = 0xff;

    static const int SGI_MAX = 16;  // Number of Software Gen Interrupts
    static const int PPI_MAX = 16;  // Number of Private Peripheral Interrupts

    /** Mask off SGI's when setting/clearing pending bits */
    static const int SGI_MASK = 0xFFFF0000;

    /** Mask for bits that config N:N mode in ICDICFR's */
    static const int NN_CONFIG_MASK = 0x55555555;

    static const int CPU_MAX = 8;   // Max number of supported CPU interfaces
    static const int SPURIOUS_INT = 1023;
    static const int INT_BITS_MAX = 32;
    static const int INT_LINES_MAX = 1020;

    BitUnion32(SWI)
        Bitfield<3,0> sgi_id;
        Bitfield<23,16> cpu_list;
        Bitfield<25,24> list_type;
    EndBitUnion(SWI)

    BitUnion32(IAR)
        Bitfield<9,0> ack_id;
        Bitfield<12,10> cpu_id;
    EndBitUnion(IAR)

    /** Distributor address GIC listens at */
    Addr distAddr;

    /** CPU address GIC listens at */
    /** @todo is this one per cpu? */
    Addr cpuAddr;

    /** Latency for a distributor operation */
    Tick distPioDelay;

    /** Latency for a cpu operation */
    Tick cpuPioDelay;

    /** Latency for a interrupt to get to CPU */
    Tick intLatency;

    /** Gic enabled */
    bool enabled;

    /** Number of itLines enabled */
    uint32_t itLines;

    uint32_t itLinesLog2;

    /** interrupt enable bits for all possible 1020 interupts.
     * one bit per interrupt, 32 bit per word = 32 words */
    uint32_t intEnabled[INT_BITS_MAX];

    /** interrupt pending bits for all possible 1020 interupts.
     * one bit per interrupt, 32 bit per word = 32 words */
    uint32_t pendingInt[INT_BITS_MAX];

    /** interrupt active bits for all possible 1020 interupts.
     * one bit per interrupt, 32 bit per word = 32 words */
    uint32_t activeInt[INT_BITS_MAX];

    /** read only running priroity register, 1 per cpu*/
    uint32_t iccrpr[CPU_MAX];

    /** an 8 bit priority (lower is higher priority) for each
     * of the 1020 possible supported interrupts.
     */
    uint8_t intPriority[INT_LINES_MAX];

    /** an 8 bit cpu target id for each shared peripheral interrupt
     * of the 1020 possible supported interrupts.
     */
    uint8_t cpuTarget[INT_LINES_MAX];

    /** 2 bit per interrupt signaling if it's level or edge sensitive
     * and if it is 1:N or N:N */
    uint32_t intConfig[INT_BITS_MAX*2];

    /** CPU enabled */
    bool cpuEnabled[CPU_MAX];

    /** CPU priority */
    uint8_t cpuPriority[CPU_MAX];

    /** Binary point registers */
    uint8_t cpuBpr[CPU_MAX];

    /** highest interrupt that is interrupting CPU */
    uint32_t cpuHighestInt[CPU_MAX];

    /** One bit per cpu per software interrupt that is pending for each possible
     * sgi source. Indexed by SGI number. Each byte in generating cpu id and
     * bits in position is destination id. e.g. 0x4 = CPU 0 generated interrupt
     * for CPU 2. */
    uint64_t cpuSgiPending[SGI_MAX];
    uint64_t cpuSgiActive[SGI_MAX];

    /** One bit per private peripheral interrupt. Only upper 16 bits
     * will be used since PPI interrupts are numberred from 16 to 32 */
    uint32_t cpuPpiPending[CPU_MAX];
    uint32_t cpuPpiActive[CPU_MAX];

    /** Banked interrupt prioirty registers for SGIs and PPIs */
    uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX];

    /** IRQ Enable Used for debug */
    bool irqEnable;

    /** software generated interrupt
     * @param data data to decode that indicates which cpus to interrupt
     */
    void softInt(int ctx_id, SWI swi);

    /** See if some processor interrupt flags need to be enabled/disabled
     * @param hint which set of interrupts needs to be checked
     */
    void updateIntState(int hint);

    /** Update the register that records priority of the highest priority
     *  active interrupt*/
    void updateRunPri();

    /** generate a bit mask to check cpuSgi for an interrupt. */
    uint64_t genSwiMask(int cpu);

    int intNumToWord(int num) const { return num >> 5; }
    int intNumToBit(int num) const { return num % 32; }

    /** Post an interrupt to a CPU
     */
    void postInt(uint32_t cpu, Tick when);

    /** Event definition to post interrupt to CPU after a delay
    */
    class PostIntEvent : public Event
    {
      private:
        uint32_t cpu;
        Platform *platform;
      public:
        PostIntEvent( uint32_t c, Platform* p)
            : cpu(c), platform(p)
        { }
        void process() { platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);}
        const char *description() const { return "Post Interrupt to CPU"; }
    };
    PostIntEvent *postIntEvent[CPU_MAX];

  public:
    typedef Pl390Params Params;
    const Params *
    params() const
    {
        return dynamic_cast<const Params *>(_params);
    }
    Pl390(const Params *p);

    /** Return the address ranges used by the Gic
     * This is the distributor address + all cpu addresses
     */
    virtual AddrRangeList getAddrRanges() const;

    /** A PIO read to the device, immediately split up into
     * readDistributor() or readCpu()
     */
    virtual Tick read(PacketPtr pkt);

    /** A PIO read to the device, immediately split up into
     * writeDistributor() or writeCpu()
     */
    virtual Tick write(PacketPtr pkt);

    /** Handle a read to the distributor poriton of the GIC
     * @param pkt packet to respond to
     */
    Tick readDistributor(PacketPtr pkt);

    /** Handle a read to the cpu poriton of the GIC
     * @param pkt packet to respond to
     */
    Tick readCpu(PacketPtr pkt);

    /** Handle a write to the distributor poriton of the GIC
     * @param pkt packet to respond to
     */
    Tick writeDistributor(PacketPtr pkt);

    /** Handle a write to the cpu poriton of the GIC
     * @param pkt packet to respond to
     */
    Tick writeCpu(PacketPtr pkt);

    /** Post an interrupt from a device that is connected to the Gic.
     * Depending on the configuration, the gic will pass this interrupt
     * on through to a CPU.
     * @param number number of interrupt to send */
    void sendInt(uint32_t number);

    /** Interface call for private peripheral interrupts  */
    void sendPPInt(uint32_t num, uint32_t cpu);

    /** Clear an interrupt from a device that is connected to the Gic
     * Depending on the configuration, the gic may de-assert it's cpu line
     * @param number number of interrupt to send */
    void clearInt(uint32_t number);

    /* Various functions fer testing and debugging */
    void driveSPI(uint32_t spi);
    void driveLegIRQ(bool state);
    void driveLegFIQ(bool state);
    void driveIrqEn(bool state);

    virtual void serialize(std::ostream &os);
    virtual void unserialize(Checkpoint *cp, const std::string &section);

};

#endif //__DEV_ARM_GIC_H__
<commit_msg>arm: Don't export private GIC methods<commit_after>/*
 * Copyright (c) 2010 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ali Saidi
 */

/** @file
 * Implementiation of a PL390 GIC
 */

#ifndef __DEV_ARM_GIC_PL390_H__
#define __DEV_ARM_GIC_PL390_H__

#include "base/bitunion.hh"
#include "cpu/intr_control.hh"
#include "dev/arm/base_gic.hh"
#include "dev/io_device.hh"
#include "dev/platform.hh"
#include "params/Pl390.hh"

/** @todo this code only assumes one processor for now. Low word
 * of intEnabled and pendingInt need to be replicated per CPU.
 * bottom 31 interrupts (7 words) need to be replicated for
 * for interrupt priority register, processor target registers
 * interrupt config registers  */

class Pl390 : public BaseGic
{
  protected:
    // distributor memory addresses
    static const int ICDDCR     = 0x000; // control register
    static const int ICDICTR    = 0x004; // controller type
    static const int ICDIIDR    = 0x008; // implementer id
    static const int ICDISER_ST = 0x100; // interrupt set enable
    static const int ICDISER_ED = 0x17c;
    static const int ICDICER_ST = 0x180; // interrupt clear enable
    static const int ICDICER_ED = 0x1fc;
    static const int ICDISPR_ST = 0x200; // set pending interrupt
    static const int ICDISPR_ED = 0x27c;
    static const int ICDICPR_ST = 0x280; // clear pending interrupt
    static const int ICDICPR_ED = 0x2fc;
    static const int ICDABR_ST  = 0x300; // active bit registers
    static const int ICDABR_ED  = 0x37c;
    static const int ICDIPR_ST  = 0x400; // interrupt priority registers
    static const int ICDIPR_ED  = 0x7f8;
    static const int ICDIPTR_ST = 0x800; // processor target registers
    static const int ICDIPTR_ED = 0xbf8;
    static const int ICDICFR_ST = 0xc00; // interrupt config registers
    static const int ICDICFR_ED = 0xcfc;
    static const int ICDSGIR    = 0xf00; // software generated interrupt
    static const int DIST_SIZE  = 0xfff;

    // cpu memory addressesa
    static const int ICCICR  = 0x00; // CPU control register
    static const int ICCPMR  = 0x04; // Interrupt priority mask
    static const int ICCBPR  = 0x08; // binary point register
    static const int ICCIAR  = 0x0C; // interrupt ack register
    static const int ICCEOIR = 0x10; // end of interrupt
    static const int ICCRPR  = 0x14; // runing priority
    static const int ICCHPIR = 0x18; // highest pending interrupt
    static const int ICCABPR = 0x1c; // aliased binary point
    static const int ICCIIDR = 0xfc; // cpu interface id register
    static const int CPU_SIZE  = 0xff;

    static const int SGI_MAX = 16;  // Number of Software Gen Interrupts
    static const int PPI_MAX = 16;  // Number of Private Peripheral Interrupts

    /** Mask off SGI's when setting/clearing pending bits */
    static const int SGI_MASK = 0xFFFF0000;

    /** Mask for bits that config N:N mode in ICDICFR's */
    static const int NN_CONFIG_MASK = 0x55555555;

    static const int CPU_MAX = 8;   // Max number of supported CPU interfaces
    static const int SPURIOUS_INT = 1023;
    static const int INT_BITS_MAX = 32;
    static const int INT_LINES_MAX = 1020;

    BitUnion32(SWI)
        Bitfield<3,0> sgi_id;
        Bitfield<23,16> cpu_list;
        Bitfield<25,24> list_type;
    EndBitUnion(SWI)

    BitUnion32(IAR)
        Bitfield<9,0> ack_id;
        Bitfield<12,10> cpu_id;
    EndBitUnion(IAR)

    /** Distributor address GIC listens at */
    Addr distAddr;

    /** CPU address GIC listens at */
    /** @todo is this one per cpu? */
    Addr cpuAddr;

    /** Latency for a distributor operation */
    Tick distPioDelay;

    /** Latency for a cpu operation */
    Tick cpuPioDelay;

    /** Latency for a interrupt to get to CPU */
    Tick intLatency;

    /** Gic enabled */
    bool enabled;

    /** Number of itLines enabled */
    uint32_t itLines;

    uint32_t itLinesLog2;

    /** interrupt enable bits for all possible 1020 interupts.
     * one bit per interrupt, 32 bit per word = 32 words */
    uint32_t intEnabled[INT_BITS_MAX];

    /** interrupt pending bits for all possible 1020 interupts.
     * one bit per interrupt, 32 bit per word = 32 words */
    uint32_t pendingInt[INT_BITS_MAX];

    /** interrupt active bits for all possible 1020 interupts.
     * one bit per interrupt, 32 bit per word = 32 words */
    uint32_t activeInt[INT_BITS_MAX];

    /** read only running priroity register, 1 per cpu*/
    uint32_t iccrpr[CPU_MAX];

    /** an 8 bit priority (lower is higher priority) for each
     * of the 1020 possible supported interrupts.
     */
    uint8_t intPriority[INT_LINES_MAX];

    /** an 8 bit cpu target id for each shared peripheral interrupt
     * of the 1020 possible supported interrupts.
     */
    uint8_t cpuTarget[INT_LINES_MAX];

    /** 2 bit per interrupt signaling if it's level or edge sensitive
     * and if it is 1:N or N:N */
    uint32_t intConfig[INT_BITS_MAX*2];

    /** CPU enabled */
    bool cpuEnabled[CPU_MAX];

    /** CPU priority */
    uint8_t cpuPriority[CPU_MAX];

    /** Binary point registers */
    uint8_t cpuBpr[CPU_MAX];

    /** highest interrupt that is interrupting CPU */
    uint32_t cpuHighestInt[CPU_MAX];

    /** One bit per cpu per software interrupt that is pending for each possible
     * sgi source. Indexed by SGI number. Each byte in generating cpu id and
     * bits in position is destination id. e.g. 0x4 = CPU 0 generated interrupt
     * for CPU 2. */
    uint64_t cpuSgiPending[SGI_MAX];
    uint64_t cpuSgiActive[SGI_MAX];

    /** One bit per private peripheral interrupt. Only upper 16 bits
     * will be used since PPI interrupts are numberred from 16 to 32 */
    uint32_t cpuPpiPending[CPU_MAX];
    uint32_t cpuPpiActive[CPU_MAX];

    /** Banked interrupt prioirty registers for SGIs and PPIs */
    uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX];

    /** IRQ Enable Used for debug */
    bool irqEnable;

    /** software generated interrupt
     * @param data data to decode that indicates which cpus to interrupt
     */
    void softInt(int ctx_id, SWI swi);

    /** See if some processor interrupt flags need to be enabled/disabled
     * @param hint which set of interrupts needs to be checked
     */
    void updateIntState(int hint);

    /** Update the register that records priority of the highest priority
     *  active interrupt*/
    void updateRunPri();

    /** generate a bit mask to check cpuSgi for an interrupt. */
    uint64_t genSwiMask(int cpu);

    int intNumToWord(int num) const { return num >> 5; }
    int intNumToBit(int num) const { return num % 32; }

    /** Post an interrupt to a CPU
     */
    void postInt(uint32_t cpu, Tick when);

    /** Event definition to post interrupt to CPU after a delay
    */
    class PostIntEvent : public Event
    {
      private:
        uint32_t cpu;
        Platform *platform;
      public:
        PostIntEvent( uint32_t c, Platform* p)
            : cpu(c), platform(p)
        { }
        void process() { platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);}
        const char *description() const { return "Post Interrupt to CPU"; }
    };
    PostIntEvent *postIntEvent[CPU_MAX];

  public:
    typedef Pl390Params Params;
    const Params *
    params() const
    {
        return dynamic_cast<const Params *>(_params);
    }
    Pl390(const Params *p);

    /** @{ */
    /** Return the address ranges used by the Gic
     * This is the distributor address + all cpu addresses
     */
    virtual AddrRangeList getAddrRanges() const;

    /** A PIO read to the device, immediately split up into
     * readDistributor() or readCpu()
     */
    virtual Tick read(PacketPtr pkt);

    /** A PIO read to the device, immediately split up into
     * writeDistributor() or writeCpu()
     */
    virtual Tick write(PacketPtr pkt);
    /** @} */

    /** @{ */
    /** Post an interrupt from a device that is connected to the Gic.
     * Depending on the configuration, the gic will pass this interrupt
     * on through to a CPU.
     * @param number number of interrupt to send */
    void sendInt(uint32_t number);

    /** Interface call for private peripheral interrupts  */
    void sendPPInt(uint32_t num, uint32_t cpu);

    /** Clear an interrupt from a device that is connected to the Gic
     * Depending on the configuration, the gic may de-assert it's cpu line
     * @param number number of interrupt to send */
    void clearInt(uint32_t number);
    /** @} */

    /** @{ */
    /* Various functions fer testing and debugging */
    void driveSPI(uint32_t spi);
    void driveLegIRQ(bool state);
    void driveLegFIQ(bool state);
    void driveIrqEn(bool state);
    /** @} */

    virtual void serialize(std::ostream &os);
    virtual void unserialize(Checkpoint *cp, const std::string &section);

  protected:
    /** Handle a read to the distributor poriton of the GIC
     * @param pkt packet to respond to
     */
    Tick readDistributor(PacketPtr pkt);

    /** Handle a read to the cpu poriton of the GIC
     * @param pkt packet to respond to
     */
    Tick readCpu(PacketPtr pkt);

    /** Handle a write to the distributor poriton of the GIC
     * @param pkt packet to respond to
     */
    Tick writeDistributor(PacketPtr pkt);

    /** Handle a write to the cpu poriton of the GIC
     * @param pkt packet to respond to
     */
    Tick writeCpu(PacketPtr pkt);
};

#endif //__DEV_ARM_GIC_H__
<|endoftext|>