<commit_before>//===-- CompilerInvocation.cpp - CompilerInvocation methods ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Frontend/Frontend.h"

#include "swift/Driver/Options.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Path.h"

using namespace swift;
using namespace swift::driver;
using namespace llvm::opt;

swift::CompilerInvocation::CompilerInvocation() {
  TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
}

void CompilerInvocation::setMainExecutablePath(StringRef Path) {
  llvm::SmallString<128> LibPath(Path);
  llvm::sys::path::remove_filename(LibPath); // Remove /swift
  llvm::sys::path::remove_filename(LibPath); // Remove /bin
  llvm::sys::path::append(LibPath, "lib", "swift");
  setRuntimeIncludePath(LibPath.str());
}

static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
                              DiagnosticEngine &Diags) {
  using namespace options;

  if (const Arg *A = Args.getLastArg(OPT_o)) {
    Opts.OutputFilename = A->getValue();
  }

  if (const Arg *A = Args.getLastArg(OPT_serialize_diagnostics)) {
    Opts.SerializedDiagnosticsPath = A->getValue();
  }

  if (Args.hasArg(OPT_emit_verbose_sil)) {
    Opts.EmitVerboseSIL = true;
  }

  if (Args.hasArg(OPT_delayed_function_body_parsing)) {
    Opts.DelayedFunctionBodyParsing = true;
  }

  if (Args.hasArg(OPT_print_stats)) {
    Opts.PrintStats = true;
  }

  if (const Arg *A = Args.getLastArg(OPT_help, OPT_help_hidden)) {
    if (A->getOption().matches(OPT_help)) {
      Opts.PrintHelp = true;
    } else if (A->getOption().matches(OPT_help_hidden)) {
      Opts.PrintHelpHidden = true;
    } else {
      llvm_unreachable("Unknown help option parsed");
    }
  }

  for (const Arg *A : make_range(Args.filtered_begin(OPT_INPUT),
                                 Args.filtered_end())) {
    Opts.InputFilenames.push_back(A->getValue());
  }

  if (const Arg *A = Args.getLastArg(OPT_module_source_list)) {
    Opts.ModuleSourceListPath = A->getValue();
  }

  if (const Arg *A = Args.getLastArg(OPT__DASH_DASH)) {
    for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
      Opts.ImmediateArgv.push_back(A->getValue(i));
    }
  }

  // Determine what the user has asked the frontend to do.
  FrontendOptions::ActionType Action;
  if (const Arg *A = Args.getLastArg(OPT_modes_Group)) {
    Option Opt = A->getOption();
    if (Opt.matches(OPT_c)) {
      Action = FrontendOptions::EmitObject;
    } else if (Opt.matches(OPT_S)) {
      Action = FrontendOptions::EmitAssembly;
    } else if (Opt.matches(OPT_emit_ir)) {
      Action = FrontendOptions::EmitIR;
    } else if (Opt.matches(OPT_emit_bc)) {
      Action = FrontendOptions::EmitBC;
    } else if (Opt.matches(OPT_emit_sil)) {
      Action = FrontendOptions::EmitSIL;
    } else if (Opt.matches(OPT_emit_silgen)) {
      Action = FrontendOptions::EmitSILGen;
    } else if (Opt.matches(OPT_parse)) {
      Action = FrontendOptions::Parse;
    } else if (Opt.matches(OPT_dump_parse)) {
      Action = FrontendOptions::DumpParse;

      // -dump-parse explicitly disables type-checking
      Opts.ParseOnly = true;
    } else if (Opt.matches(OPT_dump_ast)) {
      Action = FrontendOptions::DumpAST;
    } else if (Opt.matches(OPT_print_ast)) {
      Action = FrontendOptions::PrintAST;
    } else if (Opt.matches(OPT_repl)) {
      Action = FrontendOptions::REPL;
    } else if (Opt.matches(OPT_i)) {
      Action = FrontendOptions::Immediate;
    } else {
      llvm_unreachable("Unhandled mode option");
    }
  } else {
    // We don't have a mode, so determine a default.
    // TODO: add check for EmitModuleOnly, once we support -emit-module.
    if (Opts.InputFilenames.empty()) {
      // We don't have any input files, so default to the REPL.
      Action = FrontendOptions::REPL;
    } else {
      // In the absence of any other mode indicators, parse the inputs.
      Action = FrontendOptions::Parse;
    }
  }
  Opts.RequestedAction = Action;

  {
    const Arg *A = Args.getLastArg(OPT_module_name);
    std::string ModuleName;
    if (A) {
      ModuleName = A->getValue();
    } else {
      // The user did not specify a module name, so determine a default fallback
      // based on other options.
      if (Opts.RequestedAction == FrontendOptions::REPL) {
        // Default to a module named "REPL" if we're in REPL mode.
        ModuleName = "REPL";
      } else {
        StringRef OutputFilename(Opts.OutputFilename);
        if (OutputFilename.empty() || OutputFilename == "-") {
          ModuleName = Opts.InputFilenames[0];
        } else {
          ModuleName = OutputFilename;
        }

        ModuleName = llvm::sys::path::stem(ModuleName);
      }
    }

    if (!Lexer::isIdentifier(ModuleName)) {
      if (!Opts.actionHasOutput()) {
        ModuleName = "main";
      } else {
        Diags.diagnose(SourceLoc(), diag::bad_module_name,
                       ModuleName, A == nullptr);
        ModuleName = "__bad__";
      }
    }

    Opts.ModuleName = ModuleName;
  }

  return false;
}

static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
                          DiagnosticEngine &Diags) {
  using namespace options;

  if (Args.hasArg(OPT_use_malloc)) {
    Opts.UseMalloc = true;
  }

  if (Args.hasArg(OPT_debug_constraints)) {
    Opts.DebugConstraintSolver = true;
  }

  if (const Arg *A = Args.getLastArg(OPT_debug_constraints_attempt)) {
    unsigned attempt;
    if (StringRef(A->getValue()).getAsInteger(10, attempt)) {
      Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
                     A->getAsString(Args), A->getValue());
      return true;
    }

    Opts.DebugConstraintSolverAttempt = attempt;
  }

  if (Args.hasArg(OPT_emit_sil_protocol_witness_tables)) {
    Opts.EmitSILProtocolWitnessTables = true;
  }

  return false;
}

static bool ParseClangImporterArgs(ClangImporterOptions &Opts, ArgList &Args,
                                   DiagnosticEngine &Diags) {
  using namespace options;

  if (const Arg *A = Args.getLastArg(OPT_module_cache_path)) {
    Opts.ModuleCachePath = A->getValue();
  }

  for (const Arg *A : make_range(Args.filtered_begin(OPT_Xcc),
                                 Args.filtered_end())) {
    Opts.ExtraArgs.push_back(A->getValue());
  }

  return false;
}

static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args,
                                DiagnosticEngine &Diags) {
  using namespace options;

  for (const Arg *A : make_range(Args.filtered_begin(OPT_I),
                                 Args.filtered_end())) {
    Opts.ImportSearchPaths.push_back(A->getValue());
  }

  for (const Arg *A : make_range(Args.filtered_begin(OPT_F),
                                 Args.filtered_end())) {
    Opts.FrameworkSearchPaths.push_back(A->getValue());
  }

  if (const Arg *A = Args.getLastArg(OPT_sdk)) {
    Opts.SDKPath = A->getValue();
  }

  // Opts.RuntimeIncludePath is set by calls to
  // CompilerInvocation::setRuntimeIncludePath().
  // TODO: improve the handling of RuntimeIncludePath.

  return false;
}

static bool ParseTargetArgs(TargetOptions &Opts, ArgList &Args,
                            DiagnosticEngine &Diags) {
  using namespace options;

  if (const Arg *A = Args.getLastArg(OPT_target)) {
    Opts.Triple = llvm::Triple::normalize(A->getValue());
  }

  return false;
}

static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
                                DiagnosticEngine &Diags) {
  using namespace options;

  if (Args.hasArg(OPT_verify)) {
    Opts.VerifyDiagnostics = true;
  }

  if (Args.hasArg(OPT_disable_diagnostic_passes)) {
    Opts.SkipDiagnosticPasses = true;
  }

  return false;
}

