<commit_before>/*
 * Copyright (c) 2000-2004 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

///
/// @file sim/main.cc
///
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <signal.h>

#include <list>
#include <string>
#include <vector>

#include "base/copyright.hh"
#include "base/embedfile.hh"
#include "base/inifile.hh"
#include "base/misc.hh"
#include "base/output.hh"
#include "base/pollevent.hh"
#include "base/statistics.hh"
#include "base/str.hh"
#include "base/time.hh"
#include "cpu/base_cpu.hh"
#include "cpu/full_cpu/smt.hh"
#include "python/pyconfig.hh"
#include "sim/async.hh"
#include "sim/builder.hh"
#include "sim/configfile.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"
#include "sim/stat_control.hh"
#include "sim/stats.hh"
#include "sim/root.hh"

using namespace std;

// See async.h.
volatile bool async_event = false;
volatile bool async_dump = false;
volatile bool async_dumpreset = false;
volatile bool async_exit = false;
volatile bool async_io = false;
volatile bool async_alarm = false;

/// Stats signal handler.
void
dumpStatsHandler(int sigtype)
{
    async_event = true;
    async_dump = true;
}

void
dumprstStatsHandler(int sigtype)
{
    async_event = true;
    async_dumpreset = true;
}

/// Exit signal handler.
void
exitNowHandler(int sigtype)
{
    async_event = true;
    async_exit = true;
}

/// Abort signal handler.
void
abortHandler(int sigtype)
{
    cerr << "Program aborted at cycle " << curTick << endl;

#if TRACING_ON
    // dump trace buffer, if there is one
    Trace::theLog.dump(cerr);
#endif
}

/// Simulator executable name
char *myProgName = "";

/// Show brief help message.
void
showBriefHelp(ostream &out)
{
    char *prog = basename(myProgName);

    ccprintf(out, "Usage:\n");
    ccprintf(out,
"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n"
"        [--<var>=<val>] <config file>\n"
"\n"
"   -d            set the output directory to <dir>\n"
"   -E            set the environment variable <var> to <val> (or 'True')\n"
"   -I            add the directory <dir> to python's path\n"
"   -P            execute <python> directly in the configuration\n"
"   --var=val     set the python variable <var> to '<val>'\n"
"   <configfile>  config file name (ends in .py)\n\n",
             prog);

    ccprintf(out, "%s -X\n   -X            extract embedded files\n\n", prog);
    ccprintf(out, "%s -h\n   -h            print short help\n\n", prog);
    ccprintf(out, "%s -H\n   -H            print long help\n\n", prog);
}

/// Show verbose help message.  Includes parameter listing from
/// showBriefHelp(), plus an exhaustive list of ini-file parameters
/// and SimObjects (with their parameters).
void
showLongHelp(ostream &out)
{
    showBriefHelp(out);

    out << endl
        << endl
        << "-----------------" << endl
        << "Global Parameters" << endl
        << "-----------------" << endl
        << endl;

    ParamContext::describeAllContexts(out);

    out << endl
        << endl
        << "-----------------" << endl
        << "Simulator Objects" << endl
        << "-----------------" << endl
        << endl;

    SimObjectClass::describeAllClasses(out);
}

/// Print welcome message.
void
sayHello(ostream &out)
{
    extern const char *compileDate;	// from date.cc

    ccprintf(out, "M5 Simulator System\n");
    // display copyright
    ccprintf(out, "%s\n", briefCopyright);
    ccprintf(out, "M5 compiled on %d\n", compileDate);

    char *host = getenv("HOSTNAME");
    if (!host)
        host = getenv("HOST");

    if (host)
        ccprintf(out, "M5 executing on %s\n", host);

    ccprintf(out, "M5 simulation started %s\n", Time::start);
}

///
/// Echo the command line for posterity in such a way that it can be
/// used to rerun the same simulation (given the same .ini files).
///
void
echoCommandLine(int argc, char **argv, ostream &out)
{
    out << "command line: " << argv[0];
    for (int i = 1; i < argc; i++) {
        string arg(argv[i]);

        out << ' ';

        // If the arg contains spaces, we need to quote it.
        // The rest of this is overkill to make it look purty.

        // print dashes first outside quotes
        int non_dash_pos = arg.find_first_not_of("-");
        out << arg.substr(0, non_dash_pos);	// print dashes
        string body = arg.substr(non_dash_pos);	// the rest

        // if it's an assignment, handle the lhs & rhs separately
        int eq_pos = body.find("=");
        if (eq_pos == string::npos) {
            out << quote(body);
        }
        else {
            string lhs(body.substr(0, eq_pos));
            string rhs(body.substr(eq_pos + 1));

            out << quote(lhs) << "=" << quote(rhs);
        }
    }
    out << endl << endl;
}

char *
getOptionString(int &index, int argc, char **argv)
{
    char *option = argv[index] + 2;
    if (*option != '\0')
        return option;

    // We didn't find an argument, it must be in the next variable.
    if (++index >= argc)
        panic("option string for option '%s' not found", argv[index - 1]);

    return argv[index];
}

int
main(int argc, char **argv)
{
    // Save off program name
    myProgName = argv[0];

    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
    signal(SIGTRAP, SIG_IGN);
    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
    signal(SIGINT, exitNowHandler);		// dump final stats and exit
    signal(SIGABRT, abortHandler);

    bool configfile_found = false;
    PythonConfig pyconfig;
    string outdir;

    if (argc < 2) {
        showBriefHelp(cerr);
        exit(1);
    }

    sayHello(cerr);

    // Parse command-line options.
    // Since most of the complex options are handled through the
    // config database, we don't mess with getopts, and just parse
    // manually.
    for (int i = 1; i < argc; ++i) {
        char *arg_str = argv[i];

        // if arg starts with '--', parse as a special python option
        // of the format --<python var>=<string value>, if the arg
        // starts with '-', it should be a simulator option with a
        // format similar to getopt.  In any other case, treat the
        // option as a configuration file name and load it.
        if (arg_str[0] == '-' && arg_str[1] == '-') {
            string str = &arg_str[2];
            string var, val;

            if (!split_first(str, var, val, '='))
                panic("Could not parse configuration argument '%s'\n"
                      "Expecting --<variable>=<value>\n", arg_str);

            pyconfig.setVariable(var, val);
        } else if (arg_str[0] == '-') {
            char *option;
            string var, val;

            // switch on second char
            switch (arg_str[1]) {
              case 'd':
                outdir = getOptionString(i, argc, argv);
                break;

              case 'h':
                showBriefHelp(cerr);
                exit(1);

              case 'H':
                showLongHelp(cerr);
                exit(1);

              case 'E':
                option = getOptionString(i, argc, argv);
                if (!split_first(option, var, val, '='))
                    val = "True";

                if (setenv(var.c_str(), val.c_str(), true) == -1)
                    panic("setenv: %s\n", strerror(errno));
                break;

              case 'I':
                option = getOptionString(i, argc, argv);
                pyconfig.addPath(option);
                break;

              case 'P':
                option = getOptionString(i, argc, argv);
                pyconfig.writeLine(option);
                break;

              case 'X': {
                  list<EmbedFile> lst;
                  EmbedMap::all(lst);
                  list<EmbedFile>::iterator i = lst.begin();
                  list<EmbedFile>::iterator end = lst.end();

                  while (i != end) {
                      cprintf("Embedded File: %s\n", i->name);
                      cout.write(i->data, i->length);
                      ++i;
                  }

                  return 0;
              }

              default:
                showBriefHelp(cerr);
                panic("invalid argument '%s'\n", arg_str);
            }
        } else {
            string file(arg_str);
            string base, ext;

            if (!split_last(file, base, ext, '.') || ext != "py")
                panic("Config file '%s' must end in '.py'\n", file);

            pyconfig.load(file);
            configfile_found = true;
        }
    }

    if (outdir.empty()) {
        char *env = getenv("OUTPUT_DIR");
        outdir = env ? env : ".";
    }

    simout.setDirectory(outdir);

    char *env = getenv("CONFIG_OUTPUT");
    if (!env)
        env = "config.out";
    configStream = simout.find(env);

    if (!configfile_found)
        panic("no configuration file specified!");

    // The configuration database is now complete; start processing it.
    IniFile inifile;
    if (!pyconfig.output(inifile))
        panic("Error processing python code");

    // Initialize statistics database
    Stats::InitSimStats();

    // Now process the configuration hierarchy and create the SimObjects.
    ConfigHierarchy configHierarchy(inifile);
    configHierarchy.build();
    configHierarchy.createSimObjects();

    // Parse and check all non-config-hierarchy parameters.
    ParamContext::parseAllContexts(inifile);
    ParamContext::checkAllContexts();

    // Print hello message to stats file if it's actually a file.  If
    // it's not (i.e. it's cout or cerr) then we already did it above.
    if (simout.isFile(*outputStream))
        sayHello(*outputStream);

    // Echo command line and all parameter settings to stats file as well.
    echoCommandLine(argc, argv, *outputStream);
    ParamContext::showAllContexts(*configStream);

    // Do a second pass to finish initializing the sim objects
    SimObject::initAll();

    // Restore checkpointed state, if any.
    configHierarchy.unserializeSimObjects();

    // Done processing the configuration database.
    // Check for unreferenced entries.
    if (inifile.printUnreferenced())
        panic("unreferenced sections/entries in the intermediate ini file");

    SimObject::regAllStats();

    // uncomment the following to get PC-based execution-time profile
#ifdef DO_PROFILE
    init_profile((char *)&_init, (char *)&_fini);
#endif

    // Check to make sure that the stats package is properly initialized
    Stats::check();

    // Reset to put the stats in a consistent state.
    Stats::reset();

    warn("Entering event queue.  Starting simulation...\n");
    SimStartup();
    while (!mainEventQueue.empty()) {
        assert(curTick <= mainEventQueue.nextTick() &&
               "event scheduled in the past");

        // forward current cycle to the time of the first event on the
        // queue
        curTick = mainEventQueue.nextTick();
        mainEventQueue.serviceOne();

        if (async_event) {
            async_event = false;
            if (async_dump) {
                async_dump = false;

                using namespace Stats;
                SetupEvent(Dump, curTick);
            }

            if (async_dumpreset) {
                async_dumpreset = false;

                using namespace Stats;
                SetupEvent(Dump | Reset, curTick);
            }

            if (async_exit) {
                async_exit = false;
                new SimExitEvent("User requested STOP");
            }

            if (async_io || async_alarm) {
                async_io = false;
                async_alarm = false;
                pollQueue.service();
            }
        }
    }

    // This should never happen... every conceivable way for the
    // simulation to terminate (hit max cycles/insts, signal,
    // simulated system halts/exits) generates an exit event, so we
    // should never run out of events on the queue.
    exitNow("no events on event loop!  All CPUs must be idle.", 1);

    return 0;
}
<commit_msg>Get rid of broken "long help" option.<commit_after>/*
 * Copyright (c) 2000-2004 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

///
/// @file sim/main.cc
///
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <signal.h>

#include <list>
#include <string>
#include <vector>

#include "base/copyright.hh"
#include "base/embedfile.hh"
#include "base/inifile.hh"
#include "base/misc.hh"
#include "base/output.hh"
#include "base/pollevent.hh"
#include "base/statistics.hh"
#include "base/str.hh"
#include "base/time.hh"
#include "cpu/base_cpu.hh"
#include "cpu/full_cpu/smt.hh"
#include "python/pyconfig.hh"
#include "sim/async.hh"
#include "sim/builder.hh"
#include "sim/configfile.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"
#include "sim/stat_control.hh"
#include "sim/stats.hh"
#include "sim/root.hh"

using namespace std;

// See async.h.
volatile bool async_event = false;
volatile bool async_dump = false;
volatile bool async_dumpreset = false;
volatile bool async_exit = false;
volatile bool async_io = false;
volatile bool async_alarm = false;

/// Stats signal handler.
void
dumpStatsHandler(int sigtype)
{
    async_event = true;
    async_dump = true;
}

void
dumprstStatsHandler(int sigtype)
{
    async_event = true;
    async_dumpreset = true;
}

/// Exit signal handler.
void
exitNowHandler(int sigtype)
{
    async_event = true;
    async_exit = true;
}

/// Abort signal handler.
void
abortHandler(int sigtype)
{
    cerr << "Program aborted at cycle " << curTick << endl;

#if TRACING_ON
    // dump trace buffer, if there is one
    Trace::theLog.dump(cerr);
#endif
}

/// Simulator executable name
char *myProgName = "";

/// Show brief help message.
void
showBriefHelp(ostream &out)
{
    char *prog = basename(myProgName);

    ccprintf(out, "Usage:\n");
    ccprintf(out,
"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n"
"        [--<var>=<val>] <config file>\n"
"\n"
"   -d            set the output directory to <dir>\n"
"   -E            set the environment variable <var> to <val> (or 'True')\n"
"   -I            add the directory <dir> to python's path\n"
"   -P            execute <python> directly in the configuration\n"
"   --var=val     set the python variable <var> to '<val>'\n"
"   <configfile>  config file name (ends in .py)\n\n",
             prog);

    ccprintf(out, "%s -X\n   -X            extract embedded files\n\n", prog);
    ccprintf(out, "%s -h\n   -h            print short help\n\n", prog);
}

/// Print welcome message.
void
sayHello(ostream &out)
{
    extern const char *compileDate;	// from date.cc

    ccprintf(out, "M5 Simulator System\n");
    // display copyright
    ccprintf(out, "%s\n", briefCopyright);
    ccprintf(out, "M5 compiled on %d\n", compileDate);

    char *host = getenv("HOSTNAME");
    if (!host)
        host = getenv("HOST");

    if (host)
        ccprintf(out, "M5 executing on %s\n", host);

    ccprintf(out, "M5 simulation started %s\n", Time::start);
}

///
/// Echo the command line for posterity in such a way that it can be
/// used to rerun the same simulation (given the same .ini files).
///
void
echoCommandLine(int argc, char **argv, ostream &out)
{
    out << "command line: " << argv[0];
    for (int i = 1; i < argc; i++) {
        string arg(argv[i]);

        out << ' ';

        // If the arg contains spaces, we need to quote it.
        // The rest of this is overkill to make it look purty.

        // print dashes first outside quotes
        int non_dash_pos = arg.find_first_not_of("-");
        out << arg.substr(0, non_dash_pos);	// print dashes
        string body = arg.substr(non_dash_pos);	// the rest

        // if it's an assignment, handle the lhs & rhs separately
        int eq_pos = body.find("=");
        if (eq_pos == string::npos) {
            out << quote(body);
        }
        else {
            string lhs(body.substr(0, eq_pos));
            string rhs(body.substr(eq_pos + 1));

            out << quote(lhs) << "=" << quote(rhs);
        }
    }
    out << endl << endl;
}

char *
getOptionString(int &index, int argc, char **argv)
{
    char *option = argv[index] + 2;
    if (*option != '\0')
        return option;

    // We didn't find an argument, it must be in the next variable.
    if (++index >= argc)
        panic("option string for option '%s' not found", argv[index - 1]);

    return argv[index];
}

int
main(int argc, char **argv)
{
    // Save off program name
    myProgName = argv[0];

    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
    signal(SIGTRAP, SIG_IGN);
    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
    signal(SIGINT, exitNowHandler);		// dump final stats and exit
    signal(SIGABRT, abortHandler);

    bool configfile_found = false;
    PythonConfig pyconfig;
    string outdir;

    if (argc < 2) {
        showBriefHelp(cerr);
        exit(1);
    }

    sayHello(cerr);

    // Parse command-line options.
    // Since most of the complex options are handled through the
    // config database, we don't mess with getopts, and just parse
    // manually.
    for (int i = 1; i < argc; ++i) {
        char *arg_str = argv[i];

        // if arg starts with '--', parse as a special python option
        // of the format --<python var>=<string value>, if the arg
        // starts with '-', it should be a simulator option with a
        // format similar to getopt.  In any other case, treat the
        // option as a configuration file name and load it.
        if (arg_str[0] == '-' && arg_str[1] == '-') {
            string str = &arg_str[2];
            string var, val;

            if (!split_first(str, var, val, '='))
                panic("Could not parse configuration argument '%s'\n"
                      "Expecting --<variable>=<value>\n", arg_str);

            pyconfig.setVariable(var, val);
        } else if (arg_str[0] == '-') {
            char *option;
            string var, val;

            // switch on second char
            switch (arg_str[1]) {
              case 'd':
                outdir = getOptionString(i, argc, argv);
                break;

              case 'h':
                showBriefHelp(cerr);
                exit(1);

              case 'E':
                option = getOptionString(i, argc, argv);
                if (!split_first(option, var, val, '='))
                    val = "True";

                if (setenv(var.c_str(), val.c_str(), true) == -1)
                    panic("setenv: %s\n", strerror(errno));
                break;

              case 'I':
                option = getOptionString(i, argc, argv);
                pyconfig.addPath(option);
                break;

              case 'P':
                option = getOptionString(i, argc, argv);
                pyconfig.writeLine(option);
                break;

              case 'X': {
                  list<EmbedFile> lst;
                  EmbedMap::all(lst);
                  list<EmbedFile>::iterator i = lst.begin();
                  list<EmbedFile>::iterator end = lst.end();

                  while (i != end) {
                      cprintf("Embedded File: %s\n", i->name);
                      cout.write(i->data, i->length);
                      ++i;
                  }

                  return 0;
              }

              default:
                showBriefHelp(cerr);
                panic("invalid argument '%s'\n", arg_str);
            }
        } else {
            string file(arg_str);
            string base, ext;

            if (!split_last(file, base, ext, '.') || ext != "py")
                panic("Config file '%s' must end in '.py'\n", file);

            pyconfig.load(file);
            configfile_found = true;
        }
    }

    if (outdir.empty()) {
        char *env = getenv("OUTPUT_DIR");
        outdir = env ? env : ".";
    }

    simout.setDirectory(outdir);

    char *env = getenv("CONFIG_OUTPUT");
    if (!env)
        env = "config.out";
    configStream = simout.find(env);

    if (!configfile_found)
        panic("no configuration file specified!");

    // The configuration database is now complete; start processing it.
    IniFile inifile;
    if (!pyconfig.output(inifile))
        panic("Error processing python code");

    // Initialize statistics database
    Stats::InitSimStats();

    // Now process the configuration hierarchy and create the SimObjects.
    ConfigHierarchy configHierarchy(inifile);
    configHierarchy.build();
    configHierarchy.createSimObjects();

    // Parse and check all non-config-hierarchy parameters.
    ParamContext::parseAllContexts(inifile);
    ParamContext::checkAllContexts();

    // Print hello message to stats file if it's actually a file.  If
    // it's not (i.e. it's cout or cerr) then we already did it above.
    if (simout.isFile(*outputStream))
        sayHello(*outputStream);

    // Echo command line and all parameter settings to stats file as well.
    echoCommandLine(argc, argv, *outputStream);
    ParamContext::showAllContexts(*configStream);

    // Do a second pass to finish initializing the sim objects
    SimObject::initAll();

    // Restore checkpointed state, if any.
    configHierarchy.unserializeSimObjects();

    // Done processing the configuration database.
    // Check for unreferenced entries.
    if (inifile.printUnreferenced())
        panic("unreferenced sections/entries in the intermediate ini file");

    SimObject::regAllStats();

    // uncomment the following to get PC-based execution-time profile
#ifdef DO_PROFILE
    init_profile((char *)&_init, (char *)&_fini);
#endif

    // Check to make sure that the stats package is properly initialized
    Stats::check();

    // Reset to put the stats in a consistent state.
    Stats::reset();

    warn("Entering event queue.  Starting simulation...\n");
    SimStartup();
    while (!mainEventQueue.empty()) {
        assert(curTick <= mainEventQueue.nextTick() &&
               "event scheduled in the past");

        // forward current cycle to the time of the first event on the
        // queue
        curTick = mainEventQueue.nextTick();
        mainEventQueue.serviceOne();

        if (async_event) {
            async_event = false;
            if (async_dump) {
                async_dump = false;

                using namespace Stats;
                SetupEvent(Dump, curTick);
            }

            if (async_dumpreset) {
                async_dumpreset = false;

                using namespace Stats;
                SetupEvent(Dump | Reset, curTick);
            }

            if (async_exit) {
                async_exit = false;
                new SimExitEvent("User requested STOP");
            }

            if (async_io || async_alarm) {
                async_io = false;
                async_alarm = false;
                pollQueue.service();
            }
        }
    }

    // This should never happen... every conceivable way for the
    // simulation to terminate (hit max cycles/insts, signal,
    // simulated system halts/exits) generates an exit event, so we
    // should never run out of events on the queue.
    exitNow("no events on event loop!  All CPUs must be idle.", 1);

    return 0;
}
<|endoftext|>


<commit_before>/*=============================================================================
  NiftyLink:  A software library to facilitate communication over OpenIGTLink.

  Copyright (c) University College London (UCL). All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  See LICENSE.txt in the top level directory for details.
=============================================================================*/