bool CompilerInvocation::parseArgs(ArrayRef<const char *> Args,
                                   DiagnosticEngine &Diags) {
  using namespace driver::options;

  if (Args.empty())
    return false;

  // Parse frontend command line options using Swift's option table.
  std::unique_ptr<llvm::opt::InputArgList> ParsedArgs;
  std::unique_ptr<llvm::opt::OptTable> Table = createDriverOptTable();
  unsigned MissingIndex;
  unsigned MissingCount;
  ParsedArgs.reset(
      Table->ParseArgs(Args.begin(), Args.end(), MissingIndex, MissingCount,
                       driver::options::FrontendOption));
  if (MissingCount) {
    Diags.diagnose(SourceLoc(), diag::error_missing_arg_value,
                   ParsedArgs->getArgString(MissingIndex), MissingCount);
    return true;
  }

  if (ParsedArgs->hasArg(OPT_UNKNOWN)) {
    for (const Arg *A : make_range(ParsedArgs->filtered_begin(OPT_UNKNOWN),
                                   ParsedArgs->filtered_end())) {
      Diags.diagnose(SourceLoc(), diag::error_unknown_arg,
                     A->getAsString(*ParsedArgs));
    }
    return true;
  }

  if (ParseFrontendArgs(FrontendOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseLangArgs(LangOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseClangImporterArgs(ClangImporterOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseSearchPathArgs(SearchPathOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseTargetArgs(TargetOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseDiagnosticArgs(DiagnosticOpts, *ParsedArgs, Diags)) {
    return true;
  }

  for (auto InputArg : *ParsedArgs) {
    switch (InputArg->getOption().getID()) {
    case OPT_parse_as_library:
      setInputKind(SourceFileKind::Library);
      break;

    case OPT_parse_stdlib:
      setParseStdlib();
      break;

    case OPT_l:
      addLinkLibrary(InputArg->getValue(), LibraryKind::Library);
      break;

    case OPT_framework:
      addLinkLibrary(InputArg->getValue(), LibraryKind::Framework);
      break;
    }
  }

  return false;
}
<commit_msg>[frontend] Use "main" as a fallback module name if there's only one input file and it's kind is SourceFileKind::Main.<commit_after>//===-- CompilerInvocation.cpp - CompilerInvocation methods ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Frontend/Frontend.h"

#include "swift/Driver/Options.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Path.h"

using namespace swift;
using namespace swift::driver;
using namespace llvm::opt;

swift::CompilerInvocation::CompilerInvocation() {
  TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
}

void CompilerInvocation::setMainExecutablePath(StringRef Path) {
  llvm::SmallString<128> LibPath(Path);
  llvm::sys::path::remove_filename(LibPath); // Remove /swift
  llvm::sys::path::remove_filename(LibPath); // Remove /bin
  llvm::sys::path::append(LibPath, "lib", "swift");
  setRuntimeIncludePath(LibPath.str());
}

// TODO: remove InputKind param once we support storing it in FrontendOptions
static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
                              DiagnosticEngine &Diags, SourceFileKind InputKind)
{
  using namespace options;

  if (const Arg *A = Args.getLastArg(OPT_o)) {
    Opts.OutputFilename = A->getValue();
  }

  if (const Arg *A = Args.getLastArg(OPT_serialize_diagnostics)) {
    Opts.SerializedDiagnosticsPath = A->getValue();
  }

  if (Args.hasArg(OPT_emit_verbose_sil)) {
    Opts.EmitVerboseSIL = true;
  }

  if (Args.hasArg(OPT_delayed_function_body_parsing)) {
    Opts.DelayedFunctionBodyParsing = true;
  }

  if (Args.hasArg(OPT_print_stats)) {
    Opts.PrintStats = true;
  }

  if (const Arg *A = Args.getLastArg(OPT_help, OPT_help_hidden)) {
    if (A->getOption().matches(OPT_help)) {
      Opts.PrintHelp = true;
    } else if (A->getOption().matches(OPT_help_hidden)) {
      Opts.PrintHelpHidden = true;
    } else {
      llvm_unreachable("Unknown help option parsed");
    }
  }

  for (const Arg *A : make_range(Args.filtered_begin(OPT_INPUT),
                                 Args.filtered_end())) {
    Opts.InputFilenames.push_back(A->getValue());
  }

  if (const Arg *A = Args.getLastArg(OPT_module_source_list)) {
    Opts.ModuleSourceListPath = A->getValue();
  }

  if (const Arg *A = Args.getLastArg(OPT__DASH_DASH)) {
    for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
      Opts.ImmediateArgv.push_back(A->getValue(i));
    }
  }

  // Determine what the user has asked the frontend to do.
  FrontendOptions::ActionType Action;
  if (const Arg *A = Args.getLastArg(OPT_modes_Group)) {
    Option Opt = A->getOption();
    if (Opt.matches(OPT_c)) {
      Action = FrontendOptions::EmitObject;
    } else if (Opt.matches(OPT_S)) {
      Action = FrontendOptions::EmitAssembly;
    } else if (Opt.matches(OPT_emit_ir)) {
      Action = FrontendOptions::EmitIR;
    } else if (Opt.matches(OPT_emit_bc)) {
      Action = FrontendOptions::EmitBC;
    } else if (Opt.matches(OPT_emit_sil)) {
      Action = FrontendOptions::EmitSIL;
    } else if (Opt.matches(OPT_emit_silgen)) {
      Action = FrontendOptions::EmitSILGen;
    } else if (Opt.matches(OPT_parse)) {
      Action = FrontendOptions::Parse;
    } else if (Opt.matches(OPT_dump_parse)) {
      Action = FrontendOptions::DumpParse;

      // -dump-parse explicitly disables type-checking
      Opts.ParseOnly = true;
    } else if (Opt.matches(OPT_dump_ast)) {
      Action = FrontendOptions::DumpAST;
    } else if (Opt.matches(OPT_print_ast)) {
      Action = FrontendOptions::PrintAST;
    } else if (Opt.matches(OPT_repl)) {
      Action = FrontendOptions::REPL;
    } else if (Opt.matches(OPT_i)) {
      Action = FrontendOptions::Immediate;
    } else {
      llvm_unreachable("Unhandled mode option");
    }
  } else {
    // We don't have a mode, so determine a default.
    // TODO: add check for EmitModuleOnly, once we support -emit-module.
    if (Opts.InputFilenames.empty()) {
      // We don't have any input files, so default to the REPL.
      Action = FrontendOptions::REPL;
    } else {
      // In the absence of any other mode indicators, parse the inputs.
      Action = FrontendOptions::Parse;
    }
  }
  Opts.RequestedAction = Action;

  {
    const Arg *A = Args.getLastArg(OPT_module_name);
    std::string ModuleName;
    if (A) {
      ModuleName = A->getValue();
    } else {
      // The user did not specify a module name, so determine a default fallback
      // based on other options.
      if (Opts.RequestedAction == FrontendOptions::REPL) {
        // Default to a module named "REPL" if we're in REPL mode.
        ModuleName = "REPL";
      } else {
        StringRef OutputFilename(Opts.OutputFilename);
        if (OutputFilename.empty() || OutputFilename == "-") {
          ModuleName = Opts.InputFilenames[0];
        } else {
          ModuleName = OutputFilename;
        }

        ModuleName = llvm::sys::path::stem(ModuleName);
      }
    }

    if (!Lexer::isIdentifier(ModuleName)) {
      if (!Opts.actionHasOutput() ||
          (InputKind == SourceFileKind::Main &&
           Opts.InputFilenames.size() == 1)) {
        ModuleName = "main";
      } else {
        Diags.diagnose(SourceLoc(), diag::bad_module_name,
                       ModuleName, A == nullptr);
        ModuleName = "__bad__";
      }
    }

    Opts.ModuleName = ModuleName;
  }

  return false;
}

static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
                          DiagnosticEngine &Diags) {
  using namespace options;

  if (Args.hasArg(OPT_use_malloc)) {
    Opts.UseMalloc = true;
  }

  if (Args.hasArg(OPT_debug_constraints)) {
    Opts.DebugConstraintSolver = true;
  }

  if (const Arg *A = Args.getLastArg(OPT_debug_constraints_attempt)) {
    unsigned attempt;
    if (StringRef(A->getValue()).getAsInteger(10, attempt)) {
      Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
                     A->getAsString(Args), A->getValue());
      return true;
    }

    Opts.DebugConstraintSolverAttempt = attempt;
  }

  if (Args.hasArg(OPT_emit_sil_protocol_witness_tables)) {
    Opts.EmitSILProtocolWitnessTables = true;
  }

  return false;
}

static bool ParseClangImporterArgs(ClangImporterOptions &Opts, ArgList &Args,
                                   DiagnosticEngine &Diags) {
  using namespace options;

  if (const Arg *A = Args.getLastArg(OPT_module_cache_path)) {
    Opts.ModuleCachePath = A->getValue();
  }

  for (const Arg *A : make_range(Args.filtered_begin(OPT_Xcc),
                                 Args.filtered_end())) {
    Opts.ExtraArgs.push_back(A->getValue());
  }

  return false;
}

static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args,
                                DiagnosticEngine &Diags) {
  using namespace options;

  for (const Arg *A : make_range(Args.filtered_begin(OPT_I),
                                 Args.filtered_end())) {
    Opts.ImportSearchPaths.push_back(A->getValue());
  }

  for (const Arg *A : make_range(Args.filtered_begin(OPT_F),
                                 Args.filtered_end())) {
    Opts.FrameworkSearchPaths.push_back(A->getValue());
  }

  if (const Arg *A = Args.getLastArg(OPT_sdk)) {
    Opts.SDKPath = A->getValue();
  }

  // Opts.RuntimeIncludePath is set by calls to
  // CompilerInvocation::setRuntimeIncludePath().
  // TODO: improve the handling of RuntimeIncludePath.

  return false;
}

static bool ParseTargetArgs(TargetOptions &Opts, ArgList &Args,
                            DiagnosticEngine &Diags) {
  using namespace options;

  if (const Arg *A = Args.getLastArg(OPT_target)) {
    Opts.Triple = llvm::Triple::normalize(A->getValue());
  }

  return false;
}

static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
                                DiagnosticEngine &Diags) {
  using namespace options;

  if (Args.hasArg(OPT_verify)) {
    Opts.VerifyDiagnostics = true;
  }

  if (Args.hasArg(OPT_disable_diagnostic_passes)) {
    Opts.SkipDiagnosticPasses = true;
  }

  return false;
}

bool CompilerInvocation::parseArgs(ArrayRef<const char *> Args,
                                   DiagnosticEngine &Diags) {
  using namespace driver::options;

  if (Args.empty())
    return false;

  // Parse frontend command line options using Swift's option table.
  std::unique_ptr<llvm::opt::InputArgList> ParsedArgs;
  std::unique_ptr<llvm::opt::OptTable> Table = createDriverOptTable();
  unsigned MissingIndex;
  unsigned MissingCount;
  ParsedArgs.reset(
      Table->ParseArgs(Args.begin(), Args.end(), MissingIndex, MissingCount,
                       driver::options::FrontendOption));
  if (MissingCount) {
    Diags.diagnose(SourceLoc(), diag::error_missing_arg_value,
                   ParsedArgs->getArgString(MissingIndex), MissingCount);
    return true;
  }

  if (ParsedArgs->hasArg(OPT_UNKNOWN)) {
    for (const Arg *A : make_range(ParsedArgs->filtered_begin(OPT_UNKNOWN),
                                   ParsedArgs->filtered_end())) {
      Diags.diagnose(SourceLoc(), diag::error_unknown_arg,
                     A->getAsString(*ParsedArgs));
    }
    return true;
  }

  for (auto InputArg : *ParsedArgs) {
    switch (InputArg->getOption().getID()) {
      case OPT_parse_as_library:
        setInputKind(SourceFileKind::Library);
        break;

      case OPT_parse_stdlib:
        setParseStdlib();
        break;

      case OPT_l:
        addLinkLibrary(InputArg->getValue(), LibraryKind::Library);
        break;

      case OPT_framework:
        addLinkLibrary(InputArg->getValue(), LibraryKind::Framework);
        break;
    }
  }

  if (ParseFrontendArgs(FrontendOpts, *ParsedArgs, Diags, InputKind)) {
    return true;
  }

  if (ParseLangArgs(LangOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseClangImporterArgs(ClangImporterOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseSearchPathArgs(SearchPathOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseTargetArgs(TargetOpts, *ParsedArgs, Diags)) {
    return true;
  }

  if (ParseDiagnosticArgs(DiagnosticOpts, *ParsedArgs, Diags)) {
    return true;
  }

  return false;
}
<|endoftext|>


<commit_before>//=-- InstrProfWriter.cpp - Instrumented profiling writer -------------------=//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing profiling data for clang's
// instrumentation based PGO and coverage.
//
//===----------------------------------------------------------------------===//

#include "llvm/ProfileData/InstrProfWriter.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/OnDiskHashTable.h"
#include <tuple>

using namespace llvm;

namespace {
static support::endianness ValueProfDataEndianness = support::little;

class InstrProfRecordTrait {
public:
  typedef StringRef key_type;
  typedef StringRef key_type_ref;

  typedef const InstrProfWriter::ProfilingData *const data_type;
  typedef const InstrProfWriter::ProfilingData *const data_type_ref;

  typedef uint64_t hash_value_type;
  typedef uint64_t offset_type;

  static hash_value_type ComputeHash(key_type_ref K) {
    return IndexedInstrProf::ComputeHash(K);
  }

  static std::pair<offset_type, offset_type>
  EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) {
    using namespace llvm::support;
    endian::Writer<little> LE(Out);

    offset_type N = K.size();
    LE.write<offset_type>(N);

    offset_type M = 0;
    for (const auto &ProfileData : *V) {
      const InstrProfRecord &ProfRecord = ProfileData.second;
      M += sizeof(uint64_t); // The function hash
      M += sizeof(uint64_t); // The size of the Counts vector
      M += ProfRecord.Counts.size() * sizeof(uint64_t);

      // Value data
      M += ValueProfData::getSize(ProfileData.second);
    }
    LE.write<offset_type>(M);

    return std::make_pair(N, M);
  }

  static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N){
    Out.write(K.data(), N);
  }

  static void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V,
                       offset_type) {
    using namespace llvm::support;
    endian::Writer<little> LE(Out);
    for (const auto &ProfileData : *V) {
      const InstrProfRecord &ProfRecord = ProfileData.second;

      LE.write<uint64_t>(ProfileData.first); // Function hash
      LE.write<uint64_t>(ProfRecord.Counts.size());
      for (uint64_t I : ProfRecord.Counts)
        LE.write<uint64_t>(I);

      // Write value data
      std::unique_ptr<ValueProfData> VDataPtr =
          ValueProfData::serializeFrom(ProfileData.second);
      uint32_t S = VDataPtr->getSize();
      VDataPtr->swapBytesFromHost(ValueProfDataEndianness);
      Out.write((const char *)VDataPtr.get(), S);
    }
  }
};
}

// Internal interface for testing purpose only.
void InstrProfWriter::setValueProfDataEndianness(
    support::endianness Endianness) {
  ValueProfDataEndianness = Endianness;
}

std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I,
                                           uint64_t Weight) {
  auto &ProfileDataMap = FunctionData[I.Name];

  bool NewFunc;
  ProfilingData::iterator Where;
  std::tie(Where, NewFunc) =
      ProfileDataMap.insert(std::make_pair(I.Hash, InstrProfRecord()));
  InstrProfRecord &Dest = Where->second;

  instrprof_error Result;
  if (NewFunc) {
    // We've never seen a function with this name and hash, add it.
    Dest = std::move(I);
    Result = instrprof_error::success;
    if (Weight > 1) {
      for (auto &Count : Dest.Counts) {
        bool Overflowed;
        Count = SaturatingMultiply(Count, Weight, &Overflowed);
        if (Overflowed && Result == instrprof_error::success) {
          Result = instrprof_error::counter_overflow;
        }
      }
    }
  } else {
    // We're updating a function we've seen before.
    Result = Dest.merge(I, Weight);
  }

  // We keep track of the max function count as we go for simplicity.
  // Update this statistic no matter the result of the merge.
  if (Dest.Counts[0] > MaxFunctionCount)
    MaxFunctionCount = Dest.Counts[0];

  return Result;
}