#include "OIGTLMessage.h"

#include "QsLog.h"
#include "QsLogDest.h"
#include "NiftyLinkUtils.h"

OIGTLMessage::OIGTLMessage(void)
{
  m_timeCreated = igtl::TimeStamp::New();
  m_timeCreated->GetTime();
  m_senderPort = -1;
  m_senderHostName = QString("localhost");
  m_id = GetTimeInNanoSeconds(m_timeCreated);

  //m_timeCreated = NULL;
  m_resolution = 0;
  m_processed  = 0;
  m_ownerName.append("!");
}

OIGTLMessage::~OIGTLMessage(void)
{
  //QLOG_INFO() <<"Message destructor (Base class): "<<m_ownerName <<m_id;

  m_message.operator =(NULL);
  m_timeReceived.operator =(NULL);
  m_timeCreated.operator =(NULL);
}

OIGTLMessage::OIGTLMessage(const OIGTLMessage &other)
	: QSharedData(other)
{
  // Copy constructor
	m_message.operator     =(other.m_message);
	m_timeReceived.operator=(other.m_timeReceived);

	m_senderHostName       = other.m_senderHostName;
	m_messageType          = other.m_messageType;
	m_senderPort           = other.m_senderPort;

	m_resolution           = other.m_resolution;
	m_id                   = other.m_id;

  m_ownerName            = other.m_ownerName;
}