std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
  OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;

  // Populate the hash table generator.
  for (const auto &I : FunctionData)
    Generator.insert(I.getKey(), &I.getValue());

  using namespace llvm::support;
  endian::Writer<little> LE(OS);

  // Write the header.
  IndexedInstrProf::Header Header;
  Header.Magic = IndexedInstrProf::Magic;
  Header.Version = IndexedInstrProf::Version;
  Header.MaxFunctionCount = MaxFunctionCount;
  Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType);
  Header.HashOffset = 0;
  int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t);

  // Only write out all the fields execpt 'HashOffset'. We need
  // to remember the offset of that field to allow back patching
  // later.
  for (int I = 0; I < N - 1; I++)
    LE.write<uint64_t>(reinterpret_cast<uint64_t *>(&Header)[I]);

  // Save a space to write the hash table start location.
  uint64_t HashTableStartLoc = OS.tell();
  // Reserve the space for HashOffset field.
  LE.write<uint64_t>(0);
  // Write the hash table.
  uint64_t HashTableStart = Generator.Emit(OS);

  return std::make_pair(HashTableStartLoc, HashTableStart);
}

void InstrProfWriter::write(raw_fd_ostream &OS) {
  // Write the hash table.
  auto TableStart = writeImpl(OS);

  // Go back and fill in the hash table start.
  using namespace support;
  OS.seek(TableStart.first);
  // Now patch the HashOffset field previously reserved.
  endian::Writer<little>(OS).write<uint64_t>(TableStart.second);
}

static const char *ValueProfKindStr[] = {
#define VALUE_PROF_KIND(Enumerator, Value) #Enumerator,
#include "llvm/ProfileData/InstrProfData.inc"
};

void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func,
                                        InstrProfSymtab &Symtab,
                                        raw_fd_ostream &OS) {
  OS << Func.Name << "\n";
  OS << "# Func Hash:\n" << Func.Hash << "\n";
  OS << "# Num Counters:\n" << Func.Counts.size() << "\n";
  OS << "# Counter Values:\n";
  for (uint64_t Count : Func.Counts)
    OS << Count << "\n";

  uint32_t NumValueKinds = Func.getNumValueKinds();
  if (!NumValueKinds) {
    OS << "\n";
    return;
  }

  OS << "# Num Value Kinds:\n" << Func.getNumValueKinds() << "\n";
  for (uint32_t VK = 0; VK < IPVK_Last + 1; VK++) {
    uint32_t NS = Func.getNumValueSites(VK);
    if (!NS)
      continue;
    OS << "# ValueKind = " << ValueProfKindStr[VK] << ":\n" << VK << "\n";
    OS << "# NumValueSites:\n" << NS << "\n";
    for (uint32_t S = 0; S < NS; S++) {
      uint32_t ND = Func.getNumValueDataForSite(VK, S);
      OS << ND << "\n";
      std::unique_ptr<InstrProfValueData[]> VD = Func.getValueForSite(VK, S);
      for (uint32_t I = 0; I < ND; I++) {
        if (VK == IPVK_IndirectCallTarget)
          OS << Symtab.getFuncName(VD[I].Value) << ":" << VD[I].Count << "\n";
        else
          OS << VD[I].Value << ":" << VD[I].Count << "\n";
      }
    }
  }

  OS << "\n";
}

void InstrProfWriter::writeText(raw_fd_ostream &OS) {
  InstrProfSymtab Symtab;
  for (const auto &I : FunctionData)
    Symtab.addFuncName(I.getKey());
  Symtab.finalizeSymtab();

  for (const auto &I : FunctionData)
    for (const auto &Func : I.getValue())
      writeRecordInText(Func.second, Symtab, OS);
}

std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() {
  std::string Data;
  llvm::raw_string_ostream OS(Data);
  // Write the hash table.
  auto TableStart = writeImpl(OS);
  OS.flush();

  // Go back and fill in the hash table start.
  using namespace support;
  uint64_t Bytes = endian::byte_swap<uint64_t, little>(TableStart.second);
  Data.replace(TableStart.first, sizeof(uint64_t), (const char *)&Bytes,
               sizeof(uint64_t));

  // Return this in an aligned memory buffer.
  return MemoryBuffer::getMemBufferCopy(Data);
}
<commit_msg>Fix a latent UAF bug in profwriter<commit_after>//=-- InstrProfWriter.cpp - Instrumented profiling writer -------------------=//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing profiling data for clang's
// instrumentation based PGO and coverage.
//
//===----------------------------------------------------------------------===//

#include "llvm/ProfileData/InstrProfWriter.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/OnDiskHashTable.h"
#include <tuple>

using namespace llvm;

namespace {
static support::endianness ValueProfDataEndianness = support::little;

class InstrProfRecordTrait {
public:
  typedef StringRef key_type;
  typedef StringRef key_type_ref;

  typedef const InstrProfWriter::ProfilingData *const data_type;
  typedef const InstrProfWriter::ProfilingData *const data_type_ref;

  typedef uint64_t hash_value_type;
  typedef uint64_t offset_type;

  static hash_value_type ComputeHash(key_type_ref K) {
    return IndexedInstrProf::ComputeHash(K);
  }

  static std::pair<offset_type, offset_type>
  EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) {
    using namespace llvm::support;
    endian::Writer<little> LE(Out);

    offset_type N = K.size();
    LE.write<offset_type>(N);

    offset_type M = 0;
    for (const auto &ProfileData : *V) {
      const InstrProfRecord &ProfRecord = ProfileData.second;
      M += sizeof(uint64_t); // The function hash
      M += sizeof(uint64_t); // The size of the Counts vector
      M += ProfRecord.Counts.size() * sizeof(uint64_t);

      // Value data
      M += ValueProfData::getSize(ProfileData.second);
    }
    LE.write<offset_type>(M);

    return std::make_pair(N, M);
  }

  static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N){
    Out.write(K.data(), N);
  }

  static void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V,
                       offset_type) {
    using namespace llvm::support;
    endian::Writer<little> LE(Out);
    for (const auto &ProfileData : *V) {
      const InstrProfRecord &ProfRecord = ProfileData.second;

      LE.write<uint64_t>(ProfileData.first); // Function hash
      LE.write<uint64_t>(ProfRecord.Counts.size());
      for (uint64_t I : ProfRecord.Counts)
        LE.write<uint64_t>(I);

      // Write value data
      std::unique_ptr<ValueProfData> VDataPtr =
          ValueProfData::serializeFrom(ProfileData.second);
      uint32_t S = VDataPtr->getSize();
      VDataPtr->swapBytesFromHost(ValueProfDataEndianness);
      Out.write((const char *)VDataPtr.get(), S);
    }
  }
};
}

// Internal interface for testing purpose only.
void InstrProfWriter::setValueProfDataEndianness(
    support::endianness Endianness) {
  ValueProfDataEndianness = Endianness;
}

std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I,
                                           uint64_t Weight) {
  auto &ProfileDataMap = FunctionData[I.Name];

  bool NewFunc;
  ProfilingData::iterator Where;
  std::tie(Where, NewFunc) =
      ProfileDataMap.insert(std::make_pair(I.Hash, InstrProfRecord()));
  InstrProfRecord &Dest = Where->second;

  instrprof_error Result;
  if (NewFunc) {
    // We've never seen a function with this name and hash, add it.
    Dest = std::move(I);
    // Fix up the name to avoid dangling reference.
    Dest.Name = FunctionData.find(Dest.Name)->getKey();
    Result = instrprof_error::success;
    if (Weight > 1) {
      for (auto &Count : Dest.Counts) {
        bool Overflowed;
        Count = SaturatingMultiply(Count, Weight, &Overflowed);
        if (Overflowed && Result == instrprof_error::success) {
          Result = instrprof_error::counter_overflow;
        }
      }
    }
  } else {
    // We're updating a function we've seen before.
    Result = Dest.merge(I, Weight);
  }

  // We keep track of the max function count as we go for simplicity.
  // Update this statistic no matter the result of the merge.
  if (Dest.Counts[0] > MaxFunctionCount)
    MaxFunctionCount = Dest.Counts[0];

  return Result;
}

std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
  OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;

  // Populate the hash table generator.
  for (const auto &I : FunctionData)
    Generator.insert(I.getKey(), &I.getValue());

  using namespace llvm::support;
  endian::Writer<little> LE(OS);

  // Write the header.
  IndexedInstrProf::Header Header;
  Header.Magic = IndexedInstrProf::Magic;
  Header.Version = IndexedInstrProf::Version;
  Header.MaxFunctionCount = MaxFunctionCount;
  Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType);
  Header.HashOffset = 0;
  int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t);

  // Only write out all the fields execpt 'HashOffset'. We need
  // to remember the offset of that field to allow back patching
  // later.
  for (int I = 0; I < N - 1; I++)
    LE.write<uint64_t>(reinterpret_cast<uint64_t *>(&Header)[I]);

  // Save a space to write the hash table start location.
  uint64_t HashTableStartLoc = OS.tell();
  // Reserve the space for HashOffset field.
  LE.write<uint64_t>(0);
  // Write the hash table.
  uint64_t HashTableStart = Generator.Emit(OS);

  return std::make_pair(HashTableStartLoc, HashTableStart);
}

void InstrProfWriter::write(raw_fd_ostream &OS) {
  // Write the hash table.
  auto TableStart = writeImpl(OS);

  // Go back and fill in the hash table start.
  using namespace support;
  OS.seek(TableStart.first);
  // Now patch the HashOffset field previously reserved.
  endian::Writer<little>(OS).write<uint64_t>(TableStart.second);
}

static const char *ValueProfKindStr[] = {
#define VALUE_PROF_KIND(Enumerator, Value) #Enumerator,
#include "llvm/ProfileData/InstrProfData.inc"
};

void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func,
                                        InstrProfSymtab &Symtab,
                                        raw_fd_ostream &OS) {
  OS << Func.Name << "\n";
  OS << "# Func Hash:\n" << Func.Hash << "\n";
  OS << "# Num Counters:\n" << Func.Counts.size() << "\n";
  OS << "# Counter Values:\n";
  for (uint64_t Count : Func.Counts)
    OS << Count << "\n";

  uint32_t NumValueKinds = Func.getNumValueKinds();
  if (!NumValueKinds) {
    OS << "\n";
    return;
  }

  OS << "# Num Value Kinds:\n" << Func.getNumValueKinds() << "\n";
  for (uint32_t VK = 0; VK < IPVK_Last + 1; VK++) {
    uint32_t NS = Func.getNumValueSites(VK);
    if (!NS)
      continue;
    OS << "# ValueKind = " << ValueProfKindStr[VK] << ":\n" << VK << "\n";
    OS << "# NumValueSites:\n" << NS << "\n";
    for (uint32_t S = 0; S < NS; S++) {
      uint32_t ND = Func.getNumValueDataForSite(VK, S);
      OS << ND << "\n";
      std::unique_ptr<InstrProfValueData[]> VD = Func.getValueForSite(VK, S);
      for (uint32_t I = 0; I < ND; I++) {
        if (VK == IPVK_IndirectCallTarget)
          OS << Symtab.getFuncName(VD[I].Value) << ":" << VD[I].Count << "\n";
        else
          OS << VD[I].Value << ":" << VD[I].Count << "\n";
      }
    }
  }

  OS << "\n";
}

void InstrProfWriter::writeText(raw_fd_ostream &OS) {
  InstrProfSymtab Symtab;
  for (const auto &I : FunctionData)
    Symtab.addFuncName(I.getKey());
  Symtab.finalizeSymtab();

  for (const auto &I : FunctionData)
    for (const auto &Func : I.getValue())
      writeRecordInText(Func.second, Symtab, OS);
}

std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() {
  std::string Data;
  llvm::raw_string_ostream OS(Data);
  // Write the hash table.
  auto TableStart = writeImpl(OS);
  OS.flush();

  // Go back and fill in the hash table start.
  using namespace support;
  uint64_t Bytes = endian::byte_swap<uint64_t, little>(TableStart.second);
  Data.replace(TableStart.first, sizeof(uint64_t), (const char *)&Bytes,
               sizeof(uint64_t));

  // Return this in an aligned memory buffer.
  return MemoryBuffer::getMemBufferCopy(Data);
}
<|endoftext|>


<commit_before>/* cclive
 * Copyright (C) 2010-2013  Toni Gundogdu <legatvs@gmail.com>
 *
 * This file is part of cclive <http://cclive.sourceforge.net/>.
 *
 * 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 <ccinternal>

#include <iomanip>
#include <vector>
#include <ctime>

#include <boost/algorithm/string/classification.hpp> // is_any_of
#include <boost/algorithm/string/split.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>

#include <ccquvi>
#include <ccapplication>
#include <ccoptions>
#include <ccinput>
#include <ccutil>
#include <cclog>
#include <ccre>

namespace cc
{

static void handle_fetch(const quvi_word type, void*)
{
#ifdef HAVE_LIBQUVI_0_9
  if (type == QUVI_CALLBACK_STATUS_DONE)
#else
  if (type == QUVISTATUSTYPE_DONE)
#endif
    cc::log << " ";
}

static void print_done()
{
  cc::log << "done.\n";
}

static void handle_verify(const quvi_word type)
{
#ifdef HAVE_LIBQUVI_0_9
  if (type == QUVI_CALLBACK_STATUS_DONE)
#else
  if (type == QUVISTATUSTYPE_DONE)
#endif
    print_done();
}

static void handle_resolve(const quvi_word type)
{
#ifdef HAVE_LIBQUVI_0_9
  if (type == QUVI_CALLBACK_STATUS_DONE)
#else
  if (type == QUVISTATUSTYPE_DONE)
#endif
    cc::log << " ";
}

#ifdef HAVE_LIBQUVI_0_9
static void status_callback_pt9(const quvi_word status, const quvi_word type,
                                void *data, void *userdata)
{
  cc::log << ".";
  switch (status)
    {
    case QUVI_CALLBACK_STATUS_FETCH:
      handle_fetch(type, data);
      break;
    case QUVI_CALLBACK_STATUS_HTTP_QUERY_METAINFO:
      handle_verify(type);
      break;
    case QUVI_CALLBACK_STATUS_RESOLVE:
      handle_resolve(type);
      break;
    }
}
#else
static void status_callback_pt4(const quvi_word status, const quvi_word type,
                                void *data)
{
  cc::log << ".";
  switch (status)
    {
    case QUVISTATUS_FETCH:
      handle_fetch(type, data);
      break;
    case QUVISTATUS_VERIFY:
      handle_verify(type);
      break;
    case QUVISTATUS_RESOLVE:
      handle_resolve(type);
      break;
    }
}
#endif

#ifdef HAVE_LIBQUVI_0_9
static int status_callback(long status_type, void *data, void *userdata)
#else
static int status_callback(long status_type, void *data)
#endif
{
  const quvi_word status = quvi_loword(status_type);
  const quvi_word type   = quvi_hiword(status_type);

#ifdef HAVE_LIBQUVI_0_9
  status_callback_pt9(status, type, data, userdata);
#else
  status_callback_pt4(status, type, data);
#endif
  cc::log << std::flush;

  return QUVI_OK;
}

static void print_retrying(const int retry,
                           const int max_retries,
                           const int retry_wait)
{
  if (retry > 0)
    {
      cc::log
          << "Retrying "
          << retry
          << " of "
          << max_retries
          << " ... "
          << std::flush;

      cc::wait(retry_wait);
    }
}

static void print_checking(const int i, const int n)
{
  if (n > 1)  cc::log << "(" << i << " of " << n << ") ";
  cc::log << "Checking ... " << std::flush;
}

static void print_quvi_error(const quvi::error& e)
{
  cc::log << "libquvi: error: " << e.what() << std::endl;
}

namespace po = boost::program_options;
typedef std::vector<std::string> vst;

static std::string format_streams(const std::string& s)
{
  vst v;
  boost::split(v, s, boost::is_any_of("|,"));
  const size_t m = v.size();

  if (m ==0)
    v.push_back("default");

  std::stringstream r;
  r << "\n";

  size_t i = 0, c = 0;
  BOOST_FOREACH(const std::string& a, v)
  {
    r << boost::format("%|22s|") % a;
    ++c;
    if (++i ==3)
      {
        if (c <m)
          r << "\n";
        i = 0;
      }
  }
  return r.str();
}

static application::exit_status
print_streams(const quvi::query& query, const quvi::options &qopts,
              const vst& input_urls, const po::variables_map& vm)
{
  const size_t n = input_urls.size();
  size_t i = 0;

  BOOST_FOREACH(const std::string& url, input_urls)
  {
    try
      {
        print_checking(++i,n);
        query.setup_curl(vm);

        const std::string r = query.streams(url, qopts);
        print_done();

        cc::log << "streams (found):" << format_streams(r) << std::endl;
      }
    catch(const quvi::error& e)
      {
        print_quvi_error(e);
        return application::error;
      }
  }
  return application::ok;
}

static void parse_prefer_format(const std::string& url, std::string& fmt,
                                const po::variables_map& vm)
{
  vst vb, va = vm[OPT__PREFER_FORMAT].as<vst>();
  BOOST_FOREACH(const std::string& s, va)
  {
    boost::split(vb, s, boost::is_any_of(":"));
    if (vb.size() == 2)
      {
        // vb[0] = pattern
        // vb[1] = format
        if (cc::re::grep(vb[0], url))
          {
            fmt = vb[1];
            return;
          }
      }
    vb.clear();
  }
}

static void set_stream(const std::string& url, quvi::options& qopts,
                       const po::variables_map& vm)
{
  std::string r = vm[OPT__STREAM].as<std::string>();
  if (r == "default" && vm.count(OPT__PREFER_FORMAT))
    parse_prefer_format(url, r, vm);
  qopts.stream = r;
}

application::exit_status application::exec(int const argc, char const **argv)
{
  const boost::scoped_ptr<cc::options> o(new cc::options(argc, argv));
  const po::variables_map vm = o->values();

  // Parse input.

  const vst& input_urls = cc::input::parse(vm);
  const size_t n = input_urls.size();

  // Set up quvi.

  quvi::query query; // Throws quvi::error caught in main.cpp

  quvi::options qopts;
  qopts.useragent = vm[OPT__AGENT].as<std::string>(); /* libquvi 0.9+ */
  qopts.resolve = ! vm[OPT__NO_RESOLVE].as<bool>();
  qopts.statusfunc = status_callback;

  // Omit flag.

  bool omit = vm[OPT__QUIET].as<bool>();

  // Go to background.

#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
  const bool background_given = vm[OPT__BACKGROUND].as<bool>();
  if (background_given)
    cc::go_background(vm[OPT__LOG_FILE].as<std::string>(), omit);
#endif

  // Omit std output. Note that --background flips this above.

  cc::log.push(cc::omit_sink(omit));
  cc::log.setf(std::ios::fixed);

  // Print streams.

  if_optsw_given(vm, OPT__PRINT_STREAMS)
    return print_streams(query, qopts, input_urls, vm);

#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
  #ifdef HAVE_GETPID
  if (background_given)
    {
      cc::log
          << "Running in background (pid: "
          << static_cast<long>(getpid())
          << ")."
          << std::endl;
    }
  #endif
#endif

  // For each input URL.

  size_t i = 0;

  const int max_retries  = vm[OPT__MAX_RETRIES].as<cc::max_retries>().value();
  const int retry_wait   = vm[OPT__RETRY_WAIT].as<cc::retry_wait>().value();

  exit_status es = ok;

  BOOST_FOREACH(const std::string& url, input_urls)
  {
    ++i;

    try
      {
        int retry = 0;

        while (retry <= max_retries)
          {
            print_retrying(retry, max_retries, retry_wait);
            ++retry;

            print_checking(i, n);
            quvi::media m;

            try
              {
                set_stream(url, qopts, vm);
                _curl = query.setup_curl(vm);
                m = query.parse(url, qopts);
              }
            catch(const quvi::error& e)
              {
                if (e.cannot_retry())
                  throw e;
                else
                  print_quvi_error(e);
              }

            cc::get(m, _curl, vm);
            break; // Stop retrying.
          }
        es = ok;
      }

    catch(const quvi::error& e)
      {
        print_quvi_error(e);
        es = application::error;
      }

    catch(const std::runtime_error& e)
      {
        cc::log << "error: " << e.what() << std::endl;
        es = application::error;
      }
  }
  return es;
}

} // namespace cc

// vim: set ts=2 sw=2 tw=72 expandtab:
<commit_msg>cc::application: Rename vst to vs (std::vector<std::string>)<commit_after>/* cclive
 * Copyright (C) 2010-2013  Toni Gundogdu <legatvs@gmail.com>
 *
 * This file is part of cclive <http://cclive.sourceforge.net/>.
 *
 * 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 <ccinternal>

#include <iomanip>
#include <vector>
#include <ctime>

#include <boost/algorithm/string/classification.hpp> // is_any_of
#include <boost/algorithm/string/split.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>

#include <ccquvi>
#include <ccapplication>
#include <ccoptions>
#include <ccinput>
#include <ccutil>
#include <cclog>
#include <ccre>

namespace cc
{

static void handle_fetch(const quvi_word type, void*)
{
#ifdef HAVE_LIBQUVI_0_9
  if (type == QUVI_CALLBACK_STATUS_DONE)
#else
  if (type == QUVISTATUSTYPE_DONE)
#endif
    cc::log << " ";
}

static void print_done()
{
  cc::log << "done.\n";
}

static void handle_verify(const quvi_word type)
{
#ifdef HAVE_LIBQUVI_0_9
  if (type == QUVI_CALLBACK_STATUS_DONE)
#else
  if (type == QUVISTATUSTYPE_DONE)
#endif
    print_done();
}

static void handle_resolve(const quvi_word type)
{
#ifdef HAVE_LIBQUVI_0_9
  if (type == QUVI_CALLBACK_STATUS_DONE)
#else
  if (type == QUVISTATUSTYPE_DONE)
#endif
    cc::log << " ";
}

#ifdef HAVE_LIBQUVI_0_9
static void status_callback_pt9(const quvi_word status, const quvi_word type,
                                void *data, void *userdata)
{
  cc::log << ".";
  switch (status)
    {
    case QUVI_CALLBACK_STATUS_FETCH:
      handle_fetch(type, data);
      break;
    case QUVI_CALLBACK_STATUS_HTTP_QUERY_METAINFO:
      handle_verify(type);
      break;
    case QUVI_CALLBACK_STATUS_RESOLVE:
      handle_resolve(type);
      break;
    }
}
#else
static void status_callback_pt4(const quvi_word status, const quvi_word type,
                                void *data)
{
  cc::log << ".";
  switch (status)
    {
    case QUVISTATUS_FETCH:
      handle_fetch(type, data);
      break;
    case QUVISTATUS_VERIFY:
      handle_verify(type);
      break;
    case QUVISTATUS_RESOLVE:
      handle_resolve(type);
      break;
    }
}
#endif

#ifdef HAVE_LIBQUVI_0_9
static int status_callback(long status_type, void *data, void *userdata)
#else
static int status_callback(long status_type, void *data)
#endif
{
  const quvi_word status = quvi_loword(status_type);
  const quvi_word type   = quvi_hiword(status_type);

#ifdef HAVE_LIBQUVI_0_9
  status_callback_pt9(status, type, data, userdata);
#else
  status_callback_pt4(status, type, data);
#endif
  cc::log << std::flush;

  return QUVI_OK;
}

static void print_retrying(const int retry,
                           const int max_retries,
                           const int retry_wait)
{
  if (retry > 0)
    {
      cc::log
          << "Retrying "
          << retry
          << " of "
          << max_retries
          << " ... "
          << std::flush;

      cc::wait(retry_wait);
    }
}

static void print_checking(const int i, const int n)
{
  if (n > 1)  cc::log << "(" << i << " of " << n << ") ";
  cc::log << "Checking ... " << std::flush;
}

static void print_quvi_error(const quvi::error& e)
{
  cc::log << "libquvi: error: " << e.what() << std::endl;
}

namespace po = boost::program_options;
typedef std::vector<std::string> vs;

static std::string format_streams(const std::string& s)
{
  vs v;
  boost::split(v, s, boost::is_any_of("|,"));
  const size_t m = v.size();

  if (m ==0)
    v.push_back("default");

  std::stringstream r;
  r << "\n";

  size_t i = 0, c = 0;
  BOOST_FOREACH(const std::string& a, v)
  {
    r << boost::format("%|22s|") % a;
    ++c;
    if (++i ==3)
      {
        if (c <m)
          r << "\n";
        i = 0;
      }
  }
  return r.str();
}

static application::exit_status
print_streams(const quvi::query& query, const quvi::options &qopts,
              const vs& input_urls, const po::variables_map& vm)
{
  const size_t n = input_urls.size();
  size_t i = 0;

  BOOST_FOREACH(const std::string& url, input_urls)
  {
    try
      {
        print_checking(++i,n);
        query.setup_curl(vm);

        const std::string r = query.streams(url, qopts);
        print_done();

        cc::log << "streams (found):" << format_streams(r) << std::endl;
      }
    catch(const quvi::error& e)
      {
        print_quvi_error(e);
        return application::error;
      }
  }
  return application::ok;
}

static void parse_prefer_format(const std::string& url, std::string& fmt,
                                const po::variables_map& vm)
{
  vs vb, va = vm[OPT__PREFER_FORMAT].as<vs>();
  BOOST_FOREACH(const std::string& s, va)
  {
    boost::split(vb, s, boost::is_any_of(":"));
    if (vb.size() == 2)
      {
        // vb[0] = pattern
        // vb[1] = format
        if (cc::re::grep(vb[0], url))
          {
            fmt = vb[1];
            return;
          }
      }
    vb.clear();
  }
}

static void set_stream(const std::string& url, quvi::options& qopts,
                       const po::variables_map& vm)
{
  std::string r = vm[OPT__STREAM].as<std::string>();
  if (r == "default" && vm.count(OPT__PREFER_FORMAT))
    parse_prefer_format(url, r, vm);
  qopts.stream = r;
}

application::exit_status application::exec(int const argc, char const **argv)
{
  const boost::scoped_ptr<cc::options> o(new cc::options(argc, argv));
  const po::variables_map vm = o->values();

  // Parse input.

  const vs& input_urls = cc::input::parse(vm);
  const size_t n = input_urls.size();

  // Set up quvi.

  quvi::query query; // Throws quvi::error caught in main.cpp

  quvi::options qopts;
  qopts.useragent = vm[OPT__AGENT].as<std::string>(); /* libquvi 0.9+ */
  qopts.resolve = ! vm[OPT__NO_RESOLVE].as<bool>();
  qopts.statusfunc = status_callback;

  // Omit flag.

  bool omit = vm[OPT__QUIET].as<bool>();

  // Go to background.