void OIGTLMessage::setMessagePointer(igtl::MessageBase::Pointer mp)
{
  // Embeds the OpenIGTLink message pointer into the message
	m_message.operator =(mp);
	m_messageType = QString(m_message->GetDeviceType());
	m_message->GetTimeStamp(m_timeCreated);
	m_senderHostName = QString(m_message->GetDeviceName());
}

void OIGTLMessage::getMessagePointer(igtl::MessageBase::Pointer &mp)
{
	mp.operator = (m_message);
}

void OIGTLMessage::setTimeReceived(igtl::TimeStamp::Pointer ts)
{
	m_timeReceived.operator=(ts);
}

igtl::TimeStamp::Pointer OIGTLMessage::getTimeReceived(void)
{
	return m_timeReceived;
}

igtl::TimeStamp::Pointer OIGTLMessage::getTimeCreated(void)
{
	return m_timeCreated;
}

igtlUint64 OIGTLMessage::getId(void)
{
	return m_id;
}

void OIGTLMessage::changeHostName(QString hname)
{
  if (m_message.IsNull())
    return;

  m_senderHostName = hname;

  m_message->Unpack();

  m_message->SetDeviceName(m_senderHostName.toStdString().c_str());

  m_message->Pack();
}

QString OIGTLMessage::getHostName(void)
{
  if (m_message.IsNull())
    return QString();

  m_message->Unpack();

  m_senderHostName = m_message->GetDeviceName();

  m_message->Pack();

	return m_senderHostName;
}

void OIGTLMessage::setPort(int port)
{
	m_senderPort = port;
}

int OIGTLMessage::getPort(void)
{
	return m_senderPort;
}

void OIGTLMessage::changeMessageType(QString type)
{
	m_messageType = type;
}

QString OIGTLMessage::getMessageType(void)
{
	return m_messageType;
}