#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
  const bool background_given = vm[OPT__BACKGROUND].as<bool>();
  if (background_given)
    cc::go_background(vm[OPT__LOG_FILE].as<std::string>(), omit);
#endif

  // Omit std output. Note that --background flips this above.

  cc::log.push(cc::omit_sink(omit));
  cc::log.setf(std::ios::fixed);

  // Print streams.

  if_optsw_given(vm, OPT__PRINT_STREAMS)
    return print_streams(query, qopts, input_urls, vm);

#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
  #ifdef HAVE_GETPID
  if (background_given)
    {
      cc::log
          << "Running in background (pid: "
          << static_cast<long>(getpid())
          << ")."
          << std::endl;
    }
  #endif
#endif

  // For each input URL.

  size_t i = 0;

  const int max_retries  = vm[OPT__MAX_RETRIES].as<cc::max_retries>().value();
  const int retry_wait   = vm[OPT__RETRY_WAIT].as<cc::retry_wait>().value();

  exit_status es = ok;

  BOOST_FOREACH(const std::string& url, input_urls)
  {
    ++i;

    try
      {
        int retry = 0;

        while (retry <= max_retries)
          {
            print_retrying(retry, max_retries, retry_wait);
            ++retry;

            print_checking(i, n);
            quvi::media m;

            try
              {
                set_stream(url, qopts, vm);
                _curl = query.setup_curl(vm);
                m = query.parse(url, qopts);
              }
            catch(const quvi::error& e)
              {
                if (e.cannot_retry())
                  throw e;
                else
                  print_quvi_error(e);
              }

            cc::get(m, _curl, vm);
            break; // Stop retrying.
          }
        es = ok;
      }

    catch(const quvi::error& e)
      {
        print_quvi_error(e);
        es = application::error;
      }

    catch(const std::runtime_error& e)
      {
        cc::log << "error: " << e.what() << std::endl;
        es = application::error;
      }
  }
  return es;
}

} // namespace cc

// vim: set ts=2 sw=2 tw=72 expandtab:
<|endoftext|>


<commit_before>#include <stdio.h>
#include <vector>

#include "../cshared/opcodes.h"
#include "../cshared/opcodes_format.h"
#include "../cshared/opcodes_debug.h"

struct AsmStream
{
    std::vector<unsigned char> data;
    void read(size_t size = 1)
    {
        auto old_size = data.size();
        data.resize(old_size + size);
        fread(&data[old_size], 1, size, stdin);
    }
    unsigned char operator[](size_t index) const
    {
        return data[index];
    }
};

int main()
{
    // skip header
    const auto    header_size = 3 + 4 * 8;
    unsigned char header[header_size];
    fread(header, 1, header_size, stdin);

    while (!feof(stdin))
    {
        AsmStream stream;
        stream.read();
        unsigned char opcode = stream[0];
        printf("opcode %d\n", opcode);
    }

    return 0;
}
<commit_msg>disasm: print asm code<commit_after>#include <stdio.h>
#include <vector>
#include <assert.h>

#include "../cshared/opcodes.h"
#include "../cshared/opcodes_format.h"
#include "../cshared/opcodes_debug.h"

#define countof(x) (sizeof(x) / sizeof(x[0]))

struct AsmStream
{
    std::vector<unsigned char> data;

    void *read(size_t size = 1)
    {
        auto old_size = data.size();
        data.resize(old_size + size);
        auto buffer = &data[old_size];
        fread(buffer, 1, size, stdin);
        return buffer;
    }

    template <typename T>
    T _read()
    {
        return *(T *)read(sizeof(T));
    }

    void read_uint8(std::string &info)
    {
        auto value = _read<uint8_t>();
        char output[32];
        sprintf(output, "%d", value);
        if (info.length())
            info += ", ";
        info += output;
    }

    void read_uint16(std::string &info)
    {
        auto value = _read<uint16_t>();
        char output[32];
        sprintf(output, "%d", value);
        if (info.length())
            info += ", ";
        info += output;
    }

    void read_uint64(std::string &info)
    {
        auto value = _read<uint64_t>();
        char output[32];
        sprintf(output, "%llu", value);
        if (info.length())
            info += ", ";
        info += output;
    }

    void read_vlc(std::string &info)
    {
        size_t length = _read<uint8_t>();
        if (length == 256)
        {
            length = _read<uint64_t>();
        }
        auto        ptr = read(length);
        std::string output((const char *)ptr, length);
        if (info.length())
            info += ", ";
        info += output;
    }

    unsigned char operator[](size_t index) const
    {
        return data[index];
    }
};

int main()
{
    // skip header
    const auto    header_size = 3 + 4 * 8;
    unsigned char header[header_size];
    fread(header, 1, header_size, stdin);

    while (!feof(stdin))
    {
        AsmStream stream;
        stream.read();
        unsigned char opcode = stream[0];
        assert(opcode < countof(g_opcodes));
        const auto &data = g_opcodes[opcode];
        std::string info;
        for (const auto &arg : data.args)
        {
            switch (arg)
            {
            case ARG_UINT8:
                stream.read_uint8(info);
                break;
            case ARG_UINT16:
                stream.read_uint16(info);
                break;
            case ARG_UINT64:
                stream.read_uint64(info);
                break;
            case ARG_VLC:
                stream.read_vlc(info);
                break;
            }
        }
        info = data.name + " " + info;
        printf("%s\n", info.c_str());
    }

    return 0;
}
<|endoftext|>


<commit_before>//===-- ARMTargetMachine.cpp - Define TargetMachine for ARM ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//

#include "ARMTargetMachine.h"
#include "ARM.h"
#include "ARMFrameLowering.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
using namespace llvm;

static cl::opt<bool>
EnableGlobalMerge("global-merge", cl::Hidden,
                  cl::desc("Enable global merge pass"),
                  cl::init(true));

static cl::opt<bool>
DisableA15SDOptimization("disable-a15-sd-optimization", cl::Hidden,
                   cl::desc("Inhibit optimization of S->D register accesses on A15"),
                   cl::init(false));

extern "C" void LLVMInitializeARMTarget() {
  // Register the target.
  RegisterTargetMachine<ARMTargetMachine> X(TheARMTarget);
  RegisterTargetMachine<ThumbTargetMachine> Y(TheThumbTarget);
}

/// TargetMachine ctor - Create an ARM architecture model.
///
ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, StringRef TT,
                                           StringRef CPU, StringRef FS,
                                           const TargetOptions &Options,
                                           Reloc::Model RM, CodeModel::Model CM,
                                           CodeGenOpt::Level OL)
  : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
    Subtarget(TT, CPU, FS, Options),
    JITInfo(),
    InstrItins(Subtarget.getInstrItineraryData()) {
  // Default to soft float ABI
  if (Options.FloatABIType == FloatABI::Default)
    this->Options.FloatABIType = FloatABI::Soft;
}

void ARMBaseTargetMachine::addAnalysisPasses(PassManagerBase &PM) {
  // Add first the target-independent BasicTTI pass, then our ARM pass. This
  // allows the ARM pass to delegate to the target independent layer when
  // appropriate.
  PM.add(createBasicTargetTransformInfoPass(this));
  PM.add(createARMTargetTransformInfoPass(this));
}

void ARMTargetMachine::anchor() { }

static std::string computeDataLayout(ARMSubtarget &ST) {
  // Little endian. Pointers are 32 bits and aligned to 32 bits.
  std::string Ret = "e-p:32:32";

  // On thumb, i16,i18 and i1 have natural aligment requirements, but we try to
  // align to 32.
  if (ST.isThumb())
    Ret += "-i1:8:32-i8:8:32-i16:16:32";

  // ABIs other than APC have 64 bit integers with natural alignment.
  if (!ST.isAPCS_ABI())
    Ret += "-i64:64";

  // We have 64 bits floats. The APCS ABI requires them to be aligned to 32
  // bits, others to 64 bits. We always try to align to 64 bits.
  if (ST.isAPCS_ABI())
    Ret += "-f64:32:64";

  // We have 128 and 64 bit vectors. The APCS ABI aligns them to 32 bits, others
  // to 64. We always ty to give them natural alignment.
  if (ST.isAPCS_ABI())
    Ret += "-v64:32:64-v128:32:128";
  else
    Ret += "-v128:64:128";

  // An aggregate of size 0 is ABI aligned to 0.
  // FIXME: explain better what this means.
  if (ST.isThumb())
    Ret += "-a:0:32";

  // Integer registers are 32 bits.
  Ret += "-n32";

  // The stack is 64 bit aligned on AAPCS and 32 bit aligned everywhere else.
  if (ST.isAAPCS_ABI())
    Ret += "-S64";
  else
    Ret += "-S32";

  return Ret;
}

ARMTargetMachine::ARMTargetMachine(const Target &T, StringRef TT,
                                   StringRef CPU, StringRef FS,
                                   const TargetOptions &Options,
                                   Reloc::Model RM, CodeModel::Model CM,
                                   CodeGenOpt::Level OL)
  : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
    InstrInfo(Subtarget),
    DL(computeDataLayout(Subtarget)),
    TLInfo(*this),
    TSInfo(*this),
    FrameLowering(Subtarget) {
  initAsmInfo();
  if (!Subtarget.hasARMOps())
    report_fatal_error("CPU: '" + Subtarget.getCPUString() + "' does not "
                       "support ARM mode execution!");
}

void ThumbTargetMachine::anchor() { }

ThumbTargetMachine::ThumbTargetMachine(const Target &T, StringRef TT,
                                       StringRef CPU, StringRef FS,
                                       const TargetOptions &Options,
                                       Reloc::Model RM, CodeModel::Model CM,
                                       CodeGenOpt::Level OL)
  : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
    InstrInfo(Subtarget.hasThumb2()
              ? ((ARMBaseInstrInfo*)new Thumb2InstrInfo(Subtarget))
              : ((ARMBaseInstrInfo*)new Thumb1InstrInfo(Subtarget))),
    DL(computeDataLayout(Subtarget)),
    TLInfo(*this),
    TSInfo(*this),
    FrameLowering(Subtarget.hasThumb2()
              ? new ARMFrameLowering(Subtarget)
              : (ARMFrameLowering*)new Thumb1FrameLowering(Subtarget)) {
  initAsmInfo();
}

namespace {
/// ARM Code Generator Pass Configuration Options.
class ARMPassConfig : public TargetPassConfig {
public:
  ARMPassConfig(ARMBaseTargetMachine *TM, PassManagerBase &PM)
    : TargetPassConfig(TM, PM) {}

  ARMBaseTargetMachine &getARMTargetMachine() const {
    return getTM<ARMBaseTargetMachine>();
  }

  const ARMSubtarget &getARMSubtarget() const {
    return *getARMTargetMachine().getSubtargetImpl();
  }

  virtual bool addPreISel();
  virtual bool addInstSelector();
  virtual bool addPreRegAlloc();
  virtual bool addPreSched2();
  virtual bool addPreEmitPass();
};
} // namespace

TargetPassConfig *ARMBaseTargetMachine::createPassConfig(PassManagerBase &PM) {
  return new ARMPassConfig(this, PM);
}

bool ARMPassConfig::addPreISel() {
  if (TM->getOptLevel() != CodeGenOpt::None && EnableGlobalMerge)
    addPass(createGlobalMergePass(TM));

  return false;
}

bool ARMPassConfig::addInstSelector() {
  addPass(createARMISelDag(getARMTargetMachine(), getOptLevel()));

  const ARMSubtarget *Subtarget = &getARMSubtarget();
  if (Subtarget->isTargetELF() && !Subtarget->isThumb1Only() &&
      TM->Options.EnableFastISel)
    addPass(createARMGlobalBaseRegPass());
  return false;
}

bool ARMPassConfig::addPreRegAlloc() {
  // FIXME: temporarily disabling load / store optimization pass for Thumb1.
  if (getOptLevel() != CodeGenOpt::None && !getARMSubtarget().isThumb1Only())
    addPass(createARMLoadStoreOptimizationPass(true));
  if (getOptLevel() != CodeGenOpt::None && getARMSubtarget().isCortexA9())
    addPass(createMLxExpansionPass());
  // Since the A15SDOptimizer pass can insert VDUP instructions, it can only be
  // enabled when NEON is available.
  if (getOptLevel() != CodeGenOpt::None && getARMSubtarget().isCortexA15() &&
    getARMSubtarget().hasNEON() && !DisableA15SDOptimization) {
    addPass(createA15SDOptimizerPass());
  }
  return true;
}

bool ARMPassConfig::addPreSched2() {
  // FIXME: temporarily disabling load / store optimization pass for Thumb1.
  if (getOptLevel() != CodeGenOpt::None) {
    if (!getARMSubtarget().isThumb1Only()) {
      addPass(createARMLoadStoreOptimizationPass());
      printAndVerify("After ARM load / store optimizer");
    }
    if (getARMSubtarget().hasNEON())
      addPass(createExecutionDependencyFixPass(&ARM::DPRRegClass));
  }

  // Expand some pseudo instructions into multiple instructions to allow
  // proper scheduling.
  addPass(createARMExpandPseudoPass());

  if (getOptLevel() != CodeGenOpt::None) {
    if (!getARMSubtarget().isThumb1Only()) {
      // in v8, IfConversion depends on Thumb instruction widths
      if (getARMSubtarget().restrictIT() &&
          !getARMSubtarget().prefers32BitThumb())
        addPass(createThumb2SizeReductionPass());
      addPass(&IfConverterID);
    }
  }
  if (getARMSubtarget().isThumb2())
    addPass(createThumb2ITBlockPass());

  return true;
}

bool ARMPassConfig::addPreEmitPass() {
  if (getARMSubtarget().isThumb2()) {
    if (!getARMSubtarget().prefers32BitThumb())
      addPass(createThumb2SizeReductionPass());

    // Constant island pass work on unbundled instructions.
    addPass(&UnpackMachineBundlesID);
  }

  addPass(createARMConstantIslandPass());

  return true;
}

bool ARMBaseTargetMachine::addCodeEmitter(PassManagerBase &PM,
                                          JITCodeEmitter &JCE) {
  // Machine code emitter pass for ARM.
  PM.add(createARMJITCodeEmitterPass(*this, JCE));
  return false;
}
<commit_msg>On APCS, only try to align aggregates to 32 bits instead of 64.<commit_after>//===-- ARMTargetMachine.cpp - Define TargetMachine for ARM ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//

#include "ARMTargetMachine.h"
#include "ARM.h"
#include "ARMFrameLowering.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
using namespace llvm;

static cl::opt<bool>
EnableGlobalMerge("global-merge", cl::Hidden,
                  cl::desc("Enable global merge pass"),
                  cl::init(true));

static cl::opt<bool>
DisableA15SDOptimization("disable-a15-sd-optimization", cl::Hidden,
                   cl::desc("Inhibit optimization of S->D register accesses on A15"),
                   cl::init(false));

extern "C" void LLVMInitializeARMTarget() {
  // Register the target.
  RegisterTargetMachine<ARMTargetMachine> X(TheARMTarget);
  RegisterTargetMachine<ThumbTargetMachine> Y(TheThumbTarget);
}

/// TargetMachine ctor - Create an ARM architecture model.
///
ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, StringRef TT,
                                           StringRef CPU, StringRef FS,
                                           const TargetOptions &Options,
                                           Reloc::Model RM, CodeModel::Model CM,
                                           CodeGenOpt::Level OL)
  : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
    Subtarget(TT, CPU, FS, Options),
    JITInfo(),
    InstrItins(Subtarget.getInstrItineraryData()) {
  // Default to soft float ABI
  if (Options.FloatABIType == FloatABI::Default)
    this->Options.FloatABIType = FloatABI::Soft;
}

void ARMBaseTargetMachine::addAnalysisPasses(PassManagerBase &PM) {
  // Add first the target-independent BasicTTI pass, then our ARM pass. This
  // allows the ARM pass to delegate to the target independent layer when
  // appropriate.
  PM.add(createBasicTargetTransformInfoPass(this));
  PM.add(createARMTargetTransformInfoPass(this));
}

void ARMTargetMachine::anchor() { }

static std::string computeDataLayout(ARMSubtarget &ST) {
  // Little endian. Pointers are 32 bits and aligned to 32 bits.
  std::string Ret = "e-p:32:32";

  // On thumb, i16,i18 and i1 have natural aligment requirements, but we try to
  // align to 32.
  if (ST.isThumb())
    Ret += "-i1:8:32-i8:8:32-i16:16:32";

  // ABIs other than APC have 64 bit integers with natural alignment.
  if (!ST.isAPCS_ABI())
    Ret += "-i64:64";

  // We have 64 bits floats. The APCS ABI requires them to be aligned to 32
  // bits, others to 64 bits. We always try to align to 64 bits.
  if (ST.isAPCS_ABI())
    Ret += "-f64:32:64";

  // We have 128 and 64 bit vectors. The APCS ABI aligns them to 32 bits, others
  // to 64. We always ty to give them natural alignment.
  if (ST.isAPCS_ABI())
    Ret += "-v64:32:64-v128:32:128";
  else
    Ret += "-v128:64:128";

  // On thumb and APCS, only try to align aggregates to 32 bits (the default is
  // 64 bits).
  if (ST.isThumb() || ST.isAPCS_ABI())
    Ret += "-a:0:32";

  // Integer registers are 32 bits.
  Ret += "-n32";

  // The stack is 64 bit aligned on AAPCS and 32 bit aligned everywhere else.
  if (ST.isAAPCS_ABI())
    Ret += "-S64";
  else
    Ret += "-S32";

  return Ret;
}

ARMTargetMachine::ARMTargetMachine(const Target &T, StringRef TT,
                                   StringRef CPU, StringRef FS,
                                   const TargetOptions &Options,
                                   Reloc::Model RM, CodeModel::Model CM,
                                   CodeGenOpt::Level OL)
  : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
    InstrInfo(Subtarget),
    DL(computeDataLayout(Subtarget)),
    TLInfo(*this),
    TSInfo(*this),
    FrameLowering(Subtarget) {
  initAsmInfo();
  if (!Subtarget.hasARMOps())
    report_fatal_error("CPU: '" + Subtarget.getCPUString() + "' does not "
                       "support ARM mode execution!");
}

void ThumbTargetMachine::anchor() { }

ThumbTargetMachine::ThumbTargetMachine(const Target &T, StringRef TT,
                                       StringRef CPU, StringRef FS,
                                       const TargetOptions &Options,
                                       Reloc::Model RM, CodeModel::Model CM,
                                       CodeGenOpt::Level OL)
  : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
    InstrInfo(Subtarget.hasThumb2()
              ? ((ARMBaseInstrInfo*)new Thumb2InstrInfo(Subtarget))
              : ((ARMBaseInstrInfo*)new Thumb1InstrInfo(Subtarget))),
    DL(computeDataLayout(Subtarget)),
    TLInfo(*this),
    TSInfo(*this),
    FrameLowering(Subtarget.hasThumb2()
              ? new ARMFrameLowering(Subtarget)
              : (ARMFrameLowering*)new Thumb1FrameLowering(Subtarget)) {
  initAsmInfo();
}

namespace {
/// ARM Code Generator Pass Configuration Options.
class ARMPassConfig : public TargetPassConfig {
public:
  ARMPassConfig(ARMBaseTargetMachine *TM, PassManagerBase &PM)
    : TargetPassConfig(TM, PM) {}

  ARMBaseTargetMachine &getARMTargetMachine() const {
    return getTM<ARMBaseTargetMachine>();
  }

  const ARMSubtarget &getARMSubtarget() const {
    return *getARMTargetMachine().getSubtargetImpl();
  }

  virtual bool addPreISel();
  virtual bool addInstSelector();
  virtual bool addPreRegAlloc();
  virtual bool addPreSched2();
  virtual bool addPreEmitPass();
};
} // namespace

TargetPassConfig *ARMBaseTargetMachine::createPassConfig(PassManagerBase &PM) {
  return new ARMPassConfig(this, PM);
}

bool ARMPassConfig::addPreISel() {
  if (TM->getOptLevel() != CodeGenOpt::None && EnableGlobalMerge)
    addPass(createGlobalMergePass(TM));

  return false;
}

bool ARMPassConfig::addInstSelector() {
  addPass(createARMISelDag(getARMTargetMachine(), getOptLevel()));

  const ARMSubtarget *Subtarget = &getARMSubtarget();
  if (Subtarget->isTargetELF() && !Subtarget->isThumb1Only() &&
      TM->Options.EnableFastISel)
    addPass(createARMGlobalBaseRegPass());
  return false;
}

bool ARMPassConfig::addPreRegAlloc() {
  // FIXME: temporarily disabling load / store optimization pass for Thumb1.
  if (getOptLevel() != CodeGenOpt::None && !getARMSubtarget().isThumb1Only())
    addPass(createARMLoadStoreOptimizationPass(true));
  if (getOptLevel() != CodeGenOpt::None && getARMSubtarget().isCortexA9())
    addPass(createMLxExpansionPass());
  // Since the A15SDOptimizer pass can insert VDUP instructions, it can only be
  // enabled when NEON is available.
  if (getOptLevel() != CodeGenOpt::None && getARMSubtarget().isCortexA15() &&
    getARMSubtarget().hasNEON() && !DisableA15SDOptimization) {
    addPass(createA15SDOptimizerPass());
  }
  return true;
}

bool ARMPassConfig::addPreSched2() {
  // FIXME: temporarily disabling load / store optimization pass for Thumb1.
  if (getOptLevel() != CodeGenOpt::None) {
    if (!getARMSubtarget().isThumb1Only()) {
      addPass(createARMLoadStoreOptimizationPass());
      printAndVerify("After ARM load / store optimizer");
    }
    if (getARMSubtarget().hasNEON())
      addPass(createExecutionDependencyFixPass(&ARM::DPRRegClass));
  }

  // Expand some pseudo instructions into multiple instructions to allow
  // proper scheduling.
  addPass(createARMExpandPseudoPass());

  if (getOptLevel() != CodeGenOpt::None) {
    if (!getARMSubtarget().isThumb1Only()) {
      // in v8, IfConversion depends on Thumb instruction widths
      if (getARMSubtarget().restrictIT() &&
          !getARMSubtarget().prefers32BitThumb())
        addPass(createThumb2SizeReductionPass());
      addPass(&IfConverterID);
    }
  }
  if (getARMSubtarget().isThumb2())
    addPass(createThumb2ITBlockPass());

  return true;
}

bool ARMPassConfig::addPreEmitPass() {
  if (getARMSubtarget().isThumb2()) {
    if (!getARMSubtarget().prefers32BitThumb())
      addPass(createThumb2SizeReductionPass());

    // Constant island pass work on unbundled instructions.
    addPass(&UnpackMachineBundlesID);
  }

  addPass(createARMConstantIslandPass());

  return true;
}