void OIGTLMessage::setResolution(igtlUint64 res)
{
  // This is to set the streaming frequency
	m_resolution = res;

	if (m_message.IsNull())
		return;

  QString className(m_message->GetNameOfClass());

  if (!className.contains("Start"))
    return;

	m_message->Unpack();

	if (strcmp(m_message->GetNameOfClass(), "igtl::StartTransformMessage") == 0)
	{
		igtl::StartTransformMessage::Pointer pointer = static_cast<igtl::StartTransformMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartTrajectoryMessage") == 0)
	{
		igtl::StartTrajectoryMessage::Pointer pointer = static_cast<igtl::StartTrajectoryMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartTrackingDataMessage") == 0)
	{
		igtl::StartTrackingDataMessage::Pointer pointer = static_cast<igtl::StartTrackingDataMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartStringMessage") == 0)
	{
		igtl::StartStringMessage::Pointer pointer = static_cast<igtl::StartStringMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartStatusMessage") == 0)
	{
		igtl::StartStatusMessage::Pointer pointer = static_cast<igtl::StartStatusMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartQuaternionTrackingDataMessage") == 0)
	{
		igtl::StartQuaternionTrackingDataMessage::Pointer pointer = static_cast<igtl::StartQuaternionTrackingDataMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartPositionMessage") == 0)
	{
		igtl::StartPositionMessage::Pointer pointer = static_cast<igtl::StartPositionMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartPointMessage") == 0)
	{
		igtl::StartPointMessage::Pointer pointer = static_cast<igtl::StartPointMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartImageMessage") == 0)
	{
		igtl::StartImageMessage::Pointer pointer = static_cast<igtl::StartImageMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartBindMessage") == 0)
	{
		igtl::StartBindMessage::Pointer pointer = static_cast<igtl::StartBindMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}

	m_message->Pack();
}

void OIGTLMessage::getResolution(igtlUint64 &res)
{
	if (m_message.IsNull())
		return;

  QString className(m_message->GetNameOfClass());

  if (!className.contains("Start"))
    return;

	m_message->Unpack();

	if (strcmp(m_message->GetNameOfClass(), "igtl::StartTransformMessage") == 0)
	{
		igtl::StartTransformMessage::Pointer pointer = static_cast<igtl::StartTransformMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartTrajectoryMessage") == 0)
	{
		igtl::StartTrajectoryMessage::Pointer pointer = static_cast<igtl::StartTrajectoryMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartTrackingDataMessage") == 0)
	{
		igtl::StartTrackingDataMessage::Pointer pointer = static_cast<igtl::StartTrackingDataMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartStringMessage") == 0)
	{
		igtl::StartStringMessage::Pointer pointer = static_cast<igtl::StartStringMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartStatusMessage") == 0)
	{
		igtl::StartStatusMessage::Pointer pointer = static_cast<igtl::StartStatusMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartQuaternionTrackingDataMessage") == 0)
	{
		igtl::StartQuaternionTrackingDataMessage::Pointer pointer = static_cast<igtl::StartQuaternionTrackingDataMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartPositionMessage") == 0)
	{
		igtl::StartPositionMessage::Pointer pointer = static_cast<igtl::StartPositionMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartPointMessage") == 0)
	{
		igtl::StartPointMessage::Pointer pointer = static_cast<igtl::StartPointMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartImageMessage") == 0)
	{
		igtl::StartImageMessage::Pointer pointer = static_cast<igtl::StartImageMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartBindMessage") == 0)
	{
		igtl::StartBindMessage::Pointer pointer = static_cast<igtl::StartBindMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}

	m_message->Pack();

	res = m_resolution;
}

void OIGTLMessage::update(QString hostname, igtl::TimeStamp::Pointer ts)
{
  // Updates timestamp and hostname

  if (m_message.IsNull())
    return;

  m_timeCreated.operator =(ts);
  m_senderHostName = hostname;

  m_message->Unpack();

  m_message->SetTimeStamp(ts);
  m_message->SetDeviceName(m_senderHostName.toStdString().c_str());

  m_message->Pack();
}

void OIGTLMessage::update(QString hostname)
{
  // Updates timestamp and hostname

  if (m_message.IsNull())
    return;

  igtl::TimeStamp::Pointer ts;
  ts = igtl::TimeStamp::New();
  ts->GetTime_TAI();

  m_timeCreated.operator =(ts);
  m_senderHostName = hostname;
  m_id = GetTimeInNanoSeconds(ts);

  m_message->Unpack();

  m_message->SetTimeStamp(ts);
  m_message->SetDeviceName(m_senderHostName.toStdString().c_str());

  m_message->Pack();
}

void OIGTLMessage::setOwnerName(QString str)
  {
    if (!m_ownerName.isEmpty() && !m_ownerName.isNull())
      m_ownerName.clear();
    m_ownerName.append(str);
  }

<commit_msg>Bug #1967: Switch back to UTC as too many places create UTC timestamps<commit_after>/*=============================================================================
  NiftyLink:  A software library to facilitate communication over OpenIGTLink.

  Copyright (c) University College London (UCL). All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  See LICENSE.txt in the top level directory for details.
=============================================================================*/

#include "OIGTLMessage.h"

#include "QsLog.h"
#include "QsLogDest.h"
#include "NiftyLinkUtils.h"

OIGTLMessage::OIGTLMessage(void)
{
  m_timeCreated = igtl::TimeStamp::New();
  m_timeCreated->GetTime();
  m_senderPort = -1;

  m_senderHostName = QString("localhost");
  m_id = GetTimeInNanoSeconds(m_timeCreated);

  //m_timeCreated = NULL;
  m_resolution = 0;
  m_processed  = 0;
  m_ownerName.append("!");
}

OIGTLMessage::~OIGTLMessage(void)
{
  //QLOG_INFO() <<"Message destructor (Base class): "<<m_ownerName <<m_id;

  m_message.operator =(NULL);
  m_timeReceived.operator =(NULL);
  m_timeCreated.operator =(NULL);
}

OIGTLMessage::OIGTLMessage(const OIGTLMessage &other)
	: QSharedData(other)
{
  // Copy constructor
	m_message.operator     =(other.m_message);
	m_timeReceived.operator=(other.m_timeReceived);

	m_senderHostName       = other.m_senderHostName;
	m_messageType          = other.m_messageType;
	m_senderPort           = other.m_senderPort;

	m_resolution           = other.m_resolution;
	m_id                   = other.m_id;

  m_ownerName            = other.m_ownerName;
}

void OIGTLMessage::setMessagePointer(igtl::MessageBase::Pointer mp)
{
  // Embeds the OpenIGTLink message pointer into the message
	m_message.operator =(mp);
	m_messageType = QString(m_message->GetDeviceType());
	m_message->GetTimeStamp(m_timeCreated);
	m_senderHostName = QString(m_message->GetDeviceName());
}

void OIGTLMessage::getMessagePointer(igtl::MessageBase::Pointer &mp)
{
	mp.operator = (m_message);
}

void OIGTLMessage::setTimeReceived(igtl::TimeStamp::Pointer ts)
{
	m_timeReceived.operator=(ts);
}

igtl::TimeStamp::Pointer OIGTLMessage::getTimeReceived(void)
{
	return m_timeReceived;
}

igtl::TimeStamp::Pointer OIGTLMessage::getTimeCreated(void)
{
	return m_timeCreated;
}

igtlUint64 OIGTLMessage::getId(void)
{
	return m_id;
}

void OIGTLMessage::changeHostName(QString hname)
{
  if (m_message.IsNull())
    return;

  m_senderHostName = hname;

  m_message->Unpack();

  m_message->SetDeviceName(m_senderHostName.toStdString().c_str());

  m_message->Pack();
}

QString OIGTLMessage::getHostName(void)
{
  if (m_message.IsNull())
    return QString();

  m_message->Unpack();

  m_senderHostName = m_message->GetDeviceName();

  m_message->Pack();

	return m_senderHostName;
}

void OIGTLMessage::setPort(int port)
{
	m_senderPort = port;
}

int OIGTLMessage::getPort(void)
{
	return m_senderPort;
}

void OIGTLMessage::changeMessageType(QString type)
{
	m_messageType = type;
}

QString OIGTLMessage::getMessageType(void)
{
	return m_messageType;
}

void OIGTLMessage::setResolution(igtlUint64 res)
{
  // This is to set the streaming frequency
	m_resolution = res;

	if (m_message.IsNull())
		return;

  QString className(m_message->GetNameOfClass());

  if (!className.contains("Start"))
    return;

	m_message->Unpack();

	if (strcmp(m_message->GetNameOfClass(), "igtl::StartTransformMessage") == 0)
	{
		igtl::StartTransformMessage::Pointer pointer = static_cast<igtl::StartTransformMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartTrajectoryMessage") == 0)
	{
		igtl::StartTrajectoryMessage::Pointer pointer = static_cast<igtl::StartTrajectoryMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartTrackingDataMessage") == 0)
	{
		igtl::StartTrackingDataMessage::Pointer pointer = static_cast<igtl::StartTrackingDataMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartStringMessage") == 0)
	{
		igtl::StartStringMessage::Pointer pointer = static_cast<igtl::StartStringMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartStatusMessage") == 0)
	{
		igtl::StartStatusMessage::Pointer pointer = static_cast<igtl::StartStatusMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartQuaternionTrackingDataMessage") == 0)
	{
		igtl::StartQuaternionTrackingDataMessage::Pointer pointer = static_cast<igtl::StartQuaternionTrackingDataMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartPositionMessage") == 0)
	{
		igtl::StartPositionMessage::Pointer pointer = static_cast<igtl::StartPositionMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartPointMessage") == 0)
	{
		igtl::StartPointMessage::Pointer pointer = static_cast<igtl::StartPointMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartImageMessage") == 0)
	{
		igtl::StartImageMessage::Pointer pointer = static_cast<igtl::StartImageMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartBindMessage") == 0)
	{
		igtl::StartBindMessage::Pointer pointer = static_cast<igtl::StartBindMessage *>(m_message.GetPointer());
		pointer->SetResolution(res);
	}

	m_message->Pack();
}

void OIGTLMessage::getResolution(igtlUint64 &res)
{
	if (m_message.IsNull())
		return;

  QString className(m_message->GetNameOfClass());

  if (!className.contains("Start"))
    return;

	m_message->Unpack();

	if (strcmp(m_message->GetNameOfClass(), "igtl::StartTransformMessage") == 0)
	{
		igtl::StartTransformMessage::Pointer pointer = static_cast<igtl::StartTransformMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartTrajectoryMessage") == 0)
	{
		igtl::StartTrajectoryMessage::Pointer pointer = static_cast<igtl::StartTrajectoryMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartTrackingDataMessage") == 0)
	{
		igtl::StartTrackingDataMessage::Pointer pointer = static_cast<igtl::StartTrackingDataMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartStringMessage") == 0)
	{
		igtl::StartStringMessage::Pointer pointer = static_cast<igtl::StartStringMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartStatusMessage") == 0)
	{
		igtl::StartStatusMessage::Pointer pointer = static_cast<igtl::StartStatusMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartQuaternionTrackingDataMessage") == 0)
	{
		igtl::StartQuaternionTrackingDataMessage::Pointer pointer = static_cast<igtl::StartQuaternionTrackingDataMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartPositionMessage") == 0)
	{
		igtl::StartPositionMessage::Pointer pointer = static_cast<igtl::StartPositionMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartPointMessage") == 0)
	{
		igtl::StartPointMessage::Pointer pointer = static_cast<igtl::StartPointMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartImageMessage") == 0)
	{
		igtl::StartImageMessage::Pointer pointer = static_cast<igtl::StartImageMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}
	else if (strcmp(m_message->GetNameOfClass(), "igtl::StartBindMessage") == 0)
	{
		igtl::StartBindMessage::Pointer pointer = static_cast<igtl::StartBindMessage *>(m_message.GetPointer());
		m_resolution = pointer->GetResolution();
	}

	m_message->Pack();

	res = m_resolution;
}

void OIGTLMessage::update(QString hostname, igtl::TimeStamp::Pointer ts)
{
  // Updates timestamp and hostname

  if (m_message.IsNull())
    return;

  m_timeCreated.operator =(ts);
  m_senderHostName = hostname;

  m_message->Unpack();

  m_message->SetTimeStamp(ts);
  m_message->SetDeviceName(m_senderHostName.toStdString().c_str());

  m_message->Pack();
}

void OIGTLMessage::update(QString hostname)
{
  // Updates timestamp and hostname

  if (m_message.IsNull())
    return;

  igtl::TimeStamp::Pointer ts;
  ts = igtl::TimeStamp::New();
  ts->GetTime();

  m_timeCreated.operator =(ts);
  m_senderHostName = hostname;

  m_id = GetTimeInNanoSeconds(ts);

  m_message->Unpack();

  m_message->SetTimeStamp(ts);
  m_message->SetDeviceName(m_senderHostName.toStdString().c_str());

  m_message->Pack();
}

void OIGTLMessage::setOwnerName(QString str)
  {
    if (!m_ownerName.isEmpty() && !m_ownerName.isNull())
      m_ownerName.clear();
    m_ownerName.append(str);
  }

<|endoftext|>


<commit_before>//===--- CFG.cpp - Defines the CFG data structure ----------------*- C++ -*-==//
//
// 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/AST/AST.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/CFG/CFG.h"
#include "llvm/ADT/OwningPtr.h"

using namespace swift;

CFG::CFG() {}

CFG::~CFG() {
  // FIXME: if all parts of BasicBlock are BumpPtrAllocated, this shouldn't
  // eventually be needed.
  for(BasicBlock &B : blocks) { B.~BasicBlock(); }
}

//===----------------------------------------------------------------------===//
// CFG construction.
//===----------------------------------------------------------------------===//

static Expr *ignoreParens(Expr *Ex) {
  while (ParenExpr *P = dyn_cast<ParenExpr>(Ex)) { Ex = P->getSubExpr(); }
  return Ex;
}

namespace {
class CFGBuilder : public ASTVisitor<CFGBuilder, CFGValue> {
  typedef llvm::SmallVector<BasicBlock *, 4> BlocksVector;

  BlocksVector BasePendingMerges;
  llvm::SmallVector<BlocksVector *, 4> PendingMergesStack;
  llvm::SmallVector<BlocksVector *, 4> BreakStack;
  llvm::SmallVector<BlocksVector *, 4> ContinueStack;

  /// Mapping from expressions to instructions.
  llvm::DenseMap<Expr *, Instruction *> ExprToInst;

  /// The current basic block being constructed.
  BasicBlock *Block;

  /// The CFG being constructed.
  CFG &C;

public:
  CFGBuilder(CFG &C) : Block(0), C(C), badCFG(false) {
    PendingMergesStack.push_back(&BasePendingMerges);
  }

  ~CFGBuilder() {}

  /// A flag indicating whether or not there were problems
  /// constructing the CFG.
  bool badCFG;

  BlocksVector &pendingMerges() {
    assert(!PendingMergesStack.empty());
    return *PendingMergesStack.back();
  }

  void flushPending(BasicBlock *TargetBlock) {
    for (auto PredBlock : pendingMerges()) {
      // If the block has no terminator, we need to add an unconditional
      // jump to the block we are creating.
      if (!PredBlock->hasTerminator()) {
        UncondBranchInst *UB = new (C) UncondBranchInst(PredBlock);
        UB->setTarget(TargetBlock, ArrayRef<CFGValue>());
        continue;
      }
      TermInst &Term = cast<TermInst>(PredBlock->instructions.back());
      if (UncondBranchInst *UBI = dyn_cast<UncondBranchInst>(&Term)) {
        assert(UBI->targetBlock() == nullptr);
        UBI->setTarget(TargetBlock, ArrayRef<CFGValue>());
        continue;
      }

      // If the block already has a CondBranch terminator, then it means
      // we are fixing up one of the branch targets because it wasn't
      // available when the instruction was created.
      CondBranchInst &CBI = cast<CondBranchInst>(Term);
      assert(CBI.branches()[0]);
      assert(!CBI.branches()[1]);
      CBI.branches()[1] = TargetBlock;
      TargetBlock->addPred(PredBlock);
    }
    pendingMerges().clear();
  }

  /// The current basic block being constructed.
  BasicBlock *currentBlock() {
    if (!Block) {
      Block = new (C) BasicBlock(&C);

      // Flush out all pending merges.  These are basic blocks waiting
      // for a successor.
      flushPending(Block);
    }
    return Block;
  }

  void addCurrentBlockToPending() {
    if (Block && !Block->hasTerminator()) {
      pendingMerges().push_back(Block);
    }
    Block = 0;
  }

  /// Reset the currently active basic block by creating a new one.
  BasicBlock *createFreshBlock() {
    Block = new (C) BasicBlock(&C);
    return Block;
  }

  CFGValue addInst(Expr *Ex, Instruction *I) {
    ExprToInst[Ex] = I;
    return I;
  }

  void finishUp() {
    assert(PendingMergesStack.size() == 1);
    if (!pendingMerges().empty()) {
      assert(Block == 0);
      new (C) ReturnInst(currentBlock());
      return;
    }
    // Check if the last block has a Return.
    if (!Block)
      return;

    if (Block->instructions.empty() ||
        !isa<ReturnInst>(Block->instructions.back())) {
      new (C) ReturnInst(Block);
    }
  }

  void popBreakStack(BlocksVector &BlocksThatBreak) {
    assert(BreakStack.back() == &BlocksThatBreak);
    for (auto BreakBlock : BlocksThatBreak) {
      pendingMerges().push_back(BreakBlock);
    }
    BreakStack.pop_back();
  }

  void popContinueStack(BlocksVector &BlocksThatContinue,
                        BasicBlock *TargetBlock) {
    assert(ContinueStack.back() == &BlocksThatContinue);
    for (auto ContinueBlock : BlocksThatContinue) {
      assert(ContinueBlock->hasTerminator());
      UncondBranchInst &UB =
      cast<UncondBranchInst>(ContinueBlock->instructions.back());
      UB.setTarget(TargetBlock, ArrayRef<CFGValue>());
    }
    ContinueStack.pop_back();
  }

  //===--------------------------------------------------------------------===//
  // Statements.
  //===--------------------------------------------------------------------===//

  /// Construct the CFG components for the given BraceStmt.
  void visitBraceStmt(BraceStmt *S);

  /// SemiStmts are ignored for CFG construction.
  void visitSemiStmt(SemiStmt *S) {}

  void visitAssignStmt(AssignStmt *S) {
    assert(false && "Not yet implemented");
  }

  void visitReturnStmt(ReturnStmt *S) {
    CFGValue ArgV = S->hasResult() ? visit(S->getResult()) : (Instruction*) 0;
    (void) new (C) ReturnInst(S, ArgV, currentBlock());
    // Treat the current block as "complete" with no successors.
    Block = 0;
  }

  void visitIfStmt(IfStmt *S);

  void visitWhileStmt(WhileStmt *S);

  void visitDoWhileStmt(DoWhileStmt *S) {
    assert(false && "Not yet implemented");
  }

  void visitForStmt(ForStmt *S) {
    assert(false && "Not yet implemented");
  }

  void visitForEachStmt(ForEachStmt *S) {
    badCFG = true;
    return;
  }

  void visitBreakStmt(BreakStmt *S);

  void visitContinueStmt(ContinueStmt *S);

  //===--------------------------------------------------------------------===//
  // Expressions.
  //===--------------------------------------------------------------------===//

  CFGValue visitExpr(Expr *E) {
    llvm_unreachable("Not yet implemented");
  }

  CFGValue visitCallExpr(CallExpr *E);
  CFGValue visitDeclRefExpr(DeclRefExpr *E);
  CFGValue visitIntegerLiteralExpr(IntegerLiteralExpr *E);
  CFGValue visitLoadExpr(LoadExpr *E);
  CFGValue visitParenExpr(ParenExpr *E);
  CFGValue visitThisApplyExpr(ThisApplyExpr *E);
  CFGValue visitTupleExpr(TupleExpr *E);
  CFGValue visitTypeOfExpr(TypeOfExpr *E);

};
} // end anonymous namespace

CFG *CFG::constructCFG(Stmt *S) {
  // FIXME: implement CFG construction.
  llvm::OwningPtr<CFG> C(new CFG());
  CFGBuilder builder(*C);
  builder.visit(S);
  if (!builder.badCFG) {
    builder.finishUp();
    return C.take();
  }
  return nullptr;
}

void CFGBuilder::visitBraceStmt(BraceStmt *S) {
  // BraceStmts do not need to be explicitly represented in the CFG.
  // We should consider whether or not the scopes they introduce are
  // represented in the CFG.
  for (const BraceStmt::ExprStmtOrDecl &ESD : S->elements()) {
    assert(!ESD.is<Decl*>() && "FIXME: Handle Decls");
    if (Stmt *S = ESD.dyn_cast<Stmt*>())
      visit(S);
    if (Expr *E = ESD.dyn_cast<Expr*>())
      visit(E);
  }
}

//===--------------------------------------------------------------------===//
// Control-flow.
//===--------------------------------------------------------------------===//

void CFGBuilder::visitBreakStmt(BreakStmt *S) {
  assert(!BreakStack.empty());
  BasicBlock *BreakBlock = currentBlock();
  BreakStack.back()->push_back(BreakBlock);

  // FIXME: we need to be able to include the BreakStmt in the jump.
  new (C) UncondBranchInst(BreakBlock);
  Block = 0;
}

void CFGBuilder::visitContinueStmt(ContinueStmt *S) {
  assert(!ContinueStack.empty());
  BasicBlock *ContinueBlock = currentBlock();
  ContinueStack.back()->push_back(ContinueBlock);

  // FIXME: we need to be able to include the ContinueStmt in the jump.
  new (C) UncondBranchInst(ContinueBlock);
  Block = 0;
}

void CFGBuilder::visitIfStmt(IfStmt *S) {
  // ** FIXME ** Handle the condition.  We need to handle more of the
  // statements first.

  // The condition should be the last value evaluated just before the
  // terminator.
  //  CFGValue CondV = visit(S->getCond());
  CFGValue CondV = (Instruction*) 0;

  // Save the current block.  We will use it to construct the
  // CondBranchInst.
  BasicBlock *IfTermBlock = currentBlock();

  // Reset the state for the current block.
  Block = 0;

  // Create a new basic block for the first target.
  BasicBlock *Target1 = createFreshBlock();
  visit(S->getThenStmt());
  addCurrentBlockToPending();

  // Handle an (optional) 'else'.  If no 'else' is found, the false branch
  // will be fixed up later.
  BasicBlock *Target2 = nullptr;
  if (Stmt *Else = S->getElseStmt()) {
    // Create a new basic block for the second target.  The first target's
    // blocks will get added the "pending" list.
    Target2 = createFreshBlock();
    visit(Else);
    addCurrentBlockToPending();
  }
  else {
    // If we have no 'else', we need to fix up the branch later.
    pendingMerges().push_back(IfTermBlock);
  }

  // Finally, hook up the block with the condition to the target blocks.
  CFGValue Branch = new (C) CondBranchInst(S, CondV,
                                           Target1,
                                           Target2 /* may be null*/,
                                           IfTermBlock);
  (void) Branch;
}

void CFGBuilder::visitWhileStmt(WhileStmt *S) {
  // The condition needs to be in its own basic block so that
  // it can be the loop-back target.  We thus finish up the currently
  // active block.  It will get linked to the new block once we
  // create it.
  addCurrentBlockToPending();

  // Process the condition.  This will link up the previous block
  // with the condition block.
  BasicBlock *ConditionBlock = currentBlock();
  CFGValue CondV = (Instruction*) 0;
  //  visit(S->getCond());

  assert(ConditionBlock == Block);
  Block = 0;

  // Set up a vector to record blocks that 'break'.
  BlocksVector BlocksThatBreak;
  BreakStack.push_back(&BlocksThatBreak);

  // Set up a vector to record blocks that 'continue'.
  BlocksVector BlocksThatContinue;
  ContinueStack.push_back(&BlocksThatContinue);

  // Push a new context to record pending blocks.  These will
  // get linked up the condition block.
  BlocksVector PendingWithinLoop;
  PendingMergesStack.push_back(&PendingWithinLoop);

  // Create a new basic block for the body.
  BasicBlock *BodyBlock = createFreshBlock();
  visit(S->getBody());
  addCurrentBlockToPending();

  // Pop the pending merges.
  assert(PendingMergesStack.back() == &PendingWithinLoop);
  flushPending(ConditionBlock);
  PendingMergesStack.pop_back();

  // Pop the 'break' context.
  popBreakStack(BlocksThatBreak);

  // Pop the 'continue' context.
  popContinueStack(BlocksThatContinue, ConditionBlock);

  // Finally, hook up the block with the condition to the target blocks.
  CFGValue Branch = new (C) CondBranchInst(S, CondV,
                                           BodyBlock,
                                           0, /* will be fixed up later */
                                           ConditionBlock);
  (void) Branch;

  pendingMerges().push_back(ConditionBlock);
}

//===--------------------------------------------------------------------===//
// Expressions.
//===--------------------------------------------------------------------===//

CFGValue CFGBuilder::visitCallExpr(CallExpr *E) {
  Expr *Arg = ignoreParens(E->getArg());
  Expr *Fn = E->getFn();
  CFGValue FnV = visit(Fn);
  llvm::SmallVector<CFGValue, 10> ArgsV;

  // Special case Arg being a TupleExpr, to inline the arguments and
  // not create another instruction.
  if (TupleExpr *TU = dyn_cast<TupleExpr>(Arg)) {
    for (auto arg : TU->getElements())
      ArgsV.push_back(visit(arg));
  }
  else {
    ArgsV.push_back(visit(Arg));
  }

  return addInst(E, CallInst::create(E, currentBlock(), FnV, ArgsV));
}

CFGValue CFGBuilder::visitDeclRefExpr(DeclRefExpr *E) {
  return addInst(E, new (C) DeclRefInst(E, currentBlock()));
}

CFGValue CFGBuilder::visitThisApplyExpr(ThisApplyExpr *E) {
  CFGValue FnV = visit(E->getFn());
  CFGValue ArgV = visit(E->getArg());
  return addInst(E, new (C) ThisApplyInst(E, FnV, ArgV, currentBlock()));
}

CFGValue CFGBuilder::visitIntegerLiteralExpr(IntegerLiteralExpr *E) {
  return addInst(E, new (C) IntegerLiteralInst(E, currentBlock()));
}

CFGValue CFGBuilder::visitLoadExpr(LoadExpr *E) {
  CFGValue SubV = visit(E->getSubExpr());
  return addInst(E, new (C) LoadInst(E, SubV, currentBlock()));
}

CFGValue CFGBuilder::visitParenExpr(ParenExpr *E) {
  return visit(E->getSubExpr());
}

CFGValue CFGBuilder::visitTupleExpr(TupleExpr *E) {
  llvm::SmallVector<CFGValue, 10> ArgsV;
  for (auto &I : E->getElements()) {
    ArgsV.push_back(visit(I));
  }
  return addInst(E, TupleInst::create(E, ArgsV, currentBlock()));
}

CFGValue CFGBuilder::visitTypeOfExpr(TypeOfExpr *E) {
  return addInst(E, new (C) TypeOfInst(E, currentBlock()));
}
<commit_msg>Add CFG support for do...while.<commit_after>//===--- CFG.cpp - Defines the CFG data structure ----------------*- C++ -*-==//
//
// 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/AST/AST.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/CFG/CFG.h"
#include "llvm/ADT/OwningPtr.h"

using namespace swift;

CFG::CFG() {}

CFG::~CFG() {
  // FIXME: if all parts of BasicBlock are BumpPtrAllocated, this shouldn't
  // eventually be needed.
  for(BasicBlock &B : blocks) { B.~BasicBlock(); }
}

//===----------------------------------------------------------------------===//
// CFG construction.
//===----------------------------------------------------------------------===//

static Expr *ignoreParens(Expr *Ex) {
  while (ParenExpr *P = dyn_cast<ParenExpr>(Ex)) { Ex = P->getSubExpr(); }
  return Ex;
}

namespace {
class CFGBuilder : public ASTVisitor<CFGBuilder, CFGValue> {
  typedef llvm::SmallVector<BasicBlock *, 4> BlocksVector;

  BlocksVector BasePendingMerges;
  llvm::SmallVector<BlocksVector *, 4> PendingMergesStack;
  llvm::SmallVector<BlocksVector *, 4> BreakStack;
  llvm::SmallVector<BlocksVector *, 4> ContinueStack;

  /// Mapping from expressions to instructions.
  llvm::DenseMap<Expr *, Instruction *> ExprToInst;

  /// The current basic block being constructed.
  BasicBlock *Block;

  /// The CFG being constructed.
  CFG &C;

public:
  CFGBuilder(CFG &C) : Block(0), C(C), badCFG(false) {
    PendingMergesStack.push_back(&BasePendingMerges);
  }

  ~CFGBuilder() {}

  /// A flag indicating whether or not there were problems
  /// constructing the CFG.
  bool badCFG;

  BlocksVector &pendingMerges() {
    assert(!PendingMergesStack.empty());
    return *PendingMergesStack.back();
  }

  void flushPending(BasicBlock *TargetBlock) {
    for (auto PredBlock : pendingMerges()) {
      // If the block has no terminator, we need to add an unconditional
      // jump to the block we are creating.
      if (!PredBlock->hasTerminator()) {
        UncondBranchInst *UB = new (C) UncondBranchInst(PredBlock);
        UB->setTarget(TargetBlock, ArrayRef<CFGValue>());
        continue;
      }
      TermInst &Term = cast<TermInst>(PredBlock->instructions.back());
      if (UncondBranchInst *UBI = dyn_cast<UncondBranchInst>(&Term)) {
        assert(UBI->targetBlock() == nullptr);
        UBI->setTarget(TargetBlock, ArrayRef<CFGValue>());
        continue;
      }

      // If the block already has a CondBranch terminator, then it means
      // we are fixing up one of the branch targets because it wasn't
      // available when the instruction was created.
      CondBranchInst &CBI = cast<CondBranchInst>(Term);
      assert(CBI.branches()[0]);
      assert(!CBI.branches()[1]);
      CBI.branches()[1] = TargetBlock;
      TargetBlock->addPred(PredBlock);
    }
    pendingMerges().clear();
  }

  /// The current basic block being constructed.
  BasicBlock *currentBlock() {
    if (!Block) {
      Block = new (C) BasicBlock(&C);

      // Flush out all pending merges.  These are basic blocks waiting
      // for a successor.
      flushPending(Block);
    }
    return Block;
  }

  void addCurrentBlockToPending() {
    if (Block && !Block->hasTerminator()) {
      pendingMerges().push_back(Block);
    }
    Block = 0;
  }

  /// Reset the currently active basic block by creating a new one.
  BasicBlock *createFreshBlock() {
    Block = new (C) BasicBlock(&C);
    return Block;
  }

  CFGValue addInst(Expr *Ex, Instruction *I) {
    ExprToInst[Ex] = I;
    return I;
  }

  void finishUp() {
    assert(PendingMergesStack.size() == 1);
    if (!pendingMerges().empty()) {
      assert(Block == 0);
      new (C) ReturnInst(currentBlock());
      return;
    }
    // Check if the last block has a Return.
    if (!Block)
      return;

    if (Block->instructions.empty() ||
        !isa<ReturnInst>(Block->instructions.back())) {
      new (C) ReturnInst(Block);
    }
  }

  void popBreakStack(BlocksVector &BlocksThatBreak) {
    assert(BreakStack.back() == &BlocksThatBreak);
    for (auto BreakBlock : BlocksThatBreak) {
      pendingMerges().push_back(BreakBlock);
    }
    BreakStack.pop_back();
  }

  void popContinueStack(BlocksVector &BlocksThatContinue,
                        BasicBlock *TargetBlock) {
    assert(ContinueStack.back() == &BlocksThatContinue);
    for (auto ContinueBlock : BlocksThatContinue) {
      assert(ContinueBlock->hasTerminator());
      UncondBranchInst &UB =
      cast<UncondBranchInst>(ContinueBlock->instructions.back());
      UB.setTarget(TargetBlock, ArrayRef<CFGValue>());
    }
    ContinueStack.pop_back();
  }

  //===--------------------------------------------------------------------===//
  // Statements.
  //===--------------------------------------------------------------------===//

  /// Construct the CFG components for the given BraceStmt.
  void visitBraceStmt(BraceStmt *S);

  /// SemiStmts are ignored for CFG construction.
  void visitSemiStmt(SemiStmt *S) {}

  void visitAssignStmt(AssignStmt *S) {
    assert(false && "Not yet implemented");
  }

  void visitReturnStmt(ReturnStmt *S) {
    CFGValue ArgV = S->hasResult() ? visit(S->getResult()) : (Instruction*) 0;
    (void) new (C) ReturnInst(S, ArgV, currentBlock());
    // Treat the current block as "complete" with no successors.
    Block = 0;
  }

  void visitIfStmt(IfStmt *S);

  void visitWhileStmt(WhileStmt *S);

  void visitDoWhileStmt(DoWhileStmt *S);

  void visitForStmt(ForStmt *S) {
    assert(false && "Not yet implemented");
  }

  void visitForEachStmt(ForEachStmt *S) {
    badCFG = true;
    return;
  }

  void visitBreakStmt(BreakStmt *S);

  void visitContinueStmt(ContinueStmt *S);

  //===--------------------------------------------------------------------===//
  // Expressions.
  //===--------------------------------------------------------------------===//

  CFGValue visitExpr(Expr *E) {
    llvm_unreachable("Not yet implemented");
  }

  CFGValue visitCallExpr(CallExpr *E);
  CFGValue visitDeclRefExpr(DeclRefExpr *E);
  CFGValue visitIntegerLiteralExpr(IntegerLiteralExpr *E);
  CFGValue visitLoadExpr(LoadExpr *E);
  CFGValue visitParenExpr(ParenExpr *E);
  CFGValue visitThisApplyExpr(ThisApplyExpr *E);
  CFGValue visitTupleExpr(TupleExpr *E);
  CFGValue visitTypeOfExpr(TypeOfExpr *E);

};
} // end anonymous namespace

CFG *CFG::constructCFG(Stmt *S) {
  // FIXME: implement CFG construction.
  llvm::OwningPtr<CFG> C(new CFG());
  CFGBuilder builder(*C);
  builder.visit(S);
  if (!builder.badCFG) {
    builder.finishUp();
    return C.take();
  }
  return nullptr;
}

void CFGBuilder::visitBraceStmt(BraceStmt *S) {
  // BraceStmts do not need to be explicitly represented in the CFG.
  // We should consider whether or not the scopes they introduce are
  // represented in the CFG.
  for (const BraceStmt::ExprStmtOrDecl &ESD : S->elements()) {
    assert(!ESD.is<Decl*>() && "FIXME: Handle Decls");
    if (Stmt *S = ESD.dyn_cast<Stmt*>())
      visit(S);
    if (Expr *E = ESD.dyn_cast<Expr*>())
      visit(E);
  }
}

//===--------------------------------------------------------------------===//
// Control-flow.
//===--------------------------------------------------------------------===//

void CFGBuilder::visitBreakStmt(BreakStmt *S) {
  assert(!BreakStack.empty());
  BasicBlock *BreakBlock = currentBlock();
  BreakStack.back()->push_back(BreakBlock);

  // FIXME: we need to be able to include the BreakStmt in the jump.
  new (C) UncondBranchInst(BreakBlock);
  Block = 0;
}

void CFGBuilder::visitContinueStmt(ContinueStmt *S) {
  assert(!ContinueStack.empty());
  BasicBlock *ContinueBlock = currentBlock();
  ContinueStack.back()->push_back(ContinueBlock);

  // FIXME: we need to be able to include the ContinueStmt in the jump.
  new (C) UncondBranchInst(ContinueBlock);
  Block = 0;
}

void CFGBuilder::visitDoWhileStmt(DoWhileStmt *S) {
  // Set up a vector to record blocks that 'break'.
  BlocksVector BlocksThatBreak;
  BreakStack.push_back(&BlocksThatBreak);

  // Set up a vector to record blocks that 'continue'.
  BlocksVector BlocksThatContinue;
  ContinueStack.push_back(&BlocksThatContinue);

  // Create a new basic block for the body.
  addCurrentBlockToPending();
  BasicBlock *BodyBlock = currentBlock();

  // Push a new context to record pending blocks.  These will
  // get linked up the condition block.
  BlocksVector PendingWithinLoop;
  PendingMergesStack.push_back(&PendingWithinLoop);

  // Now visit the loop body.
  visit(S->getBody());
  addCurrentBlockToPending();

  // Create the condition block.
  BasicBlock *ConditionBlock = currentBlock();
  CFGValue CondV = (Instruction*) 0;
  //  visit(S->getCond());

  assert(ConditionBlock == Block);
  Block = 0;

  // Pop the pending merges.
  assert(PendingMergesStack.back() == &PendingWithinLoop);
  flushPending(ConditionBlock);
  PendingMergesStack.pop_back();

  // Pop the 'break' context.
  popBreakStack(BlocksThatBreak);

  // Pop the 'continue' context.
  popContinueStack(BlocksThatContinue, ConditionBlock);

  // Finally, hook up the block with the condition to the target blocks.
  CFGValue Branch = new (C) CondBranchInst(S, CondV,
                                           BodyBlock,
                                           0, /* will be fixed up later */
                                           ConditionBlock);
  (void) Branch;

  pendingMerges().push_back(ConditionBlock);
}

void CFGBuilder::visitIfStmt(IfStmt *S) {
  // ** FIXME ** Handle the condition.  We need to handle more of the
  // statements first.

  // The condition should be the last value evaluated just before the
  // terminator.
  //  CFGValue CondV = visit(S->getCond());
  CFGValue CondV = (Instruction*) 0;

  // Save the current block.  We will use it to construct the
  // CondBranchInst.
  BasicBlock *IfTermBlock = currentBlock();

  // Reset the state for the current block.
  Block = 0;

  // Create a new basic block for the first target.
  BasicBlock *Target1 = createFreshBlock();
  visit(S->getThenStmt());
  addCurrentBlockToPending();

  // Handle an (optional) 'else'.  If no 'else' is found, the false branch
  // will be fixed up later.
  BasicBlock *Target2 = nullptr;
  if (Stmt *Else = S->getElseStmt()) {
    // Create a new basic block for the second target.  The first target's
    // blocks will get added the "pending" list.
    Target2 = createFreshBlock();
    visit(Else);
    addCurrentBlockToPending();
  }
  else {
    // If we have no 'else', we need to fix up the branch later.
    pendingMerges().push_back(IfTermBlock);
  }

  // Finally, hook up the block with the condition to the target blocks.
  CFGValue Branch = new (C) CondBranchInst(S, CondV,
                                           Target1,
                                           Target2 /* may be null*/,
                                           IfTermBlock);
  (void) Branch;
}

void CFGBuilder::visitWhileStmt(WhileStmt *S) {
  // The condition needs to be in its own basic block so that
  // it can be the loop-back target.  We thus finish up the currently
  // active block.  It will get linked to the new block once we
  // create it.
  addCurrentBlockToPending();

  // Process the condition.  This will link up the previous block
  // with the condition block.
  BasicBlock *ConditionBlock = currentBlock();
  CFGValue CondV = (Instruction*) 0;
  //  visit(S->getCond());

  assert(ConditionBlock == Block);
  Block = 0;

  // Set up a vector to record blocks that 'break'.
  BlocksVector BlocksThatBreak;
  BreakStack.push_back(&BlocksThatBreak);

  // Set up a vector to record blocks that 'continue'.
  BlocksVector BlocksThatContinue;
  ContinueStack.push_back(&BlocksThatContinue);

  // Push a new context to record pending blocks.  These will
  // get linked up the condition block.
  BlocksVector PendingWithinLoop;
  PendingMergesStack.push_back(&PendingWithinLoop);

  // Create a new basic block for the body.
  BasicBlock *BodyBlock = createFreshBlock();
  visit(S->getBody());
  addCurrentBlockToPending();

  // Pop the pending merges.
  assert(PendingMergesStack.back() == &PendingWithinLoop);
  flushPending(ConditionBlock);
  PendingMergesStack.pop_back();

  // Pop the 'break' context.
  popBreakStack(BlocksThatBreak);

  // Pop the 'continue' context.
  popContinueStack(BlocksThatContinue, ConditionBlock);

  // Finally, hook up the block with the condition to the target blocks.
  CFGValue Branch = new (C) CondBranchInst(S, CondV,
                                           BodyBlock,
                                           0, /* will be fixed up later */
                                           ConditionBlock);
  (void) Branch;

  pendingMerges().push_back(ConditionBlock);
}

//===--------------------------------------------------------------------===//
// Expressions.
//===--------------------------------------------------------------------===//

CFGValue CFGBuilder::visitCallExpr(CallExpr *E) {
  Expr *Arg = ignoreParens(E->getArg());
  Expr *Fn = E->getFn();
  CFGValue FnV = visit(Fn);
  llvm::SmallVector<CFGValue, 10> ArgsV;

  // Special case Arg being a TupleExpr, to inline the arguments and
  // not create another instruction.
  if (TupleExpr *TU = dyn_cast<TupleExpr>(Arg)) {
    for (auto arg : TU->getElements())
      ArgsV.push_back(visit(arg));
  }
  else {
    ArgsV.push_back(visit(Arg));
  }

  return addInst(E, CallInst::create(E, currentBlock(), FnV, ArgsV));
}

CFGValue CFGBuilder::visitDeclRefExpr(DeclRefExpr *E) {
  return addInst(E, new (C) DeclRefInst(E, currentBlock()));
}

CFGValue CFGBuilder::visitThisApplyExpr(ThisApplyExpr *E) {
  CFGValue FnV = visit(E->getFn());
  CFGValue ArgV = visit(E->getArg());
  return addInst(E, new (C) ThisApplyInst(E, FnV, ArgV, currentBlock()));
}

CFGValue CFGBuilder::visitIntegerLiteralExpr(IntegerLiteralExpr *E) {
  return addInst(E, new (C) IntegerLiteralInst(E, currentBlock()));
}

CFGValue CFGBuilder::visitLoadExpr(LoadExpr *E) {
  CFGValue SubV = visit(E->getSubExpr());
  return addInst(E, new (C) LoadInst(E, SubV, currentBlock()));
}

CFGValue CFGBuilder::visitParenExpr(ParenExpr *E) {
  return visit(E->getSubExpr());
}

CFGValue CFGBuilder::visitTupleExpr(TupleExpr *E) {
  llvm::SmallVector<CFGValue, 10> ArgsV;
  for (auto &I : E->getElements()) {
    ArgsV.push_back(visit(I));
  }
  return addInst(E, TupleInst::create(E, ArgsV, currentBlock()));
}

CFGValue CFGBuilder::visitTypeOfExpr(TypeOfExpr *E) {
  return addInst(E, new (C) TypeOfInst(E, currentBlock()));
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla 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.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "tests/test-utils.hh"
#include "tests/cql_test_env.hh"
#include "tests/cql_assertions.hh"

SEASTAR_TEST_CASE(test_secondary_index_regular_column_query) {
    return do_with_cql_env([] (cql_test_env& e) {
        return e.execute_cql("CREATE TABLE users (userid int, name text, email text, country text, PRIMARY KEY (userid));").discard_result().then([&e] {
            return e.execute_cql("CREATE INDEX ON users (email);").discard_result();
        }).then([&e] {
            return e.execute_cql("CREATE INDEX ON users (country);").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (0, 'Bondie Easseby', 'beassebyv@house.gov', 'France');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (1, 'Demetri Curror', 'dcurrorw@techcrunch.com', 'France');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (2, 'Langston Paulisch', 'lpaulischm@reverbnation.com', 'United States');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (3, 'Channa Devote', 'cdevote14@marriott.com', 'Denmark');").discard_result();
        }).then([&e] {
            return e.execute_cql("SELECT email FROM users WHERE country = 'France';");
        }).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
            assert_that(msg).is_rows().with_rows({
                { utf8_type->decompose(sstring("beassebyv@house.gov")) },
                { utf8_type->decompose(sstring("dcurrorw@techcrunch.com")) },
            });
        });
    });
}

SEASTAR_TEST_CASE(test_secondary_index_clustering_key_query) {
    return do_with_cql_env([] (cql_test_env& e) {
        return e.execute_cql("CREATE TABLE users (userid int, name text, email text, country text, PRIMARY KEY (userid, country));").discard_result().then([&e] {
            return e.execute_cql("CREATE INDEX ON users (country);").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (0, 'Bondie Easseby', 'beassebyv@house.gov', 'France');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (1, 'Demetri Curror', 'dcurrorw@techcrunch.com', 'France');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (2, 'Langston Paulisch', 'lpaulischm@reverbnation.com', 'United States');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (3, 'Channa Devote', 'cdevote14@marriott.com', 'Denmark');").discard_result();
        }).then([&e] {
            return e.execute_cql("SELECT email FROM users WHERE country = 'France';");
        }).then([&e] (auto msg) {
            assert_that(msg).is_rows().with_rows({
                { utf8_type->decompose(sstring("beassebyv@house.gov")) },
                { utf8_type->decompose(sstring("dcurrorw@techcrunch.com")) },
            });
        });
    });
}

// CQL usually folds identifier names - keyspace, table and column names -
// to lowercase. That is, unless the identifier is enclosed in double
// quotation marks ("). Let's test that case-sensitive (quoted) column
// names can be indexed. This reproduces issue #3154.
SEASTAR_TEST_CASE(test_secondary_index_case_sensitive) {
    return do_with_cql_env_thread([] (auto& e) {
        // Test case-sensitive *table* name.
        e.execute_cql("CREATE TABLE \"FooBar\" (a int PRIMARY KEY, b int, c int)").get();
        e.execute_cql("CREATE INDEX ON \"FooBar\" (b)").get();
        e.execute_cql("SELECT * from \"FooBar\" WHERE b = 1").get();
        // Test case-sensitive *indexed column* name.
        // This not working was issue #3154. The symptom was that the SELECT
        // below threw a "No index found." runtime error.
        e.execute_cql("CREATE TABLE tab (a int PRIMARY KEY, \"FooBar\" int, c int)").get();
        e.execute_cql("CREATE INDEX ON tab (\"FooBar\")").get();
        e.execute_cql("SELECT * from tab WHERE \"FooBar\" = 1").get();
    });
}

SEASTAR_TEST_CASE(test_cannot_drop_secondary_index_backing_mv) {
    return do_with_cql_env_thread([] (cql_test_env& e) {
        e.execute_cql("create table cf (p int primary key, a int)").get();
        e.execute_cql("create index on cf (a)").get();
        auto s = e.local_db().find_schema(sstring("ks"), sstring("cf"));
        auto index_name = s->index_names().front();
        assert_that_failed(e.execute_cql(sprint("drop materialized view %s_index", index_name)));
    });
}

// Issue #3210 is about searching the secondary index not working properly
// when the *partition key* has multiple columns (a compound partition key),
// and this is what we test here.
SEASTAR_TEST_CASE(test_secondary_index_case_compound_partition_key) {
    return do_with_cql_env_thread([] (auto& e) {
        // Test case-sensitive *table* name.
        e.execute_cql("CREATE TABLE tab (a int, b int, c int, PRIMARY KEY ((a, b)))").get();
        e.execute_cql("CREATE INDEX ON tab (c)").get();
        e.execute_cql("INSERT INTO tab (a, b, c) VALUES (1, 2, 3)").get();
        eventually([&] {
            // We expect this search to find the single row, with the compound
            // partition key (a, b) = (1, 2).
            auto res = e.execute_cql("SELECT * from tab WHERE c = 3").get0();
            assert_that(res).is_rows()
                    .with_size(1)
                    .with_row({
                        {int32_type->decompose(1)},
                        {int32_type->decompose(2)},
                        {int32_type->decompose(3)},
                    });
        });
    });
}
<commit_msg>secondary index: improve testing of case-sensitive column names<commit_after>/*
 * Copyright (C) 2018 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla 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.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "tests/test-utils.hh"
#include "tests/cql_test_env.hh"
#include "tests/cql_assertions.hh"

SEASTAR_TEST_CASE(test_secondary_index_regular_column_query) {
    return do_with_cql_env([] (cql_test_env& e) {
        return e.execute_cql("CREATE TABLE users (userid int, name text, email text, country text, PRIMARY KEY (userid));").discard_result().then([&e] {
            return e.execute_cql("CREATE INDEX ON users (email);").discard_result();
        }).then([&e] {
            return e.execute_cql("CREATE INDEX ON users (country);").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (0, 'Bondie Easseby', 'beassebyv@house.gov', 'France');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (1, 'Demetri Curror', 'dcurrorw@techcrunch.com', 'France');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (2, 'Langston Paulisch', 'lpaulischm@reverbnation.com', 'United States');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (3, 'Channa Devote', 'cdevote14@marriott.com', 'Denmark');").discard_result();
        }).then([&e] {
            return e.execute_cql("SELECT email FROM users WHERE country = 'France';");
        }).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
            assert_that(msg).is_rows().with_rows({
                { utf8_type->decompose(sstring("beassebyv@house.gov")) },
                { utf8_type->decompose(sstring("dcurrorw@techcrunch.com")) },
            });
        });
    });
}

SEASTAR_TEST_CASE(test_secondary_index_clustering_key_query) {
    return do_with_cql_env([] (cql_test_env& e) {
        return e.execute_cql("CREATE TABLE users (userid int, name text, email text, country text, PRIMARY KEY (userid, country));").discard_result().then([&e] {
            return e.execute_cql("CREATE INDEX ON users (country);").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (0, 'Bondie Easseby', 'beassebyv@house.gov', 'France');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (1, 'Demetri Curror', 'dcurrorw@techcrunch.com', 'France');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (2, 'Langston Paulisch', 'lpaulischm@reverbnation.com', 'United States');").discard_result();
        }).then([&e] {
            return e.execute_cql("INSERT INTO users (userid, name, email, country) VALUES (3, 'Channa Devote', 'cdevote14@marriott.com', 'Denmark');").discard_result();
        }).then([&e] {
            return e.execute_cql("SELECT email FROM users WHERE country = 'France';");
        }).then([&e] (auto msg) {
            assert_that(msg).is_rows().with_rows({
                { utf8_type->decompose(sstring("beassebyv@house.gov")) },
                { utf8_type->decompose(sstring("dcurrorw@techcrunch.com")) },
            });
        });
    });
}

// CQL usually folds identifier names - keyspace, table and column names -
// to lowercase. That is, unless the identifier is enclosed in double
// quotation marks ("). Let's test that case-sensitive (quoted) column
// names can be indexed. This reproduces issues #3154, #3388, #3391, #3401.
SEASTAR_TEST_CASE(test_secondary_index_case_sensitive) {
    return do_with_cql_env_thread([] (auto& e) {
        // Test case-sensitive *table* name.
        e.execute_cql("CREATE TABLE \"FooBar\" (a int PRIMARY KEY, b int, c int)").get();
        e.execute_cql("CREATE INDEX ON \"FooBar\" (b)").get();
        e.execute_cql("INSERT INTO \"FooBar\" (a, b, c) VALUES (1, 2, 3)").get();
        e.execute_cql("SELECT * from \"FooBar\" WHERE b = 1").get();

        // Test case-sensitive *indexed column* name.
        // This not working was issue #3154. The symptom was that the SELECT
        // below threw a "No index found." runtime error.
        e.execute_cql("CREATE TABLE tab (a int PRIMARY KEY, \"FooBar\" int, c int)").get();
        e.execute_cql("CREATE INDEX ON tab (\"FooBar\")").get();
        // This INSERT also had problems (issue #3401)
        e.execute_cql("INSERT INTO tab (a, \"FooBar\", c) VALUES (1, 2, 3)").get();
        e.execute_cql("SELECT * from tab WHERE \"FooBar\" = 2").get();

        // Test case-sensitive *partition column* name.
        // This used to have multiple bugs in SI and MV code, detailed below:
        e.execute_cql("CREATE TABLE tab2 (\"FooBar\" int PRIMARY KEY, b int, c int)").get();
        e.execute_cql("CREATE INDEX ON tab2 (b)").get();
        // The following INSERT didn't work because of issues #3388 and #3391.
        e.execute_cql("INSERT INTO tab2 (\"FooBar\", b, c) VALUES (1, 2, 3)").get();
        // After the insert works, add the SELECT and see it works. It used
        // to fail before the patch to #3210 fixed this incidentally.
        e.execute_cql("SELECT * from tab2 WHERE b = 2").get();
    });
}

SEASTAR_TEST_CASE(test_cannot_drop_secondary_index_backing_mv) {
    return do_with_cql_env_thread([] (cql_test_env& e) {
        e.execute_cql("create table cf (p int primary key, a int)").get();
        e.execute_cql("create index on cf (a)").get();
        auto s = e.local_db().find_schema(sstring("ks"), sstring("cf"));
        auto index_name = s->index_names().front();
        assert_that_failed(e.execute_cql(sprint("drop materialized view %s_index", index_name)));
    });
}

// Issue #3210 is about searching the secondary index not working properly
// when the *partition key* has multiple columns (a compound partition key),
// and this is what we test here.
SEASTAR_TEST_CASE(test_secondary_index_case_compound_partition_key) {
    return do_with_cql_env_thread([] (auto& e) {
        // Test case-sensitive *table* name.
        e.execute_cql("CREATE TABLE tab (a int, b int, c int, PRIMARY KEY ((a, b)))").get();
        e.execute_cql("CREATE INDEX ON tab (c)").get();
        e.execute_cql("INSERT INTO tab (a, b, c) VALUES (1, 2, 3)").get();
        eventually([&] {
            // We expect this search to find the single row, with the compound
            // partition key (a, b) = (1, 2).
            auto res = e.execute_cql("SELECT * from tab WHERE c = 3").get0();
            assert_that(res).is_rows()
                    .with_size(1)
                    .with_row({
                        {int32_type->decompose(1)},
                        {int32_type->decompose(2)},
                        {int32_type->decompose(3)},
                    });
        });
    });
}
<|endoftext|>


<commit_before> #include "opencv2/objdetect/objdetect.hpp"
 #include "opencv2/highgui/highgui.hpp"
 #include "opencv2/imgproc/imgproc.hpp"
 #include <sstream>
 #include <iostream>
 #include <stdio.h>

using namespace std;
using namespace cv;

bool save_large = false;
void classifierDetect(CascadeClassifier classifier, Mat frame, int frameNum);

int main(int argc, const char** argv ) {
	string video_path = argv[1];
	string classifier_name = argv[2];
	VideoCapture video_in(video_path);
	Mat frame;

	CascadeClassifier detector;
	if( !detector.load( classifier_name ) ) {
		cout << "Error loading classifier.";
		return -1;
	}

	if(argv[3] == "--save-large") {
		save_large = true;
	}
	int frameNum = 0;
	while (true) {
		video_in >> frame;
		frameNum++;
		if(frame.empty()) {
			cout << "No frame! Exiting..." << endl;
			break;
		}
		classifierDetect(detector,frame,frameNum);
	}
	return 0;

}

void classifierDetect(CascadeClassifier &classifier,Mat &frame, int frameNum) {
	cvtColor(frame,frame,CV_BGR2GRAY);
	vector<Rect> objects;
	equalizeHist(frame,frame);
	classifier.detectMultiScale(frame,objects);
	for(int i = 0; i < objects.size(); i++) {
		Mat subImg = frame(objects[i]);
		Mat sample;
		subImg.copyTo(sample);
		stringstream name;
		stringstream name_small;
		Mat sample_small;
		name << "./negative_";
		name << frameNum;
		name << "_";
		name << i;
		name_small << name;
		name_small << "-s";
		name << ".png";
		name_small << ".png";
		resize(sample,sample_small,Size(20,20));
		imwrite(name_small.str(),sample_small);
		if(save_large) {
			imwrite(name.str(),sample);
		}
	}
}<commit_msg>Fixed things!<commit_after> #include "opencv2/objdetect/objdetect.hpp"
 #include "opencv2/highgui/highgui.hpp"
 #include "opencv2/imgproc/imgproc.hpp"
 #include <sstream>
 #include <iostream>
 #include <stdio.h>

using namespace std;
using namespace cv;

bool save_large = false;
void classifierDetect(const CascadeClassifier &classifier, Mat frame, int frameNum);

int main(int argc, const char** argv ) {
	string video_path = argv[1];
	string classifier_name = argv[2];
	VideoCapture video_in(video_path);
	Mat frame;

	CascadeClassifier detector;
	if( !detector.load( classifier_name ) ) {
		cout << "Error loading classifier.";
		return -1;
	}

	if(argv[3] == "--save-large") {
		save_large = true;
	}
	int frameNum = 0;
	while (true) {
		video_in >> frame;
		frameNum++;
		if(frame.empty()) {
			cout << "No frame! Exiting..." << endl;
			break;
		}
		classifierDetect(detector,frame,frameNum);
	}
	return 0;

}

void classifierDetect(const CascadeClassifier &classifier,Mat &frame, int frameNum) {
	cvtColor(frame,frame,CV_BGR2GRAY);
	vector<Rect> objects;
	equalizeHist(frame,frame);
	classifier.detectMultiScale(frame,objects);
	for(int i = 0; i < objects.size(); i++) {
		Mat subImg = frame(objects[i]);
		Mat sample;
		subImg.copyTo(sample);
		stringstream name;
		stringstream name_small;
		Mat sample_small;
		name << "./negative_";
		name << frameNum;
		name << "_";
		name << i;
		name_small << name;
		name_small << "-s";
		name << ".png";
		name_small << ".png";
		resize(sample,sample_small,Size(20,20));
		imwrite(name_small.str(),sample_small);
		if(save_large) {
			imwrite(name.str(),sample);
		}
	}
}<|endoftext|>