bool ARMBaseTargetMachine::addCodeEmitter(PassManagerBase &PM,
                                          JITCodeEmitter &JCE) {
  // Machine code emitter pass for ARM.
  PM.add(createARMJITCodeEmitterPass(*this, JCE));
  return false;
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <ctime>
#include <stdint.h>
#include <fnord/inspect.h>
#include <chartsql/svalue.h>
#include <chartsql/format.h>
#include <chartsql/parser/token.h>

namespace csql {

SValue::SValue() {
  memset(&data_, 0, sizeof(data_));
  data_.type = T_NULL;
}

SValue::~SValue() {
  // FIXPAUL free string!
}

SValue::SValue(const SValue::StringType& string_value) {
  data_.type = T_STRING;
  data_.u.t_string.len = string_value.size();
  data_.u.t_string.ptr = static_cast<char *>(malloc(data_.u.t_string.len));

  if (data_.u.t_string.ptr == nullptr) {
    RAISE(kRuntimeError, "could not allocate SValue");
  }

  memcpy(
      data_.u.t_string.ptr,
      string_value.c_str(),
      data_.u.t_string.len);
}

SValue::SValue(
    char const* string_value) :
    SValue(std::string(string_value)) {}

SValue::SValue(SValue::IntegerType integer_value) {
  data_.type = T_INTEGER;
  data_.u.t_integer = integer_value;
}

SValue::SValue(SValue::FloatType float_value) {
  data_.type = T_FLOAT;
  data_.u.t_float = float_value;
}

SValue::SValue(SValue::BoolType bool_value) {
  data_.type = T_BOOL;
  data_.u.t_bool = bool_value;
}

SValue::SValue(SValue::TimeType time_value) {
  data_.type = T_TIMESTAMP;
  data_.u.t_timestamp = static_cast<uint64_t>(time_value);
}

SValue::SValue(const SValue& copy) {
  switch (copy.data_.type) {

    case T_STRING:
      data_.type = T_STRING;
      data_.u.t_string.len = copy.data_.u.t_string.len;
      data_.u.t_string.ptr = static_cast<char *>(malloc(data_.u.t_string.len));

      if (data_.u.t_string.ptr == nullptr) {
        RAISE(kRuntimeError, "could not allocate SValue");
      }

      memcpy(
          data_.u.t_string.ptr,
          copy.data_.u.t_string.ptr,
          data_.u.t_string.len);

    default:
      memcpy(&data_, &copy.data_, sizeof(data_));
      break;

  }

}

SValue& SValue::operator=(const SValue& copy) {
  // FIXPAUL free old string!

  switch (copy.data_.type) {

    case T_STRING:
      data_.type = T_STRING;
      data_.u.t_string.len = copy.data_.u.t_string.len;
      data_.u.t_string.ptr = static_cast<char *>(malloc(data_.u.t_string.len));

      if (data_.u.t_string.ptr == nullptr) {
        RAISE(kRuntimeError, "could not allocate SValue");
      }

      memcpy(
          data_.u.t_string.ptr,
          copy.data_.u.t_string.ptr,
          data_.u.t_string.len);

    default:
      memcpy(&data_, &copy.data_, sizeof(data_));
      break;

  }

  return *this;
}

bool SValue::operator==(const SValue& other) const {
  if (data_.type != other.data_.type) {
    return false;
  }

  switch (data_.type) {
    case T_STRING:
      return memcmp(
          data_.u.t_string.ptr,
          other.data_.u.t_string.ptr,
          data_.u.t_string.len) == 0;

    default:
      return memcmp(&data_, &other.data_, sizeof(data_)) == 0;

  }
}

SValue::kSValueType SValue::getType() const {
  return data_.type;
}

SValue::IntegerType SValue::getInteger() const {
  switch (data_.type) {

    case T_INTEGER:
      return data_.u.t_integer;

    case T_TIMESTAMP:
      return data_.u.t_timestamp;

    case T_STRING:
      try {
        return std::stol(getString());
      } catch (std::exception e) {
        /* fallthrough */
      }

    default:
      RAISE(
          kTypeError,
          "can't convert %s '%s' to Integer",
          SValue::getTypeName(data_.type),
          toString().c_str());

  }

  return 0;
}

SValue::FloatType SValue::getFloat() const {
  switch (data_.type) {

    case T_INTEGER:
      return data_.u.t_integer;

    case T_FLOAT:
      return data_.u.t_float;

    case T_STRING:
      try {
        return std::stod(getString());
      } catch (std::exception e) {
        /* fallthrough */
      }

    default:
      RAISE(
          kTypeError,
          "can't convert %s '%s' to Float",
          SValue::getTypeName(data_.type),
          toString().c_str());

  }

  return 0;
}

SValue::BoolType SValue::getBool() const {
  if (data_.type != T_BOOL) {
    RAISE(
       kTypeError,
        "can't convert %s '%s' to Bool",
        SValue::getTypeName(data_.type),
        toString().c_str());
  }

  return data_.u.t_bool;
}

SValue::BoolType SValue::getBoolWithConversion() const {
  switch (data_.type) {

    case T_INTEGER:
      return getInteger() > 0;

    case T_FLOAT:
      return getFloat() > 0;

    case T_BOOL:
      return getBool();

    case T_NULL:
      return false;

    default:
      RAISEF(
         kTypeError,
          "can't convert $0 '$1' to Boolean",
          SValue::getTypeName(data_.type),
          toString());

  }
}

SValue::TimeType SValue::getTimestamp() const {
  switch (getType()) {

    case T_TIMESTAMP:
      return data_.u.t_timestamp;

    default:
      RAISE(
         kTypeError,
          "can't convert %s '%s' to Timestamp",
          SValue::getTypeName(data_.type),
          toString().c_str());

  }
}

SValue::StringType SValue::getString() const {
  if (data_.type == T_STRING) {
    return std::string(data_.u.t_string.ptr, data_.u.t_string.len);
  } else {
    return toString();
  }
}

std::string SValue::makeUniqueKey(SValue* arr, size_t len) {
  std::string key;

  for (int i = 0; i < len; ++i) {
    key.append(arr[i].toString());
    key.append("\x00");
  }

  return key;
}

std::string SValue::toString() const {
  char buf[512];
  const char* str;
  size_t len;

  switch (data_.type) {

    case T_INTEGER: {
      len = snprintf(buf, sizeof(buf), "%" PRId64, getInteger());
      str = buf;
      break;
    }

    case T_TIMESTAMP: {
      return getTimestamp().toString("%Y-%m-%d %H:%M:%S");
    }

    case T_FLOAT: {
      len = snprintf(buf, sizeof(buf), "%f", getFloat());
      str = buf;
      break;
    }

    case T_BOOL: {
      static const auto true_str = "true";
      static const auto false_str = "false";
      if (getBool()) {
        str = true_str;
        len = strlen(true_str);
      } else {
        str = false_str;
        len = strlen(false_str);
      }
      break;
    }

    case T_STRING: {
      return getString();
    }

    case T_NULL: {
      static const char undef_str[] = "NULL";
      str = undef_str;
      len = sizeof(undef_str) - 1;
    }

  }

  return std::string(str, len);
}

const char* SValue::getTypeName(kSValueType type) {
  switch (type) {
    case T_STRING:
      return "String";
    case T_FLOAT:
      return "Float";
    case T_INTEGER:
      return "Integer";
    case T_BOOL:
      return "Boolean";
    case T_TIMESTAMP:
      return "Timestamp";
    case T_NULL:
      return "NULL";
  }
}

const char* SValue::getTypeName() const {
  return SValue::getTypeName(data_.type);
}

template <> SValue::BoolType SValue::getValue<SValue::BoolType>() const {
  return getBool();
}

template <> SValue::IntegerType SValue::getValue<SValue::IntegerType>() const {
  return getInteger();
}

template <> SValue::FloatType SValue::getValue<SValue::FloatType>() const {
  return getFloat();
}

template <> SValue::StringType SValue::getValue<SValue::StringType>() const {
  return toString();
}

template <> SValue::TimeType SValue::getValue<SValue::TimeType>() const {
  return getTimestamp();
}

// FIXPAUL: smarter type detection
template <> bool SValue::testType<SValue::BoolType>() const {
  return data_.type == T_BOOL;
}

template <> bool SValue::testType<SValue::TimeType>() const {
  return data_.type == T_TIMESTAMP;
}

template <> bool SValue::testType<SValue::IntegerType>() const {
  if (data_.type == T_INTEGER) {
    return true;
  }

  auto str = toString();
  const char* cur = str.c_str();
  const char* end = cur + str.size();

  if (*cur == '-') {
    ++cur;
  }

  if (cur == end) {
    return false;
  }

  for (; cur < end; ++cur) {
    if (*cur < '0' || *cur > '9') {
      return false;
    }
  }

  return true;
}

template <> bool SValue::testType<SValue::FloatType>() const {
  if (data_.type == T_FLOAT) {
    return true;
  }

  auto str = toString();
  bool dot = false;
  const char* c = str.c_str();

  if (*c == '-') {
    ++c;
  }

  for (; *c != 0; ++c) {
    if (*c >= '0' && *c <= '9') {
      continue;
    }

    if (*c == '.' || *c == ',') {
      if (dot) {
        return false;
      } else {
        dot = true;
      }
      continue;
    }

    return false;
  }

  return true;
}

template <> bool SValue::testType<std::string>() const {
  return true;
}

SValue::kSValueType SValue::testTypeWithNumericConversion() const {
  if (testType<SValue::IntegerType>()) return T_INTEGER;
  if (testType<SValue::FloatType>()) return T_FLOAT;
  return getType();
}

bool SValue::tryNumericConversion() {
  if (testType<SValue::IntegerType>()) {
    SValue::IntegerType val = getValue<SValue::IntegerType>();
    data_.type = T_INTEGER;
    data_.u.t_integer = val;
    return true;
  }

  if (testType<SValue::FloatType>()) {
    SValue::FloatType val = getValue<SValue::FloatType>();
    data_.type = T_FLOAT;
    data_.u.t_float = val;
    return true;
  }

  return false;
}

bool SValue::tryTimeConversion() {
  if (!tryNumericConversion()) {
    return false;
  }

  time_t ts = getInteger();
  data_.type = T_TIMESTAMP;
  // FIXPAUL take a smart guess if this is milli, micro, etc
  data_.u.t_timestamp = ts * 1000000llu;
  return true;
}

}

namespace fnord {

template <>
std::string inspect<csql::SValue::kSValueType>(
    const csql::SValue::kSValueType& type) {
  return csql::SValue::getTypeName(type);
}

template <>
std::string inspect<csql::SValue>(
    const csql::SValue& sval) {
  return sval.toString();
}

}

namespace std {

size_t hash<csql::SValue>::operator()(const csql::SValue& sval) const {
  return hash<std::string>()(sval.toString()); // FIXPAUL
}

}
<commit_msg>make string truthy<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <ctime>
#include <stdint.h>
#include <fnord/inspect.h>
#include <chartsql/svalue.h>
#include <chartsql/format.h>
#include <chartsql/parser/token.h>

namespace csql {

SValue::SValue() {
  memset(&data_, 0, sizeof(data_));
  data_.type = T_NULL;
}

SValue::~SValue() {
  // FIXPAUL free string!
}

SValue::SValue(const SValue::StringType& string_value) {
  data_.type = T_STRING;
  data_.u.t_string.len = string_value.size();
  data_.u.t_string.ptr = static_cast<char *>(malloc(data_.u.t_string.len));

  if (data_.u.t_string.ptr == nullptr) {
    RAISE(kRuntimeError, "could not allocate SValue");
  }

  memcpy(
      data_.u.t_string.ptr,
      string_value.c_str(),
      data_.u.t_string.len);
}

SValue::SValue(
    char const* string_value) :
    SValue(std::string(string_value)) {}

SValue::SValue(SValue::IntegerType integer_value) {
  data_.type = T_INTEGER;
  data_.u.t_integer = integer_value;
}

SValue::SValue(SValue::FloatType float_value) {
  data_.type = T_FLOAT;
  data_.u.t_float = float_value;
}

SValue::SValue(SValue::BoolType bool_value) {
  data_.type = T_BOOL;
  data_.u.t_bool = bool_value;
}

SValue::SValue(SValue::TimeType time_value) {
  data_.type = T_TIMESTAMP;
  data_.u.t_timestamp = static_cast<uint64_t>(time_value);
}

SValue::SValue(const SValue& copy) {
  switch (copy.data_.type) {

    case T_STRING:
      data_.type = T_STRING;
      data_.u.t_string.len = copy.data_.u.t_string.len;
      data_.u.t_string.ptr = static_cast<char *>(malloc(data_.u.t_string.len));

      if (data_.u.t_string.ptr == nullptr) {
        RAISE(kRuntimeError, "could not allocate SValue");
      }

      memcpy(
          data_.u.t_string.ptr,
          copy.data_.u.t_string.ptr,
          data_.u.t_string.len);

    default:
      memcpy(&data_, &copy.data_, sizeof(data_));
      break;

  }

}

SValue& SValue::operator=(const SValue& copy) {
  // FIXPAUL free old string!

  switch (copy.data_.type) {

    case T_STRING:
      data_.type = T_STRING;
      data_.u.t_string.len = copy.data_.u.t_string.len;
      data_.u.t_string.ptr = static_cast<char *>(malloc(data_.u.t_string.len));

      if (data_.u.t_string.ptr == nullptr) {
        RAISE(kRuntimeError, "could not allocate SValue");
      }

      memcpy(
          data_.u.t_string.ptr,
          copy.data_.u.t_string.ptr,
          data_.u.t_string.len);

    default:
      memcpy(&data_, &copy.data_, sizeof(data_));
      break;

  }

  return *this;
}

bool SValue::operator==(const SValue& other) const {
  if (data_.type != other.data_.type) {
    return false;
  }

  switch (data_.type) {
    case T_STRING:
      return memcmp(
          data_.u.t_string.ptr,
          other.data_.u.t_string.ptr,
          data_.u.t_string.len) == 0;

    default:
      return memcmp(&data_, &other.data_, sizeof(data_)) == 0;

  }
}

SValue::kSValueType SValue::getType() const {
  return data_.type;
}

SValue::IntegerType SValue::getInteger() const {
  switch (data_.type) {

    case T_INTEGER:
      return data_.u.t_integer;

    case T_TIMESTAMP:
      return data_.u.t_timestamp;

    case T_STRING:
      try {
        return std::stol(getString());
      } catch (std::exception e) {
        /* fallthrough */
      }

    default:
      RAISE(
          kTypeError,
          "can't convert %s '%s' to Integer",
          SValue::getTypeName(data_.type),
          toString().c_str());

  }

  return 0;
}

SValue::FloatType SValue::getFloat() const {
  switch (data_.type) {

    case T_INTEGER:
      return data_.u.t_integer;

    case T_FLOAT:
      return data_.u.t_float;

    case T_STRING:
      try {
        return std::stod(getString());
      } catch (std::exception e) {
        /* fallthrough */
      }

    default:
      RAISE(
          kTypeError,
          "can't convert %s '%s' to Float",
          SValue::getTypeName(data_.type),
          toString().c_str());

  }

  return 0;
}

SValue::BoolType SValue::getBool() const {
  if (data_.type != T_BOOL) {
    RAISE(
       kTypeError,
        "can't convert %s '%s' to Bool",
        SValue::getTypeName(data_.type),
        toString().c_str());
  }

  return data_.u.t_bool;
}

SValue::BoolType SValue::getBoolWithConversion() const {
  switch (data_.type) {

    case T_INTEGER:
      return getInteger() > 0;

    case T_FLOAT:
      return getFloat() > 0;

    case T_BOOL:
      return getBool();

    case T_STRING:
      return true;

    case T_NULL:
      return false;

    default:
      RAISEF(
         kTypeError,
          "can't convert $0 '$1' to Boolean",
          SValue::getTypeName(data_.type),
          toString());

  }
}

SValue::TimeType SValue::getTimestamp() const {
  switch (getType()) {

    case T_TIMESTAMP:
      return data_.u.t_timestamp;

    default:
      RAISE(
         kTypeError,
          "can't convert %s '%s' to Timestamp",
          SValue::getTypeName(data_.type),
          toString().c_str());

  }
}

SValue::StringType SValue::getString() const {
  if (data_.type == T_STRING) {
    return std::string(data_.u.t_string.ptr, data_.u.t_string.len);
  } else {
    return toString();
  }
}

std::string SValue::makeUniqueKey(SValue* arr, size_t len) {
  std::string key;

  for (int i = 0; i < len; ++i) {
    key.append(arr[i].toString());
    key.append("\x00");
  }

  return key;
}

std::string SValue::toString() const {
  char buf[512];
  const char* str;
  size_t len;

  switch (data_.type) {

    case T_INTEGER: {
      len = snprintf(buf, sizeof(buf), "%" PRId64, getInteger());
      str = buf;
      break;
    }

    case T_TIMESTAMP: {
      return getTimestamp().toString("%Y-%m-%d %H:%M:%S");
    }

    case T_FLOAT: {
      len = snprintf(buf, sizeof(buf), "%f", getFloat());
      str = buf;
      break;
    }

    case T_BOOL: {
      static const auto true_str = "true";
      static const auto false_str = "false";
      if (getBool()) {
        str = true_str;
        len = strlen(true_str);
      } else {
        str = false_str;
        len = strlen(false_str);
      }
      break;
    }

    case T_STRING: {
      return getString();
    }

    case T_NULL: {
      static const char undef_str[] = "NULL";
      str = undef_str;
      len = sizeof(undef_str) - 1;
    }

  }

  return std::string(str, len);
}

const char* SValue::getTypeName(kSValueType type) {
  switch (type) {
    case T_STRING:
      return "String";
    case T_FLOAT:
      return "Float";
    case T_INTEGER:
      return "Integer";
    case T_BOOL:
      return "Boolean";
    case T_TIMESTAMP:
      return "Timestamp";
    case T_NULL:
      return "NULL";
  }
}

const char* SValue::getTypeName() const {
  return SValue::getTypeName(data_.type);
}

template <> SValue::BoolType SValue::getValue<SValue::BoolType>() const {
  return getBool();
}

template <> SValue::IntegerType SValue::getValue<SValue::IntegerType>() const {
  return getInteger();
}

template <> SValue::FloatType SValue::getValue<SValue::FloatType>() const {
  return getFloat();
}

template <> SValue::StringType SValue::getValue<SValue::StringType>() const {
  return toString();
}

template <> SValue::TimeType SValue::getValue<SValue::TimeType>() const {
  return getTimestamp();
}

// FIXPAUL: smarter type detection
template <> bool SValue::testType<SValue::BoolType>() const {
  return data_.type == T_BOOL;
}

template <> bool SValue::testType<SValue::TimeType>() const {
  return data_.type == T_TIMESTAMP;
}

template <> bool SValue::testType<SValue::IntegerType>() const {
  if (data_.type == T_INTEGER) {
    return true;
  }

  auto str = toString();
  const char* cur = str.c_str();
  const char* end = cur + str.size();

  if (*cur == '-') {
    ++cur;
  }

  if (cur == end) {
    return false;
  }

  for (; cur < end; ++cur) {
    if (*cur < '0' || *cur > '9') {
      return false;
    }
  }

  return true;
}

template <> bool SValue::testType<SValue::FloatType>() const {
  if (data_.type == T_FLOAT) {
    return true;
  }

  auto str = toString();
  bool dot = false;
  const char* c = str.c_str();

  if (*c == '-') {
    ++c;
  }

  for (; *c != 0; ++c) {
    if (*c >= '0' && *c <= '9') {
      continue;
    }

    if (*c == '.' || *c == ',') {
      if (dot) {
        return false;
      } else {
        dot = true;
      }
      continue;
    }

    return false;
  }

  return true;
}

template <> bool SValue::testType<std::string>() const {
  return true;
}

SValue::kSValueType SValue::testTypeWithNumericConversion() const {
  if (testType<SValue::IntegerType>()) return T_INTEGER;
  if (testType<SValue::FloatType>()) return T_FLOAT;
  return getType();
}

bool SValue::tryNumericConversion() {
  if (testType<SValue::IntegerType>()) {
    SValue::IntegerType val = getValue<SValue::IntegerType>();
    data_.type = T_INTEGER;
    data_.u.t_integer = val;
    return true;
  }

  if (testType<SValue::FloatType>()) {
    SValue::FloatType val = getValue<SValue::FloatType>();
    data_.type = T_FLOAT;
    data_.u.t_float = val;
    return true;
  }

  return false;
}

bool SValue::tryTimeConversion() {
  if (!tryNumericConversion()) {
    return false;
  }

  time_t ts = getInteger();
  data_.type = T_TIMESTAMP;
  // FIXPAUL take a smart guess if this is milli, micro, etc
  data_.u.t_timestamp = ts * 1000000llu;
  return true;
}

}

namespace fnord {

template <>
std::string inspect<csql::SValue::kSValueType>(
    const csql::SValue::kSValueType& type) {
  return csql::SValue::getTypeName(type);
}

template <>
std::string inspect<csql::SValue>(
    const csql::SValue& sval) {
  return sval.toString();
}

}

namespace std {

size_t hash<csql::SValue>::operator()(const csql::SValue& sval) const {
  return hash<std::string>()(sval.toString()); // FIXPAUL
}

}
<|endoftext|>


<commit_before>/*
 * THE NEW CHRONOTEXT TOOLKIT: https://github.com/arielm/new-chronotext-toolkit
 * COPYRIGHT (C) 2012-2014, ARIEL MALKA ALL RIGHTS RESERVED.
 *
 * THE FOLLOWING SOURCE-CODE IS DISTRIBUTED UNDER THE SIMPLIFIED BSD LICENSE:
 * https://github.com/arielm/new-chronotext-toolkit/blob/master/LICENSE.md
 */

#include "Log.h"

#include "cinder/Cinder.h"

#if defined(CINDER_MSW)

#include "cinder/msw/OutputDebugStringStream.h"

#elif defined(CINDER_ANDROID)

#include "cinder/android/LogStream.h"

#elif defined(CINDER_MAC) && defined(FORCE_SYSLOG)

#include "chronotext/utils/SyslogStringStream.h"

#endif

#include <mutex>

using namespace std;
using namespace ci;

namespace chr
{
    ostream& Log::cout()
    {
#if defined(CINDER_MSW)
        static ci::msw::dostream COUT;
        return COUT;
#elif defined(CINDER_ANDROID)
        static ci::android::dostream COUT;
        return COUT;
#elif defined(CINDER_MAC) && defined(FORCE_SYSLOG)
        static ci::mac::dostream COUT;
        return COUT;
#else
        return std::cout;
#endif
    }

    Log::~Log()
    {
        static mutex _mutex;
        lock_guard<mutex> lock(_mutex);

        Log::cout() << ss.rdbuf() << std::flush;
    }

    Log& Log::operator<<(ostream_manipulator manip)
    {
        ss << manip;
        return *this;
    }
}
<commit_msg>develop: FIXING LOG ISSUE<commit_after>/*
 * THE NEW CHRONOTEXT TOOLKIT: https://github.com/arielm/new-chronotext-toolkit
 * COPYRIGHT (C) 2012-2014, ARIEL MALKA ALL RIGHTS RESERVED.
 *
 * THE FOLLOWING SOURCE-CODE IS DISTRIBUTED UNDER THE SIMPLIFIED BSD LICENSE:
 * https://github.com/arielm/new-chronotext-toolkit/blob/master/LICENSE.md
 */

#include "Log.h"

#include "cinder/Cinder.h"

#if defined(CINDER_MSW)

#include "cinder/msw/OutputDebugStringStream.h"

#elif defined(CINDER_ANDROID)

#include "cinder/android/LogStream.h"

#elif defined(CINDER_MAC) && defined(FORCE_SYSLOG)

#include "chronotext/utils/SyslogStringStream.h"

#endif

#include <mutex>

using namespace std;
using namespace ci;

namespace chr
{
    ostream& Log::cout()
    {
#if defined(CINDER_MSW)
        static ci::msw::dostream COUT;
        return COUT;
#elif defined(CINDER_ANDROID)
        static ci::android::dostream COUT;
        return COUT;
#elif defined(CINDER_MAC) && defined(FORCE_SYSLOG)
        static chr::mac::dostream COUT;
        return COUT;
#else
        return std::cout;
#endif
    }

    Log::~Log()
    {
        static mutex _mutex;
        lock_guard<mutex> lock(_mutex);

        Log::cout() << ss.rdbuf() << std::flush;
    }

    Log& Log::operator<<(ostream_manipulator manip)
    {
        ss << manip;
        return *this;
    }
}
<|endoftext|>