<commit_before>// @(#)root/test:$Id$
// Author: Fons Rademakers   19/08/96

#include <stdlib.h>

#include "Riostream.h"
#include "TString.h"
#include "TRegexp.h"
#include "TPRegexp.h"

void Ok(int i, int b)
{
   cout << "Test " << i;
   if (b)
      cout << "   ok" << endl;
   else
      cout << "   NOT ok" << endl;
}

int main()
{
   // create base string
   TString s = "aap noot mies";
   cout << s << endl;

   // use different constructors and excercise +, += and == operators
   TString s1 = TString("aa") + "p ";
   s1 += TString("noot ") + "mi" + "es";
   cout << s1 << endl;
   Ok(1, s1==s);

   // use single char constructor and excercise again += and == operators
   TString s2 = 'a';
   s2 += "ap ";
   s2 += "noot ";
   s2 += "mies";
   cout << s2 << endl;
   Ok(2, s2==s);

   // get and set a subrange (via TSubString)
   TString s3 = s(4,9);
   s3(0,4) = "mama papa";
   cout << s3 << endl;
   Ok(3, s3=="mama papa mies");

   // create a regular expression, make search in string and replace
   // matched substring
   TRegexp re(" n.*t ");
   TString s4 = s;
   s4(re) = " pipo ";
   cout << s4 << endl;
   Ok(4, s4=="aap pipo mies");

   // use "const char*" operator and the Data() member function to access
   // the string as a const char*
   const char *a = (const char*)s;
   cout << a << endl;
   Ok(5, !strcmp(a, s.Data()));

   // return 13th character and replace it by 't', getting 14th character
   // should result in an error message since operator[] uses range checking
   TString s6 = s;
   s6[12] = 't';
   cout << s6 << endl;
   cout << "*** Error message ok, accessing intentionaly out-of-bounds" << endl;
   char b = s6[13];
   cout << b << endl;
   Ok(6, s6=="aap noot miet");

   // return 13th character and replace it by 'p', getting 14th character
   // should NOT result in an error message since operator() does not use
   // range checking
   TString s7 = s;
   s7(12) = 'p';
   cout << s7 << endl;
   char c = s7(13);
   cout << c << endl;
   Ok(7, s7=="aap noot miep");

   // use Append, Remove, Prepend, Replace and Insert
   TString s8 = s;
   s8.Append(" tante ");
   s8.Append(s7(9,4));
   cout << s8 << endl;

   s8.Remove(0,14);
   cout << s8 << endl;
   s8.Prepend("oom jan");
   cout << s8 << endl;
   s8.Insert(7," en ");
   cout << s8 << endl;
   s8.Replace(4,3,"jaap");
   cout << s8 << endl;
   Ok(8, s8=="oom jaap en tante miep");

   // use CompareTo to compare char * and TString
   TString s9 = s;
   Ok(9,  !s9.CompareTo(s));
   Ok(10, !s9.CompareTo("AAP NOOT MIES", TString::kIgnoreCase));

   // use Contains to find if "string" is contained
   Ok(11, s9.Contains("NooT", TString::kIgnoreCase));
   Ok(12, !s9.Contains("pipo"));

   // return the index to the first and last character 'c'
   Ok(13, s.First('o')==5);
   Ok(14, s.First('z')==kNPOS);
   Ok(15, s.Last('a')==1);
   Ok(16, s.Last('z')==kNPOS);

   // returns the index of the start of match
   Ok(17, s.Index("mies")==9);
   Ok(18, s.Index("aa",1)==kNPOS);

   // returns length of string
   Ok(19, s.Length()==13);

   // test IsNull
   TString s10;

   Ok(20, s10.IsNull());
   Ok(21, !s.IsNull());

   // test IsAscii
   s10 = "\xb9";

   Ok(22, !s10.IsAscii());
   Ok(23, s.IsAscii());

   // some excercises with the Perl Compatible Regular Expressions
   TString s11("Food is on the foo table.");
   TPRegexp("\\b(foo)\\s+(\\w+)").Substitute(s11, "round $2");
   Ok(24, s11=="Food is on the round table.");

   TString s12("pepernotenkoek");
   TPRegexp("peper(.*)koek").Substitute(s12, "wal$1boom");
   Ok(25, s12=="walnotenboom");

   TString s13("hihi haha");
   TPRegexp("^([^ ]*) *([^ ]*)").Substitute(s13, "$2 $1");
   Ok(26, s13=="haha hihi");

   Ok(27, TPRegexp("^(\\w+) *(\\w+)").Match(s13) == 3);

   // test Resize and Strip
   s9.Prepend("   ");
   cout << s9 << endl;

   s9.Resize(50);
   cout << s9 << "<<ends here" << endl;

   cout << s9.Strip(TString::kBoth) << "<<ends here" << endl;

   Printf("Using Print: %s (%d)\n", (const char*) s9, s9.Length());

   TString s20 = "abc";
   TString s21 = "abcd";
   TString s22 = "bcde";
   TString s23 = "Bcde";

   Ok(28, s20 < s21);
   Ok(29, s21 < s22);
   Ok(30, s23 < s22);
   Ok(31, s22.CompareTo(s23, TString::kIgnoreCase) == 0);

   return 0;
}
<commit_msg>Also test operator< with empty strings<commit_after>// @(#)root/test:$Id$
// Author: Fons Rademakers   19/08/96

#include <stdlib.h>

#include "Riostream.h"
#include "TString.h"
#include "TRegexp.h"
#include "TPRegexp.h"

void Ok(int i, int b)
{
   cout << "Test " << i;
   if (b)
      cout << "   ok" << endl;
   else
      cout << "   NOT ok" << endl;
}

int main()
{
   // create base string
   TString s = "aap noot mies";
   cout << s << endl;

   // use different constructors and excercise +, += and == operators
   TString s1 = TString("aa") + "p ";
   s1 += TString("noot ") + "mi" + "es";
   cout << s1 << endl;
   Ok(1, s1==s);

   // use single char constructor and excercise again += and == operators
   TString s2 = 'a';
   s2 += "ap ";
   s2 += "noot ";
   s2 += "mies";
   cout << s2 << endl;
   Ok(2, s2==s);

   // get and set a subrange (via TSubString)
   TString s3 = s(4,9);
   s3(0,4) = "mama papa";
   cout << s3 << endl;
   Ok(3, s3=="mama papa mies");

   // create a regular expression, make search in string and replace
   // matched substring
   TRegexp re(" n.*t ");
   TString s4 = s;
   s4(re) = " pipo ";
   cout << s4 << endl;
   Ok(4, s4=="aap pipo mies");

   // use "const char*" operator and the Data() member function to access
   // the string as a const char*
   const char *a = (const char*)s;
   cout << a << endl;
   Ok(5, !strcmp(a, s.Data()));

   // return 13th character and replace it by 't', getting 14th character
   // should result in an error message since operator[] uses range checking
   TString s6 = s;
   s6[12] = 't';
   cout << s6 << endl;
   cout << "*** Error message ok, accessing intentionaly out-of-bounds" << endl;
   char b = s6[13];
   cout << b << endl;
   Ok(6, s6=="aap noot miet");

   // return 13th character and replace it by 'p', getting 14th character
   // should NOT result in an error message since operator() does not use
   // range checking
   TString s7 = s;
   s7(12) = 'p';
   cout << s7 << endl;
   char c = s7(13);
   cout << c << endl;
   Ok(7, s7=="aap noot miep");

   // use Append, Remove, Prepend, Replace and Insert
   TString s8 = s;
   s8.Append(" tante ");
   s8.Append(s7(9,4));
   cout << s8 << endl;

   s8.Remove(0,14);
   cout << s8 << endl;
   s8.Prepend("oom jan");
   cout << s8 << endl;
   s8.Insert(7," en ");
   cout << s8 << endl;
   s8.Replace(4,3,"jaap");
   cout << s8 << endl;
   Ok(8, s8=="oom jaap en tante miep");

   // use CompareTo to compare char * and TString
   TString s9 = s;
   Ok(9,  !s9.CompareTo(s));
   Ok(10, !s9.CompareTo("AAP NOOT MIES", TString::kIgnoreCase));

   // use Contains to find if "string" is contained
   Ok(11, s9.Contains("NooT", TString::kIgnoreCase));
   Ok(12, !s9.Contains("pipo"));

   // return the index to the first and last character 'c'
   Ok(13, s.First('o')==5);
   Ok(14, s.First('z')==kNPOS);
   Ok(15, s.Last('a')==1);
   Ok(16, s.Last('z')==kNPOS);

   // returns the index of the start of match
   Ok(17, s.Index("mies")==9);
   Ok(18, s.Index("aa",1)==kNPOS);

   // returns length of string
   Ok(19, s.Length()==13);

   // test IsNull
   TString s10;

   Ok(20, s10.IsNull());
   Ok(21, !s.IsNull());

   // test IsAscii
   s10 = "\xb9";

   Ok(22, !s10.IsAscii());
   Ok(23, s.IsAscii());

   // some excercises with the Perl Compatible Regular Expressions
   TString s11("Food is on the foo table.");
   TPRegexp("\\b(foo)\\s+(\\w+)").Substitute(s11, "round $2");
   Ok(24, s11=="Food is on the round table.");

   TString s12("pepernotenkoek");
   TPRegexp("peper(.*)koek").Substitute(s12, "wal$1boom");
   Ok(25, s12=="walnotenboom");

   TString s13("hihi haha");
   TPRegexp("^([^ ]*) *([^ ]*)").Substitute(s13, "$2 $1");
   Ok(26, s13=="haha hihi");

   Ok(27, TPRegexp("^(\\w+) *(\\w+)").Match(s13) == 3);

   // test Resize and Strip
   s9.Prepend("   ");
   cout << s9 << endl;

   s9.Resize(50);
   cout << s9 << "<<ends here" << endl;

   cout << s9.Strip(TString::kBoth) << "<<ends here" << endl;

   Printf("Using Print: %s (%d)\n", (const char*) s9, s9.Length());

   TString s20 = "abc";
   TString s21 = "abcd";
   TString s22 = "bcde";
   TString s23 = "Bcde";
   TString s24 = "";

   Ok(28, s20 < s21);
   Ok(29, s21 < s22);
   Ok(30, s23 < s22);
   Ok(31, s22.CompareTo(s23, TString::kIgnoreCase) == 0);
   Ok(32, (s23 < s24) != (s24 < s23));

   return 0;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// File: Tester.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Tester executable.
//
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <TestData.h>
#include <Metric.h>

#include <boost/filesystem.hpp>
#include <boost/version.hpp>
#include <boost/program_options.hpp>

using namespace std;
using namespace Nektar;

// Define some namespace aliases
namespace po = boost::program_options;
namespace fs = boost::filesystem;

string PortablePath(const boost::filesystem::path& path)
{
    boost::filesystem::path temp = path;
#if BOOST_VERSION > 104200
    temp.make_preferred();
    return temp.string();
#else
    return temp.file_string();
#endif
}

int main(int argc, char *argv[])
{
    int status = 0;
    string command;

    // Set up command line options.
    po::options_description desc("Available options");
    desc.add_options()
        ("help,h",                 "Produce this help message.")
        ("verbose,v",              "Turn on verbosity.")
        ("generate-metric,g",      po::value<vector<int> >(),
                                   "Generate a single metric.")
        ("generate-all-metrics,a", "Generate all metrics.");

    po::options_description hidden("Hidden options");
    hidden.add_options()
        ("input-file",   po::value<string>(), "Input filename");

    po::options_description cmdline_options;
    cmdline_options.add(hidden).add(desc);

    po::options_description visible("Allowed options");
    visible.add(desc);

    po::positional_options_description p;
    p.add("input-file", -1);

    po::variables_map vm;

    try
    {
        po::store(po::command_line_parser(argc, argv).
                  options(cmdline_options).positional(p).run(), vm);
        po::notify(vm);
    }
    catch (const exception& e)
    {
        cerr << e.what() << endl;
        cerr << desc;
        return 1;
    }

    if (vm.count("help") || vm.count("input-file") != 1) {
        cerr << "Usage: Tester [options] input-file.tst" << endl;
        cout << desc;
        return 1;
    }

    // Set up set containing metrics to be generated.
    vector<int> metricGenVec;
    if (vm.count("generate-metric"))
    {
        metricGenVec = vm["generate-metric"].as<vector<int> >();
        cout << "SIZE = " << metricGenVec.size() << endl;
    }
    set<int> metricGen(metricGenVec.begin(), metricGenVec.end());

    // Path to test definition file
    const fs::path specFile(vm["input-file"].as<string>());

    // Parent path of test definition file containing dependent files
    fs::path specPath = specFile.parent_path();

    if (specPath.empty())
    {
        specPath = fs::current_path();
    }

    // Temporary directory to create and in which to conduct test
    const fs::path tmpDir = fs::current_path()
                            / fs::path("tmp_" + specFile.stem().string());

    // The current directory
    const fs::path startDir = fs::current_path();

    try
    {
        // Parse the test file
        TestData file(specFile);

        // Generate the metric objects
        vector<MetricSharedPtr> metrics;
        for (unsigned int i = 0; i < file.GetNumMetrics(); ++i)
        {
            set<int>::iterator it = metricGen.find(file.GetMetricId(i));
            bool genMetric = it != metricGen.end() ||
                             (vm.count("generate-all-metrics") > 0);

            metrics.push_back( GetMetricFactory().CreateInstance(
                                                    file.GetMetricType(i),
                                                    file.GetMetric(i),
                                                    genMetric
                                                  ));

            if (it != metricGen.end())
            {
                metricGen.erase(it);
            }
        }

        if (metricGen.size() != 0)
        {
            string s = metricGen.size() == 1 ? "s" : "";
            set<int>::iterator it;
            cerr << "Unable to find metric"+s+" with ID"+s+" ";
            for (it = metricGen.begin(); it != metricGen.end(); ++it)
            {
                cerr << *it << " ";
            }
            cerr << endl;
            return 1;
        }

        // Remove the temporary directory if left from a previous test
        if (fs::exists(tmpDir))
        {
            fs::remove_all(tmpDir);
        }

        // Create temporary directory
        fs::create_directory(tmpDir);

        // Change working directory to the temporary directory
        fs::current_path(tmpDir);

        // Copy required files for this test from the test definition directory
        // to the temporary directory.
        for (unsigned int i = 0; i < file.GetNumDependentFiles(); ++i)
        {
            fs::path source_file(file.GetDependentFile(i).m_filename);

            fs::path source = specPath / source_file;
            fs::path dest   = tmpDir   / source_file;
            fs::copy_file(source, dest);
        }

        // Construct test command to run. If in debug mode, append "-g"
        // Output from stdout and stderr are directed to the files output.out
        // and output.err, respectively.
        if (file.GetNProcesses() > 1)
        {
            command += "mpirun -np "
                    + boost::lexical_cast<string>(file.GetNProcesses())
                    + " ";
        }

        // If executable doesn't exist in path then hope that it is in the
        // user's PATH environment variable.
        fs::path execPath = startDir / fs::path(file.GetExecutable());
        if (!fs::exists(execPath))
        {
            execPath = fs::path(file.GetExecutable());
        }

        command += PortablePath(execPath);
        command += " ";
        command += file.GetParameters();
        command += " 1>output.out 2>output.err";

        // Run executable to perform test.
        if (system(command.c_str()))
        {
            cerr << "Error occurred running test:" << endl;
            cerr << "Command: " << command << endl;
            throw 1;
        }

        // Check output files exist
        if (!(fs::exists("output.out") && fs::exists("output.err")))
        {
            cerr << "One or more test output files are missing." << endl;
            throw 1;
        }

        // Open output files and check they are readable
        ifstream vStdout("output.out");
        ifstream vStderr("output.err");
        if (vStdout.bad() || vStderr.bad())
        {
            cerr << "One or more test output files are unreadable." << endl;
            throw 1;
        }

        // Test against all metrics
        status = 0;
        for (int i = 0; i < metrics.size(); ++i)
        {
            vStdout.clear();
            vStderr.clear();
            vStdout.seekg(0, ios::beg);
            vStderr.seekg(0, ios::beg);
            if (!metrics[i]->Test(vStdout, vStderr))
            {
                status = 1;
            }
        }

        // Change back to the original path and delete temporary directory
        fs::current_path(startDir);
        fs::remove_all(tmpDir);

        // Save any changes.
        if (vm.count("generate-metric")      > 0 ||
            vm.count("generate-all-metrics") > 0)
        {
            file.SaveFile();
        }

        // Return status of test. 0 = PASS, 1 = FAIL
        return status;
    }
    catch (const fs::filesystem_error& e)
    {
        cerr << "Filesystem operation error occurred:" << endl;
        cerr << "  " << e.what() << endl;
        cerr << "  Files left in " << tmpDir.string() << endl;
    }
    catch (...)
    {
        cerr << "  Files left in " << tmpDir.string() << endl;
    }

    // If a system error, return 2
    return 2;
}
<commit_msg>Another fix for boost less than 1.42.<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// File: Tester.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Tester executable.
//
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <TestData.h>
#include <Metric.h>

#include <boost/filesystem.hpp>
#include <boost/version.hpp>
#include <boost/program_options.hpp>

using namespace std;
using namespace Nektar;

// Define some namespace aliases
namespace po = boost::program_options;
namespace fs = boost::filesystem;

string PortablePath(const boost::filesystem::path& path)
{
    boost::filesystem::path temp = path;
#if BOOST_VERSION > 104200
    temp.make_preferred();
    return temp.string();
#else
    return temp.file_string();
#endif
}

int main(int argc, char *argv[])
{
    int status = 0;
    string command;

    // Set up command line options.
    po::options_description desc("Available options");
    desc.add_options()
        ("help,h",                 "Produce this help message.")
        ("verbose,v",              "Turn on verbosity.")
        ("generate-metric,g",      po::value<vector<int> >(),
                                   "Generate a single metric.")
        ("generate-all-metrics,a", "Generate all metrics.");

    po::options_description hidden("Hidden options");
    hidden.add_options()
        ("input-file",   po::value<string>(), "Input filename");

    po::options_description cmdline_options;
    cmdline_options.add(hidden).add(desc);

    po::options_description visible("Allowed options");
    visible.add(desc);

    po::positional_options_description p;
    p.add("input-file", -1);

    po::variables_map vm;

    try
    {
        po::store(po::command_line_parser(argc, argv).
                  options(cmdline_options).positional(p).run(), vm);
        po::notify(vm);
    }
    catch (const exception& e)
    {
        cerr << e.what() << endl;
        cerr << desc;
        return 1;
    }

    if (vm.count("help") || vm.count("input-file") != 1) {
        cerr << "Usage: Tester [options] input-file.tst" << endl;
        cout << desc;
        return 1;
    }

    // Set up set containing metrics to be generated.
    vector<int> metricGenVec;
    if (vm.count("generate-metric"))
    {
        metricGenVec = vm["generate-metric"].as<vector<int> >();
        cout << "SIZE = " << metricGenVec.size() << endl;
    }
    set<int> metricGen(metricGenVec.begin(), metricGenVec.end());

    // Path to test definition file
    const fs::path specFile(vm["input-file"].as<string>());

    // Parent path of test definition file containing dependent files
    fs::path specPath = specFile.parent_path();

    if (specPath.empty())
    {
        specPath = fs::current_path();
    }

#if BOOST_VERSION > 104200
    string specFileStem = specFile.stem().string();
#else
    string specFileStem = specFile.stem().file_string();
#endif

    // Temporary directory to create and in which to conduct test
    const fs::path tmpDir = fs::current_path()
        / fs::path("tmp_" + specFileStem);

    // The current directory
    const fs::path startDir = fs::current_path();

    try
    {
        // Parse the test file
        TestData file(specFile);

        // Generate the metric objects
        vector<MetricSharedPtr> metrics;
        for (unsigned int i = 0; i < file.GetNumMetrics(); ++i)
        {
            set<int>::iterator it = metricGen.find(file.GetMetricId(i));
            bool genMetric = it != metricGen.end() ||
                             (vm.count("generate-all-metrics") > 0);

            metrics.push_back( GetMetricFactory().CreateInstance(
                                                    file.GetMetricType(i),
                                                    file.GetMetric(i),
                                                    genMetric
                                                  ));

            if (it != metricGen.end())
            {
                metricGen.erase(it);
            }
        }

        if (metricGen.size() != 0)
        {
            string s = metricGen.size() == 1 ? "s" : "";
            set<int>::iterator it;
            cerr << "Unable to find metric"+s+" with ID"+s+" ";
            for (it = metricGen.begin(); it != metricGen.end(); ++it)
            {
                cerr << *it << " ";
            }
            cerr << endl;
            return 1;
        }

        // Remove the temporary directory if left from a previous test
        if (fs::exists(tmpDir))
        {
            fs::remove_all(tmpDir);
        }

        // Create temporary directory
        fs::create_directory(tmpDir);

        // Change working directory to the temporary directory
        fs::current_path(tmpDir);

        // Copy required files for this test from the test definition directory
        // to the temporary directory.
        for (unsigned int i = 0; i < file.GetNumDependentFiles(); ++i)
        {
            fs::path source_file(file.GetDependentFile(i).m_filename);

            fs::path source = specPath / source_file;
            fs::path dest   = tmpDir   / source_file;
            fs::copy_file(source, dest);
        }

        // Construct test command to run. If in debug mode, append "-g"
        // Output from stdout and stderr are directed to the files output.out
        // and output.err, respectively.
        if (file.GetNProcesses() > 1)
        {
            command += "mpirun -np "
                    + boost::lexical_cast<string>(file.GetNProcesses())
                    + " ";
        }

        // If executable doesn't exist in path then hope that it is in the
        // user's PATH environment variable.
        fs::path execPath = startDir / fs::path(file.GetExecutable());
        if (!fs::exists(execPath))
        {
            execPath = fs::path(file.GetExecutable());
        }

        command += PortablePath(execPath);
        command += " ";
        command += file.GetParameters();
        command += " 1>output.out 2>output.err";

        // Run executable to perform test.
        if (system(command.c_str()))
        {
            cerr << "Error occurred running test:" << endl;
            cerr << "Command: " << command << endl;
            throw 1;
        }

        // Check output files exist
        if (!(fs::exists("output.out") && fs::exists("output.err")))
        {
            cerr << "One or more test output files are missing." << endl;
            throw 1;
        }

        // Open output files and check they are readable
        ifstream vStdout("output.out");
        ifstream vStderr("output.err");
        if (vStdout.bad() || vStderr.bad())
        {
            cerr << "One or more test output files are unreadable." << endl;
            throw 1;
        }

        // Test against all metrics
        status = 0;
        for (int i = 0; i < metrics.size(); ++i)
        {
            vStdout.clear();
            vStderr.clear();
            vStdout.seekg(0, ios::beg);
            vStderr.seekg(0, ios::beg);
            if (!metrics[i]->Test(vStdout, vStderr))
            {
                status = 1;
            }
        }

        // Change back to the original path and delete temporary directory
        fs::current_path(startDir);
        fs::remove_all(tmpDir);

        // Save any changes.
        if (vm.count("generate-metric")      > 0 ||
            vm.count("generate-all-metrics") > 0)
        {
            file.SaveFile();
        }

        // Return status of test. 0 = PASS, 1 = FAIL
        return status;
    }
    catch (const fs::filesystem_error& e)
    {
        cerr << "Filesystem operation error occurred:" << endl;
        cerr << "  " << e.what() << endl;
        cerr << "  Files left in " << tmpDir.string() << endl;
    }
    catch (...)
    {
        cerr << "  Files left in " << tmpDir.string() << endl;
    }

    // If a system error, return 2
    return 2;
}
<|endoftext|>


<commit_before>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <blackhole/extensions/facade.hpp>

#include "mocks/logger.hpp"

#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)

#if GCC_VERSION < 40900

namespace std {

template<typename T>
auto operator==(const std::reference_wrapper<T>& lhs, const std::reference_wrapper<T>& rhs) -> bool {
    return lhs.get() == rhs.get();
}

}  // namespace std

#endif

namespace blackhole {
namespace testing {

using ::testing::ByRef;
using ::testing::InvokeArgument;
using ::testing::_;

typedef mock::logger_t logger_type;

TEST(Facade, PrimitiveLog) {
    const logger_type inner{};
    const logger_facade<logger_type> logger(inner);

    EXPECT_CALL(inner, log(0, string_view("GET /porn.png HTTP/1.0")))
        .Times(1);

    logger.log(0, "GET /porn.png HTTP/1.0");
}

TEST(Facade, AttributeLog) {
    const logger_type inner{};
    const logger_facade<logger_type> logger(inner);

    const attribute_list attributes{{"key#1", {42}}};
    attribute_pack expected{attributes};

    EXPECT_CALL(inner, log(0, string_view("GET /porn.png HTTP/1.0"), expected))
        .Times(1);

    logger.log(0, "GET /porn.png HTTP/1.0", attribute_list{
        {"key#1", {42}}
    });
}

TEST(Facade, FormattedLog) {
    const logger_type inner{};
    const logger_facade<logger_type> logger(inner);

    attribute_pack expected;
    writer_t writer;

    EXPECT_CALL(inner, log(0, string_view("GET /porn.png HTTP/1.0 - {}"), expected, _))
        .Times(1)
        .WillOnce(InvokeArgument<3>(ByRef(writer)));

    logger.log(0, "GET /porn.png HTTP/1.0 - {}", 42);

    EXPECT_EQ("GET /porn.png HTTP/1.0 - 42", writer.inner.str());
}

TEST(Facade, FormattedAttributeLog) {
    const logger_type inner{};
    const logger_facade<logger_type> logger(inner);

    const attribute_list attributes{{"key#1", {42}}};
    attribute_pack expected{attributes};
    writer_t writer;

    EXPECT_CALL(inner, log(0, string_view("GET /porn.png HTTP/1.0 - {}"), expected, _))
        .Times(1)
        .WillOnce(InvokeArgument<3>(ByRef(writer)));

    logger.log(0, "GET /porn.png HTTP/1.0 - {}", 2345, attribute_list{
        {"key#1", {42}}
    });

    EXPECT_EQ("GET /porn.png HTTP/1.0 - 2345", writer.inner.str());
}

}  // namespace testing
}  // namespace blackhole
<commit_msg>fix(gcc): fix reference wrapper compare on 4.9<commit_after>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <blackhole/extensions/facade.hpp>

#include "mocks/logger.hpp"

#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)

#if GCC_VERSION < 50000

namespace std {

template<typename T>
auto operator==(const std::reference_wrapper<T>& lhs, const std::reference_wrapper<T>& rhs) -> bool {
    return lhs.get() == rhs.get();
}

}  // namespace std

#endif

namespace blackhole {
namespace testing {

using ::testing::ByRef;
using ::testing::InvokeArgument;
using ::testing::_;

typedef mock::logger_t logger_type;

TEST(Facade, PrimitiveLog) {
    const logger_type inner{};
    const logger_facade<logger_type> logger(inner);

    EXPECT_CALL(inner, log(0, string_view("GET /porn.png HTTP/1.0")))
        .Times(1);

    logger.log(0, "GET /porn.png HTTP/1.0");
}

TEST(Facade, AttributeLog) {
    const logger_type inner{};
    const logger_facade<logger_type> logger(inner);

    const attribute_list attributes{{"key#1", {42}}};
    attribute_pack expected{attributes};

    EXPECT_CALL(inner, log(0, string_view("GET /porn.png HTTP/1.0"), expected))
        .Times(1);

    logger.log(0, "GET /porn.png HTTP/1.0", attribute_list{
        {"key#1", {42}}
    });
}

TEST(Facade, FormattedLog) {
    const logger_type inner{};
    const logger_facade<logger_type> logger(inner);

    attribute_pack expected;
    writer_t writer;

    EXPECT_CALL(inner, log(0, string_view("GET /porn.png HTTP/1.0 - {}"), expected, _))
        .Times(1)
        .WillOnce(InvokeArgument<3>(ByRef(writer)));

    logger.log(0, "GET /porn.png HTTP/1.0 - {}", 42);

    EXPECT_EQ("GET /porn.png HTTP/1.0 - 42", writer.inner.str());
}

TEST(Facade, FormattedAttributeLog) {
    const logger_type inner{};
    const logger_facade<logger_type> logger(inner);

    const attribute_list attributes{{"key#1", {42}}};
    attribute_pack expected{attributes};
    writer_t writer;

    EXPECT_CALL(inner, log(0, string_view("GET /porn.png HTTP/1.0 - {}"), expected, _))
        .Times(1)
        .WillOnce(InvokeArgument<3>(ByRef(writer)));

    logger.log(0, "GET /porn.png HTTP/1.0 - {}", 2345, attribute_list{
        {"key#1", {42}}
    });

    EXPECT_EQ("GET /porn.png HTTP/1.0 - 2345", writer.inner.str());
}

}  // namespace testing
}  // namespace blackhole
<|endoftext|>


<commit_before>//----------------------------  rt_7.cc  ---------------------------
//    rt_7.cc,v 1.3 2003/06/09 16:00:38 wolf Exp
//    Version:
//
//    Copyright (C) 2003, 2005 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  rt_7.cc  ---------------------------

// RT(2) had some problems with shape functions...

#include "../tests.h"
#include <base/quadrature_lib.h>
#include <base/logstream.h>
#include <lac/vector.h>
#include <grid/tria.h>
#include <grid/tria_iterator.h>
#include <dofs/dof_accessor.h>
#include <grid/grid_generator.h>
#include <grid/grid_tools.h>
#include <fe/fe_raviart_thomas.h>
#include <fe/fe_values.h>

#include <vector>
#include <fstream>
#include <string>

#define PRECISION 2

template<int dim>
void
plot_shape_functions(const unsigned int degree)
{
  FE_RaviartThomasNodal<dim> fe_rt(degree);
  Triangulation<dim> tr;
  GridGenerator::hyper_cube(tr, 0., 1.);

  DoFHandler<dim> dof(tr);
  typename DoFHandler<dim>::cell_iterator c = dof.begin();
  dof.distribute_dofs(fe_rt);

  QTrapez<1> q_trapez;
  const unsigned int div=10;
  QIterated<dim> q(q_trapez, div);
  FEValues<dim> fe(fe_rt, q, update_values|update_gradients|update_q_points);
  fe.reinit(c);

  Assert (fe.get_fe().n_components() == dim, ExcInternalError());

  for (unsigned int q_point=0; q_point<q.n_quadrature_points; ++q_point)
    {
      if (q_point % QIterated<1>(q_trapez,div).n_quadrature_points == 0)
        deallog << std::endl;

      deallog << fe.quadrature_point(q_point) << " ";

      for (unsigned int i=0;i<fe_rt.dofs_per_cell;++i)
        for (unsigned int c=0; c<fe.get_fe().n_components(); ++c)
          deallog << " " << fe.shape_value_component(i,q_point,c);

      deallog << std::endl;
    }
}

int
main()
{
  std::ofstream logfile ("rt_7.output");
  logfile.precision (PRECISION);
  logfile.setf(std::ios::fixed);
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  plot_shape_functions<2>(2);

  return 0;
}

<commit_msg>The element should have been simply RT, not RTNodal.<commit_after>//----------------------------  rt_7.cc  ---------------------------
//    rt_7.cc,v 1.3 2003/06/09 16:00:38 wolf Exp
//    Version:
//
//    Copyright (C) 2003, 2005 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  rt_7.cc  ---------------------------

// RT(2) had some problems with shape functions...

#include "../tests.h"
#include <base/quadrature_lib.h>
#include <base/logstream.h>
#include <lac/vector.h>
#include <grid/tria.h>
#include <grid/tria_iterator.h>
#include <dofs/dof_accessor.h>
#include <grid/grid_generator.h>
#include <grid/grid_tools.h>
#include <fe/fe_raviart_thomas.h>
#include <fe/fe_values.h>

#include <vector>
#include <fstream>
#include <string>

#define PRECISION 2

template<int dim>
void
plot_shape_functions(const unsigned int degree)
{
  FE_RaviartThomas<dim> fe_rt(degree);
  Triangulation<dim> tr;
  GridGenerator::hyper_cube(tr, 0., 1.);

  DoFHandler<dim> dof(tr);
  typename DoFHandler<dim>::cell_iterator c = dof.begin();
  dof.distribute_dofs(fe_rt);

  QTrapez<1> q_trapez;
  const unsigned int div=10;
  QIterated<dim> q(q_trapez, div);
  FEValues<dim> fe(fe_rt, q, update_values|update_gradients|update_q_points);
  fe.reinit(c);

  Assert (fe.get_fe().n_components() == dim, ExcInternalError());

  for (unsigned int q_point=0; q_point<q.n_quadrature_points; ++q_point)
    {
      if (q_point % QIterated<1>(q_trapez,div).n_quadrature_points == 0)
        deallog << std::endl;

      deallog << fe.quadrature_point(q_point) << " ";

      for (unsigned int i=0;i<fe_rt.dofs_per_cell;++i)
        for (unsigned int c=0; c<fe.get_fe().n_components(); ++c)
          deallog << " " << fe.shape_value_component(i,q_point,c);

      deallog << std::endl;
    }
}

int
main()
{
  std::ofstream logfile ("rt_7.output");
  logfile.precision (PRECISION);
  logfile.setf(std::ios::fixed);
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  plot_shape_functions<2>(2);

  return 0;
}

<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include <blackhole/record.hpp>

namespace blackhole {
namespace testing {

TEST(Record, Severity) {
    const view_of<attributes_t>::type attributes{{"key#1", {42}}};
    attribute_pack pack{};

    record_t record(42, "GET /porn.png HTTP/1.1", pack);

    EXPECT_EQ(42, record.severity());
}

TEST(Record, Message) {
    const view_of<attributes_t>::type attributes{{"key#1", {42}}};
    attribute_pack pack{};

    record_t record(42, "GET /porn.png HTTP/1.1", pack);

    EXPECT_EQ("GET /porn.png HTTP/1.1", record.message().to_string());
}

}  // namespace testing
}  // namespace blackhole
<commit_msg>chore(tests): eliminate unused code<commit_after>#include <gtest/gtest.h>

#include <blackhole/record.hpp>

namespace blackhole {
namespace testing {

TEST(Record, Severity) {
    attribute_pack pack{};

    record_t record(42, "GET /porn.png HTTP/1.1", pack);

    EXPECT_EQ(42, record.severity());
}

TEST(Record, Message) {
    attribute_pack pack{};

    record_t record(42, "GET /porn.png HTTP/1.1", pack);

    EXPECT_EQ("GET /porn.png HTTP/1.1", record.message().to_string());
}

}  // namespace testing
}  // namespace blackhole
<|endoftext|>


<commit_before>//===-- R600KernelParameters.cpp - Lower kernel function arguments --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass lowers kernel function arguments to loads from the vertex buffer.
//
// Kernel arguemnts are stored in the vertex buffer at an offset of 9 dwords,
// so arg0 needs to be loaded from VTX_BUFFER[9] and arg1 is loaded from
// VTX_BUFFER[10], etc.
//
//===----------------------------------------------------------------------===//

#include "AMDGPU.h"
#include "AMDIL.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Intrinsics.h"
#include "llvm/IRBuilder.h"
#include "llvm/Metadata.h"
#include "llvm/Module.h"
#include "llvm/TypeBuilder.h"
#include "llvm/Target/TargetData.h"

#include <map>
#include <set>

using namespace llvm;

namespace {

#define CONSTANT_CACHE_SIZE_DW 127

class R600KernelParameters : public FunctionPass {
  const TargetData *TD;
  LLVMContext* Context;
  Module *Mod;

  struct Param {
    Param() : Val(NULL), PtrVal(NULL), OffsetInDW(0), SizeInDW(0),
              IsIndirect(true), SpecialID(0) {}

    Value* Val;
    Value* PtrVal;
    int OffsetInDW;
    int SizeInDW;

    bool IsIndirect;

    std::string SpecialType;
    int SpecialID;

    int End() { return OffsetInDW + SizeInDW; }
    // The first 9 dwords are reserved for the grid sizes.
    int getRatOffset() { return 9 + OffsetInDW; }
  };

  std::vector<Param> Params;

  bool IsOpenCLKernel(const Function *Fun);
  int getLastSpecialID(const std::string& TypeName);

  int getListSize();
  void AddParam(Argument *Arg);
  int CalculateArgumentSize(Argument *Arg);
  void RunAna(Function *Fun);
  void Replace(Function *Fun);
  bool IsIndirect(Value *Val, std::set<Value*> &Visited);
  void Propagate(Function* Fun);
  void Propagate(Value *V, const Twine &Name, bool IsIndirect = true);
  Value* ConstantRead(Function *Fun, Param &P);
  Value* handleSpecial(Function *Fun, Param &P);
  bool IsSpecialType(Type *T);
  std::string getSpecialTypeName(Type *T);
public:
  static char ID;
  R600KernelParameters() : FunctionPass(ID) {}
  R600KernelParameters(const TargetData* TD) : FunctionPass(ID), TD(TD) {}
  bool runOnFunction (Function &F);
  void getAnalysisUsage(AnalysisUsage &AU) const;
  const char *getPassName() const;
  bool doInitialization(Module &M);
  bool doFinalization(Module &M);
};

char R600KernelParameters::ID = 0;

static RegisterPass<R600KernelParameters> X("kerparam",
                            "OpenCL Kernel Parameter conversion", false, false);

bool R600KernelParameters::IsOpenCLKernel(const Function* Fun) {
  Module *Mod = const_cast<Function*>(Fun)->getParent();
  NamedMDNode * MD = Mod->getOrInsertNamedMetadata("opencl.kernels");

  if (!MD or !MD->getNumOperands()) {
    return false;
  }

  for (int i = 0; i < int(MD->getNumOperands()); i++) {
    if (!MD->getOperand(i) or !MD->getOperand(i)->getOperand(0)) {
      continue;
    }

    assert(MD->getOperand(i)->getNumOperands() == 1);

    if (MD->getOperand(i)->getOperand(0)->getName() == Fun->getName()) {
      return true;
    }
  }

  return false;
}

int R600KernelParameters::getLastSpecialID(const std::string &TypeName) {
  int LastID = -1;

  for (std::vector<Param>::iterator i = Params.begin(); i != Params.end(); i++) {
    if (i->SpecialType == TypeName) {
      LastID = i->SpecialID;
    }
  }

  return LastID;
}

int R600KernelParameters::getListSize() {
  if (Params.size() == 0) {
    return 0;
  }

  return Params.back().End();
}

bool R600KernelParameters::IsIndirect(Value *Val, std::set<Value*> &Visited) {
  //XXX Direct parameters are not supported yet, so return true here.
  return true;
#if 0
  if (isa<LoadInst>(Val)) {
    return false;
  }

  if (isa<IntegerType>(Val->getType())) {
    assert(0 and "Internal error");
    return false;
  }

  if (Visited.count(Val)) {
    return false;
  }

  Visited.insert(Val);

  if (isa<getElementPtrInst>(Val)) {
    getElementPtrInst* GEP = dyn_cast<getElementPtrInst>(Val);
    getElementPtrInst::op_iterator I = GEP->op_begin();

    for (++I; I != GEP->op_end(); ++I) {
      if (!isa<Constant>(*I)) {
        return true;
      }
    }
  }

  for (Value::use_iterator I = Val->use_begin(); i != Val->use_end(); ++I) {
    Value* V2 = dyn_cast<Value>(*I);

    if (V2) {
      if (IsIndirect(V2, Visited)) {
        return true;
      }
    }
  }

  return false;
#endif
}

void R600KernelParameters::AddParam(Argument *Arg) {
  Param P;

  P.Val = dyn_cast<Value>(Arg);
  P.OffsetInDW = getListSize();
  P.SizeInDW = CalculateArgumentSize(Arg);

  if (isa<PointerType>(Arg->getType()) and Arg->hasByValAttr()) {
    std::set<Value*> Visited;
    P.IsIndirect = IsIndirect(P.Val, Visited);
  }

  Params.push_back(P);
}

int R600KernelParameters::CalculateArgumentSize(Argument *Arg) {
  Type* T = Arg->getType();

  if (Arg->hasByValAttr() and dyn_cast<PointerType>(T)) {
    T = dyn_cast<PointerType>(T)->getElementType();
  }

  int StoreSizeInDW = (TD->getTypeStoreSize(T) + 3)/4;

  assert(StoreSizeInDW);

  return StoreSizeInDW;
}

void R600KernelParameters::RunAna(Function* Fun) {
  assert(IsOpenCLKernel(Fun));

  for (Function::arg_iterator I = Fun->arg_begin(); I != Fun->arg_end(); ++I) {
    AddParam(I);
  }

}

void R600KernelParameters::Replace(Function* Fun) {
  for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
    Value *NewVal;

    if (IsSpecialType(I->Val->getType())) {
      NewVal = handleSpecial(Fun, *I);
    } else {
      NewVal = ConstantRead(Fun, *I);
    }
    if (NewVal) {
      I->Val->replaceAllUsesWith(NewVal);
    }
  }
}

void R600KernelParameters::Propagate(Function* Fun) {
  for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
    if (I->PtrVal) {
      Propagate(I->PtrVal, I->Val->getName(), I->IsIndirect);
    }
  }
}

void R600KernelParameters::Propagate(Value* V, const Twine& Name, bool IsIndirect) {
  LoadInst* Load = dyn_cast<LoadInst>(V);
  GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V);

  unsigned Addrspace;

  if (IsIndirect) {
    Addrspace = AMDILAS::PARAM_I_ADDRESS;
  }  else {
    Addrspace = AMDILAS::PARAM_D_ADDRESS;
  }

  if (GEP and GEP->getType()->getAddressSpace() != Addrspace) {
    Value *Op = GEP->getPointerOperand();

    if (dyn_cast<PointerType>(Op->getType())->getAddressSpace() != Addrspace) {
      Op = new BitCastInst(Op, PointerType::get(dyn_cast<PointerType>(
                           Op->getType())->getElementType(), Addrspace),
                           Name, dyn_cast<Instruction>(V));
    }

    std::vector<Value*> Params(GEP->idx_begin(), GEP->idx_end());

    GetElementPtrInst* GEP2 = GetElementPtrInst::Create(Op, Params, Name,
                                                      dyn_cast<Instruction>(V));
    GEP2->setIsInBounds(GEP->isInBounds());
    V = dyn_cast<Value>(GEP2);
    GEP->replaceAllUsesWith(GEP2);
    GEP->eraseFromParent();
    Load = NULL;
  }

  if (Load) {
    ///normally at this point we have the right address space
    if (Load->getPointerAddressSpace() != Addrspace) {
      Value *OrigPtr = Load->getPointerOperand();
      PointerType *OrigPtrType = dyn_cast<PointerType>(OrigPtr->getType());

      Type* NewPtrType = PointerType::get(OrigPtrType->getElementType(),
                                            Addrspace);

      Value* NewPtr = OrigPtr;

      if (OrigPtr->getType() != NewPtrType) {
        NewPtr = new BitCastInst(OrigPtr, NewPtrType, "prop_cast", Load);
      }

      Value* new_Load = new LoadInst(NewPtr, Name, Load);
      Load->replaceAllUsesWith(new_Load);
      Load->eraseFromParent();
    }

    return;
  }

  std::vector<User*> Users(V->use_begin(), V->use_end());

  for (int i = 0; i < int(Users.size()); i++) {
    Value* V2 = dyn_cast<Value>(Users[i]);

    if (V2) {
      Propagate(V2, Name, IsIndirect);
    }
  }
}

Value* R600KernelParameters::ConstantRead(Function *Fun, Param &P) {
  assert(Fun->front().begin() != Fun->front().end());

  Instruction *FirstInst = Fun->front().begin();
  IRBuilder <> Builder (FirstInst);
/* First 3 dwords are reserved for the dimmension info */

  if (!P.Val->hasNUsesOrMore(1)) {
    return NULL;
  }
  unsigned Addrspace;

  if (P.IsIndirect) {
    Addrspace = AMDILAS::PARAM_I_ADDRESS;
  } else {
    Addrspace = AMDILAS::PARAM_D_ADDRESS;
  }

  Argument *Arg = dyn_cast<Argument>(P.Val);
  Type * ArgType = P.Val->getType();
  PointerType * ArgPtrType = dyn_cast<PointerType>(P.Val->getType());

  if (ArgPtrType and Arg->hasByValAttr()) {
    Value* ParamAddrSpacePtr = ConstantPointerNull::get(
                                    PointerType::get(Type::getInt32Ty(*Context),
                                    Addrspace));
    Value* ParamPtr = GetElementPtrInst::Create(ParamAddrSpacePtr,
                                    ConstantInt::get(Type::getInt32Ty(*Context),
                                    P.getRatOffset()), Arg->getName(),
                                    FirstInst);
    ParamPtr = new BitCastInst(ParamPtr,
                                PointerType::get(ArgPtrType->getElementType(),
                                                 Addrspace),
                                Arg->getName(), FirstInst);
    P.PtrVal = ParamPtr;
    return ParamPtr;
  } else {
    Value *ParamAddrSpacePtr = ConstantPointerNull::get(PointerType::get(
                                                        ArgType, Addrspace));

    Value *ParamPtr = Builder.CreateGEP(ParamAddrSpacePtr,
             ConstantInt::get(Type::getInt32Ty(*Context), P.getRatOffset()),
                              Arg->getName());

    Value *Param_Value = Builder.CreateLoad(ParamPtr, Arg->getName());

    return Param_Value;
  }
}

Value* R600KernelParameters::handleSpecial(Function* Fun, Param& P) {
  std::string Name = getSpecialTypeName(P.Val->getType());
  int ID;

  assert(!Name.empty());

  if (Name == "image2d_t" or Name == "image3d_t") {
    int LastID = std::max(getLastSpecialID("image2d_t"),
                     getLastSpecialID("image3d_t"));

    if (LastID == -1) {
      ID = 2; ///ID0 and ID1 are used internally by the driver
    } else {
      ID = LastID + 1;
    }
  } else if (Name == "sampler_t") {
    int LastID = getLastSpecialID("sampler_t");

    if (LastID == -1) {
      ID = 0;
    } else {
      ID = LastID + 1;
    }
  } else {
    ///TODO: give some error message
    return NULL;
  }

  P.SpecialType = Name;
  P.SpecialID = ID;

  Instruction *FirstInst = Fun->front().begin();

  return new IntToPtrInst(ConstantInt::get(Type::getInt32Ty(*Context),
                                           P.SpecialID), P.Val->getType(),
                                           "resourceID", FirstInst);
}

bool R600KernelParameters::IsSpecialType(Type* T) {
  return !getSpecialTypeName(T).empty();
}

std::string R600KernelParameters::getSpecialTypeName(Type* T) {
  PointerType *PT = dyn_cast<PointerType>(T);
  StructType *ST = NULL;

  if (PT) {
    ST = dyn_cast<StructType>(PT->getElementType());
  }

  if (ST) {
    std::string Prefix = "struct.opencl_builtin_type_";

    std::string Name = ST->getName().str();

    if (Name.substr(0, Prefix.length()) == Prefix) {
      return Name.substr(Prefix.length(), Name.length());
    }
  }

  return "";
}

bool R600KernelParameters::runOnFunction (Function &F) {
  if (!IsOpenCLKernel(&F)) {
    return false;
  }

  RunAna(&F);
  Replace(&F);
  Propagate(&F);

  return false;
}

void R600KernelParameters::getAnalysisUsage(AnalysisUsage &AU) const {
  FunctionPass::getAnalysisUsage(AU);
  AU.setPreservesAll();
}

const char *R600KernelParameters::getPassName() const {
  return "OpenCL Kernel parameter conversion to memory";
}

bool R600KernelParameters::doInitialization(Module &M) {
  Context = &M.getContext();
  Mod = &M;

  return false;
}

bool R600KernelParameters::doFinalization(Module &M) {
  return false;
}

} // End anonymous namespace

FunctionPass* llvm::createR600KernelParametersPass(const TargetData* TD) {
  return new R600KernelParameters(TD);
}
<commit_msg>Revert "Target/AMDGPU/R600KernelParameters.cpp: Fix two includes, <llvm/IRBuilder.h> and <llvm/TypeBuilder.h>"<commit_after>//===-- R600KernelParameters.cpp - Lower kernel function arguments --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass lowers kernel function arguments to loads from the vertex buffer.
//
// Kernel arguemnts are stored in the vertex buffer at an offset of 9 dwords,
// so arg0 needs to be loaded from VTX_BUFFER[9] and arg1 is loaded from
// VTX_BUFFER[10], etc.
//
//===----------------------------------------------------------------------===//

#include "AMDGPU.h"
#include "AMDIL.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Intrinsics.h"
#include "llvm/Metadata.h"
#include "llvm/Module.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/TypeBuilder.h"

#include <map>
#include <set>

using namespace llvm;

namespace {

#define CONSTANT_CACHE_SIZE_DW 127

class R600KernelParameters : public FunctionPass {
  const TargetData *TD;
  LLVMContext* Context;
  Module *Mod;

  struct Param {
    Param() : Val(NULL), PtrVal(NULL), OffsetInDW(0), SizeInDW(0),
              IsIndirect(true), SpecialID(0) {}

    Value* Val;
    Value* PtrVal;
    int OffsetInDW;
    int SizeInDW;

    bool IsIndirect;

    std::string SpecialType;
    int SpecialID;

    int End() { return OffsetInDW + SizeInDW; }
    // The first 9 dwords are reserved for the grid sizes.
    int getRatOffset() { return 9 + OffsetInDW; }
  };

  std::vector<Param> Params;

  bool IsOpenCLKernel(const Function *Fun);
  int getLastSpecialID(const std::string& TypeName);

  int getListSize();
  void AddParam(Argument *Arg);
  int CalculateArgumentSize(Argument *Arg);
  void RunAna(Function *Fun);
  void Replace(Function *Fun);
  bool IsIndirect(Value *Val, std::set<Value*> &Visited);
  void Propagate(Function* Fun);
  void Propagate(Value *V, const Twine &Name, bool IsIndirect = true);
  Value* ConstantRead(Function *Fun, Param &P);
  Value* handleSpecial(Function *Fun, Param &P);
  bool IsSpecialType(Type *T);
  std::string getSpecialTypeName(Type *T);
public:
  static char ID;
  R600KernelParameters() : FunctionPass(ID) {}
  R600KernelParameters(const TargetData* TD) : FunctionPass(ID), TD(TD) {}
  bool runOnFunction (Function &F);
  void getAnalysisUsage(AnalysisUsage &AU) const;
  const char *getPassName() const;
  bool doInitialization(Module &M);
  bool doFinalization(Module &M);
};

char R600KernelParameters::ID = 0;

static RegisterPass<R600KernelParameters> X("kerparam",
                            "OpenCL Kernel Parameter conversion", false, false);

bool R600KernelParameters::IsOpenCLKernel(const Function* Fun) {
  Module *Mod = const_cast<Function*>(Fun)->getParent();
  NamedMDNode * MD = Mod->getOrInsertNamedMetadata("opencl.kernels");

  if (!MD or !MD->getNumOperands()) {
    return false;
  }

  for (int i = 0; i < int(MD->getNumOperands()); i++) {
    if (!MD->getOperand(i) or !MD->getOperand(i)->getOperand(0)) {
      continue;
    }

    assert(MD->getOperand(i)->getNumOperands() == 1);

    if (MD->getOperand(i)->getOperand(0)->getName() == Fun->getName()) {
      return true;
    }
  }

  return false;
}

int R600KernelParameters::getLastSpecialID(const std::string &TypeName) {
  int LastID = -1;

  for (std::vector<Param>::iterator i = Params.begin(); i != Params.end(); i++) {
    if (i->SpecialType == TypeName) {
      LastID = i->SpecialID;
    }
  }

  return LastID;
}

int R600KernelParameters::getListSize() {
  if (Params.size() == 0) {
    return 0;
  }

  return Params.back().End();
}

bool R600KernelParameters::IsIndirect(Value *Val, std::set<Value*> &Visited) {
  //XXX Direct parameters are not supported yet, so return true here.
  return true;
#if 0
  if (isa<LoadInst>(Val)) {
    return false;
  }

  if (isa<IntegerType>(Val->getType())) {
    assert(0 and "Internal error");
    return false;
  }

  if (Visited.count(Val)) {
    return false;
  }

  Visited.insert(Val);

  if (isa<getElementPtrInst>(Val)) {
    getElementPtrInst* GEP = dyn_cast<getElementPtrInst>(Val);
    getElementPtrInst::op_iterator I = GEP->op_begin();

    for (++I; I != GEP->op_end(); ++I) {
      if (!isa<Constant>(*I)) {
        return true;
      }
    }
  }

  for (Value::use_iterator I = Val->use_begin(); i != Val->use_end(); ++I) {
    Value* V2 = dyn_cast<Value>(*I);

    if (V2) {
      if (IsIndirect(V2, Visited)) {
        return true;
      }
    }
  }

  return false;
#endif
}

void R600KernelParameters::AddParam(Argument *Arg) {
  Param P;

  P.Val = dyn_cast<Value>(Arg);
  P.OffsetInDW = getListSize();
  P.SizeInDW = CalculateArgumentSize(Arg);

  if (isa<PointerType>(Arg->getType()) and Arg->hasByValAttr()) {
    std::set<Value*> Visited;
    P.IsIndirect = IsIndirect(P.Val, Visited);
  }

  Params.push_back(P);
}

int R600KernelParameters::CalculateArgumentSize(Argument *Arg) {
  Type* T = Arg->getType();

  if (Arg->hasByValAttr() and dyn_cast<PointerType>(T)) {
    T = dyn_cast<PointerType>(T)->getElementType();
  }

  int StoreSizeInDW = (TD->getTypeStoreSize(T) + 3)/4;

  assert(StoreSizeInDW);

  return StoreSizeInDW;
}

void R600KernelParameters::RunAna(Function* Fun) {
  assert(IsOpenCLKernel(Fun));

  for (Function::arg_iterator I = Fun->arg_begin(); I != Fun->arg_end(); ++I) {
    AddParam(I);
  }

}

void R600KernelParameters::Replace(Function* Fun) {
  for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
    Value *NewVal;

    if (IsSpecialType(I->Val->getType())) {
      NewVal = handleSpecial(Fun, *I);
    } else {
      NewVal = ConstantRead(Fun, *I);
    }
    if (NewVal) {
      I->Val->replaceAllUsesWith(NewVal);
    }
  }
}

void R600KernelParameters::Propagate(Function* Fun) {
  for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
    if (I->PtrVal) {
      Propagate(I->PtrVal, I->Val->getName(), I->IsIndirect);
    }
  }
}

void R600KernelParameters::Propagate(Value* V, const Twine& Name, bool IsIndirect) {
  LoadInst* Load = dyn_cast<LoadInst>(V);
  GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V);

  unsigned Addrspace;

  if (IsIndirect) {
    Addrspace = AMDILAS::PARAM_I_ADDRESS;
  }  else {
    Addrspace = AMDILAS::PARAM_D_ADDRESS;
  }

  if (GEP and GEP->getType()->getAddressSpace() != Addrspace) {
    Value *Op = GEP->getPointerOperand();

    if (dyn_cast<PointerType>(Op->getType())->getAddressSpace() != Addrspace) {
      Op = new BitCastInst(Op, PointerType::get(dyn_cast<PointerType>(
                           Op->getType())->getElementType(), Addrspace),
                           Name, dyn_cast<Instruction>(V));
    }

    std::vector<Value*> Params(GEP->idx_begin(), GEP->idx_end());

    GetElementPtrInst* GEP2 = GetElementPtrInst::Create(Op, Params, Name,
                                                      dyn_cast<Instruction>(V));
    GEP2->setIsInBounds(GEP->isInBounds());
    V = dyn_cast<Value>(GEP2);
    GEP->replaceAllUsesWith(GEP2);
    GEP->eraseFromParent();
    Load = NULL;
  }

  if (Load) {
    ///normally at this point we have the right address space
    if (Load->getPointerAddressSpace() != Addrspace) {
      Value *OrigPtr = Load->getPointerOperand();
      PointerType *OrigPtrType = dyn_cast<PointerType>(OrigPtr->getType());

      Type* NewPtrType = PointerType::get(OrigPtrType->getElementType(),
                                            Addrspace);

      Value* NewPtr = OrigPtr;

      if (OrigPtr->getType() != NewPtrType) {
        NewPtr = new BitCastInst(OrigPtr, NewPtrType, "prop_cast", Load);
      }

      Value* new_Load = new LoadInst(NewPtr, Name, Load);
      Load->replaceAllUsesWith(new_Load);
      Load->eraseFromParent();
    }

    return;
  }

  std::vector<User*> Users(V->use_begin(), V->use_end());

  for (int i = 0; i < int(Users.size()); i++) {
    Value* V2 = dyn_cast<Value>(Users[i]);

    if (V2) {
      Propagate(V2, Name, IsIndirect);
    }
  }
}

Value* R600KernelParameters::ConstantRead(Function *Fun, Param &P) {
  assert(Fun->front().begin() != Fun->front().end());

  Instruction *FirstInst = Fun->front().begin();
  IRBuilder <> Builder (FirstInst);
/* First 3 dwords are reserved for the dimmension info */

  if (!P.Val->hasNUsesOrMore(1)) {
    return NULL;
  }
  unsigned Addrspace;

  if (P.IsIndirect) {
    Addrspace = AMDILAS::PARAM_I_ADDRESS;
  } else {
    Addrspace = AMDILAS::PARAM_D_ADDRESS;
  }

  Argument *Arg = dyn_cast<Argument>(P.Val);
  Type * ArgType = P.Val->getType();
  PointerType * ArgPtrType = dyn_cast<PointerType>(P.Val->getType());

  if (ArgPtrType and Arg->hasByValAttr()) {
    Value* ParamAddrSpacePtr = ConstantPointerNull::get(
                                    PointerType::get(Type::getInt32Ty(*Context),
                                    Addrspace));
    Value* ParamPtr = GetElementPtrInst::Create(ParamAddrSpacePtr,
                                    ConstantInt::get(Type::getInt32Ty(*Context),
                                    P.getRatOffset()), Arg->getName(),
                                    FirstInst);
    ParamPtr = new BitCastInst(ParamPtr,
                                PointerType::get(ArgPtrType->getElementType(),
                                                 Addrspace),
                                Arg->getName(), FirstInst);
    P.PtrVal = ParamPtr;
    return ParamPtr;
  } else {
    Value *ParamAddrSpacePtr = ConstantPointerNull::get(PointerType::get(
                                                        ArgType, Addrspace));

    Value *ParamPtr = Builder.CreateGEP(ParamAddrSpacePtr,
             ConstantInt::get(Type::getInt32Ty(*Context), P.getRatOffset()),
                              Arg->getName());

    Value *Param_Value = Builder.CreateLoad(ParamPtr, Arg->getName());

    return Param_Value;
  }
}

Value* R600KernelParameters::handleSpecial(Function* Fun, Param& P) {
  std::string Name = getSpecialTypeName(P.Val->getType());
  int ID;

  assert(!Name.empty());

  if (Name == "image2d_t" or Name == "image3d_t") {
    int LastID = std::max(getLastSpecialID("image2d_t"),
                     getLastSpecialID("image3d_t"));

    if (LastID == -1) {
      ID = 2; ///ID0 and ID1 are used internally by the driver
    } else {
      ID = LastID + 1;
    }
  } else if (Name == "sampler_t") {
    int LastID = getLastSpecialID("sampler_t");

    if (LastID == -1) {
      ID = 0;
    } else {
      ID = LastID + 1;
    }
  } else {
    ///TODO: give some error message
    return NULL;
  }

  P.SpecialType = Name;
  P.SpecialID = ID;

  Instruction *FirstInst = Fun->front().begin();

  return new IntToPtrInst(ConstantInt::get(Type::getInt32Ty(*Context),
                                           P.SpecialID), P.Val->getType(),
                                           "resourceID", FirstInst);
}

bool R600KernelParameters::IsSpecialType(Type* T) {
  return !getSpecialTypeName(T).empty();
}

std::string R600KernelParameters::getSpecialTypeName(Type* T) {
  PointerType *PT = dyn_cast<PointerType>(T);
  StructType *ST = NULL;

  if (PT) {
    ST = dyn_cast<StructType>(PT->getElementType());
  }

  if (ST) {
    std::string Prefix = "struct.opencl_builtin_type_";

    std::string Name = ST->getName().str();

    if (Name.substr(0, Prefix.length()) == Prefix) {
      return Name.substr(Prefix.length(), Name.length());
    }
  }

  return "";
}

bool R600KernelParameters::runOnFunction (Function &F) {
  if (!IsOpenCLKernel(&F)) {
    return false;
  }

  RunAna(&F);
  Replace(&F);
  Propagate(&F);

  return false;
}

void R600KernelParameters::getAnalysisUsage(AnalysisUsage &AU) const {
  FunctionPass::getAnalysisUsage(AU);
  AU.setPreservesAll();
}

const char *R600KernelParameters::getPassName() const {
  return "OpenCL Kernel parameter conversion to memory";
}

bool R600KernelParameters::doInitialization(Module &M) {
  Context = &M.getContext();
  Mod = &M;

  return false;
}

bool R600KernelParameters::doFinalization(Module &M) {
  return false;
}

} // End anonymous namespace

FunctionPass* llvm::createR600KernelParametersPass(const TargetData* TD) {
  return new R600KernelParameters(TD);
}
<|endoftext|>


<commit_before>//===- DeadTypeElimination.cpp - Eliminate unused types for symbol table --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is used to cleanup the output of GCC.  It eliminate names for types
// that are unused in the entire translation unit, using the FindUsedTypes pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Analysis/FindUsedTypes.h"
#include "llvm/Module.h"
#include "llvm/SymbolTable.h"
#include "llvm/DerivedTypes.h"
#include "Support/Statistic.h"

namespace {
  struct DTE : public Pass {
    // doPassInitialization - For this pass, it removes global symbol table
    // entries for primitive types.  These are never used for linking in GCC and
    // they make the output uglier to look at, so we nuke them.
    //
    // Also, initialize instance variables.
    //
    bool run(Module &M);

    // getAnalysisUsage - This function needs FindUsedTypes to do its job...
    //
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<FindUsedTypes>();
    }
  };
  RegisterOpt<DTE> X("deadtypeelim", "Dead Type Elimination");
  Statistic<>
  NumKilled("deadtypeelim", "Number of unused typenames removed from symtab");
}

Pass *createDeadTypeEliminationPass() {
  return new DTE();
}

// ShouldNukSymtabEntry - Return true if this module level symbol table entry
// should be eliminated.
//
static inline bool ShouldNukeSymtabEntry(const std::pair<std::string,Value*>&E){
  // Nuke all names for primitive types!
  if (cast<Type>(E.second)->isPrimitiveType()) return true;

  // Nuke all pointers to primitive types as well...
  if (const PointerType *PT = dyn_cast<PointerType>(E.second))
    if (PT->getElementType()->isPrimitiveType()) return true;

  return false;
}

// run - For this pass, it removes global symbol table entries for primitive
// types.  These are never used for linking in GCC and they make the output
// uglier to look at, so we nuke them.  Also eliminate types that are never used
// in the entire program as indicated by FindUsedTypes.
//
bool DTE::run(Module &M) {
  bool Changed = false;

  SymbolTable &ST = M.getSymbolTable();
  const std::set<const Type *> &UsedTypes =
    getAnalysis<FindUsedTypes>().getTypes();

  // Check the symbol table for superfluous type entries...
  //
  // Grab the 'type' plane of the module symbol...
  SymbolTable::iterator STI = ST.find(Type::TypeTy);
  if (STI != ST.end()) {
    // Loop over all entries in the type plane...
    SymbolTable::VarMap &Plane = STI->second;
    for (SymbolTable::VarMap::iterator PI = Plane.begin(); PI != Plane.end();)
      // If this entry should be unconditionally removed, or if we detect that
      // the type is not used, remove it.
      if (ShouldNukeSymtabEntry(*PI) ||
          !UsedTypes.count(cast<Type>(PI->second))) {
        SymbolTable::VarMap::iterator PJ = PI++;
        Plane.erase(PJ);
        ++NumKilled;
        Changed = true;
      } else {
        ++PI;
      }
  }

  return Changed;
}
<commit_msg>Untypo<commit_after>//===- DeadTypeElimination.cpp - Eliminate unused types for symbol table --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is used to cleanup the output of GCC.  It eliminate names for types
// that are unused in the entire translation unit, using the FindUsedTypes pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Analysis/FindUsedTypes.h"
#include "llvm/Module.h"
#include "llvm/SymbolTable.h"
#include "llvm/DerivedTypes.h"
#include "Support/Statistic.h"

namespace {
  struct DTE : public Pass {
    // doPassInitialization - For this pass, it removes global symbol table
    // entries for primitive types.  These are never used for linking in GCC and
    // they make the output uglier to look at, so we nuke them.
    //
    // Also, initialize instance variables.
    //
    bool run(Module &M);

    // getAnalysisUsage - This function needs FindUsedTypes to do its job...
    //
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<FindUsedTypes>();
    }
  };
  RegisterOpt<DTE> X("deadtypeelim", "Dead Type Elimination");
  Statistic<>
  NumKilled("deadtypeelim", "Number of unused typenames removed from symtab");
}

Pass *createDeadTypeEliminationPass() {
  return new DTE();
}

// ShouldNukeSymtabEntry - Return true if this module level symbol table entry
// should be eliminated.
//
static inline bool ShouldNukeSymtabEntry(const std::pair<std::string,Value*>&E){
  // Nuke all names for primitive types!
  if (cast<Type>(E.second)->isPrimitiveType()) return true;

  // Nuke all pointers to primitive types as well...
  if (const PointerType *PT = dyn_cast<PointerType>(E.second))
    if (PT->getElementType()->isPrimitiveType()) return true;

  return false;
}

// run - For this pass, it removes global symbol table entries for primitive
// types.  These are never used for linking in GCC and they make the output
// uglier to look at, so we nuke them.  Also eliminate types that are never used
// in the entire program as indicated by FindUsedTypes.
//
bool DTE::run(Module &M) {
  bool Changed = false;

  SymbolTable &ST = M.getSymbolTable();
  const std::set<const Type *> &UsedTypes =
    getAnalysis<FindUsedTypes>().getTypes();

  // Check the symbol table for superfluous type entries...
  //
  // Grab the 'type' plane of the module symbol...
  SymbolTable::iterator STI = ST.find(Type::TypeTy);
  if (STI != ST.end()) {
    // Loop over all entries in the type plane...
    SymbolTable::VarMap &Plane = STI->second;
    for (SymbolTable::VarMap::iterator PI = Plane.begin(); PI != Plane.end();)
      // If this entry should be unconditionally removed, or if we detect that
      // the type is not used, remove it.
      if (ShouldNukeSymtabEntry(*PI) ||
          !UsedTypes.count(cast<Type>(PI->second))) {
        SymbolTable::VarMap::iterator PJ = PI++;
        Plane.erase(PJ);
        ++NumKilled;
        Changed = true;
      } else {
        ++PI;
      }
  }

  return Changed;
}
<|endoftext|>


<commit_before>/*
 *  VHDL code generation for statements.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "vhdl_target.h"

#include <iostream>
#include <cstring>
#include <cassert>
#include <sstream>

/*
 * Generate VHDL for the $display system task.
 * This is implemented using the functions in std.textio. Each
 * parameter is written to a line variable in the process and
 * then the line is written to the special variable `Output'
 * (which represents the console). Subsequent $displays will
 * use the same line variable.
 *
 * It's possible, although quite unlikely, that there will be
 * name collision with an existing variable called
 * `Verilog_Display_Line' -- do something about this?
 */
static int draw_stask_display(vhdl_process *proc, stmt_container *container,
                              ivl_statement_t stmt)
{
   // Add the package requirement to the containing entity
   proc->get_parent()->get_parent()->requires_package("std.textio");

   const char *display_line = "Verilog_Display_Line";

   if (!proc->have_declared_var(display_line)) {
      vhdl_var_decl *line_var =
         new vhdl_var_decl(display_line, vhdl_type::line());
      line_var->set_comment("For generating $display output");
      proc->add_decl(line_var);
   }

   // Write the data into the line
   int count = ivl_stmt_parm_count(stmt);
   for (int i = 0; i < count; i++) {
      // $display may have an empty parameter, in which case
      // the expression will be null
      // The behaviour here seems to be to output a space
      ivl_expr_t net = ivl_stmt_parm(stmt, i);
      vhdl_expr *e = NULL;
      if (net) {
         vhdl_expr *base = translate_expr(net);
         if (NULL == base)
            return 1;

         // Need to add a call to Type'Image for types not
         // supported by std.textio
         if (base->get_type()->get_name() != VHDL_TYPE_STRING) {
            std::string name(base->get_type()->get_string());
            name += "'Image";

            vhdl_fcall *cast
               = new vhdl_fcall(name.c_str(), vhdl_type::string());
            cast->add_expr(base);
            e = cast;
         }
         else
            e = base;
      }
      else
         e = new vhdl_const_string(" ");

      vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write");
      vhdl_var_ref *ref =
         new vhdl_var_ref(display_line, vhdl_type::line());
      write->add_expr(ref);
      write->add_expr(e);

      container->add_stmt(write);
   }

   // WriteLine(Output, Verilog_Display_Line)
   vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine");
   vhdl_var_ref *output_ref =
      new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE));
   write_line->add_expr(output_ref);
   vhdl_var_ref *ref =
      new vhdl_var_ref(display_line, vhdl_type::line());
   write_line->add_expr(ref);
   container->add_stmt(write_line);

   return 0;
}

/*
 * VHDL has no real equivalent of Verilog's $finish task. The
 * current solution is to use `assert false ...' to terminate
 * the simulator. This isn't great, as the simulator will
 * return a failure exit code when in fact it completed
 * successfully.
 */
static int draw_stask_finish(vhdl_process *proc, stmt_container *container,
                             ivl_statement_t stmt)
{
   container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED"));
   return 0;
}

/*
 * Generate VHDL for system tasks (like $display). Not all of
 * these are supported.
 */
static int draw_stask(vhdl_process *proc, stmt_container *container,
                      ivl_statement_t stmt)
{
   const char *name = ivl_stmt_name(stmt);

   if (strcmp(name, "$display") == 0)
      return draw_stask_display(proc, container, stmt);
   else if (strcmp(name, "$finish") == 0)
      return draw_stask_finish(proc, container, stmt);
   else {
      error("No VHDL translation for system task %s", name);
      return 0;
   }
}

/*
 * Generate VHDL for a block of Verilog statements. This doesn't
 * actually do anything, other than recursively translate the
 * block's statements and add them to the process. This is OK as
 * the stmt_container class behaves like a Verilog block.
 */
static int draw_block(vhdl_process *proc, stmt_container *container,
                      ivl_statement_t stmt)
{
   int count = ivl_stmt_block_count(stmt);
   for (int i = 0; i < count; i++) {
      if (draw_stmt(proc, container, ivl_stmt_block_stmt(stmt, i)) != 0)
         return 1;
   }
   return 0;
}

/*
 * A no-op statement. This corresponds to a `null' statement in
 * VHDL.
 */
static int draw_noop(vhdl_process *proc, stmt_container *container,
                     ivl_statement_t stmt)
{
   container->add_stmt(new vhdl_null_stmt());
   return 0;
}

/*
 * A non-blocking assignment inside a process. The semantics for
 * this are essentially the same as VHDL's non-blocking signal
 * assignment.
 */
static int draw_nbassign(vhdl_process *proc, stmt_container *container,
                         ivl_statement_t stmt, vhdl_expr *after = NULL)
{
   int nlvals = ivl_stmt_lvals(stmt);
   if (nlvals != 1) {
      error("Can only have 1 lval at the moment (found %d)", nlvals);
      return 1;
   }

   ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
   ivl_signal_t sig;
   if ((sig = ivl_lval_sig(lval))) {
      const char *signame = get_renamed_signal(sig).c_str();

      vhdl_decl *decl = proc->get_parent()->get_decl(signame);
      assert(decl);

      vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt));
      if (NULL == rhs_raw)
         return 1;
      vhdl_expr *rhs = rhs_raw->cast(decl->get_type());

      // The type here can be null as it is never actually needed
      vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL);

      vhdl_nbassign_stmt *nbassign = new vhdl_nbassign_stmt(lval_ref, rhs);
      if (after != NULL)
         nbassign->set_after(after);
      container->add_stmt(nbassign);
   }
   else {
      error("Only signals as lvals supported at the moment");
      return 1;
   }

   return 0;
}

/*
 * Delay statements are equivalent to the `wait for' form of the
 * VHDL wait statement.
 */
static int draw_delay(vhdl_process *proc, stmt_container *container,
                      ivl_statement_t stmt)
{
   uint64_t value = ivl_stmt_delay_val(stmt);

   // This currently ignores the time units and precision
   // of the enclosing scope
   // A neat way to do this would be to make these values
   // constants in the scope (type is Time), and have the
   // VHDL wait statement compute the value from that.
   // The other solution is to add them as parameters to
   // the vhdl_process class
   vhdl_expr *time = new vhdl_const_int(value);

   // If the sub-statement is an assignment then VHDL lets
   // us put the delay after it, which is more compact and
   // idiomatic
   ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);
   ivl_statement_type_t type = ivl_statement_type(sub_stmt);
   if (type == IVL_ST_ASSIGN_NB) {
      draw_nbassign(proc, container, sub_stmt, time);
   }
   else {
      vhdl_wait_stmt *wait =
         new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, time);
      container->add_stmt(wait);

      // Expand the sub-statement as well
      // Often this would result in a useless `null' statement which
      // is caught here instead
      if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP)
         draw_stmt(proc, container, sub_stmt);

   }

   return 0;
}

/*
 * A wait statement waits for a level change on a @(..) list of
 * signals.
 */
static int draw_wait(vhdl_process *proc, stmt_container *container,
                     ivl_statement_t stmt)
{
   ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);

   int nevents = ivl_stmt_nevent(stmt);
   for (int i = 0; i < nevents; i++) {
      ivl_event_t event = ivl_stmt_events(stmt, i);

      // A list of the non-edge triggered signals to they can
      // be added to the edge-detecting `if' statement later
      string_list_t non_edges;

      int nany = ivl_event_nany(event);
      for (int i = 0; i < nany; i++) {
         ivl_nexus_t nexus = ivl_event_any(event, i);

         int nptrs = ivl_nexus_ptrs(nexus);
         for (int j = 0; j < nptrs; j++) {
            ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, j);

            ivl_signal_t sig;
            if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
               const char *signame = ivl_signal_basename(sig);

               // Only add this signal to the sensitivity if it's part
               // of the containing architecture (i.e. it has already
               // been declared)
               if (proc->get_parent()->have_declared(signame)) {
                  proc->add_sensitivity(signame);
                  non_edges.push_back(signame);
                  break;
               }
            }
            else {
               // Ignore all other types of nexus pointer
            }
         }
      }

      int nneg = ivl_event_nneg(event);
      int npos = ivl_event_npos(event);
      if (nneg + npos > 0) {
         vhdl_binop_expr *test =
            new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean());

         // Generate falling_edge(..) calls for each negedge event
         for (int i = 0; i < nneg; i++) {
            ivl_nexus_t nexus = ivl_event_neg(event, i);

            int nptrs = ivl_nexus_ptrs(nexus);
            for (int j = 0; j < nptrs; j++) {
               ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, j);

               ivl_signal_t sig;
               if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
                  vhdl_fcall *detect
                     = new vhdl_fcall("falling_edge", vhdl_type::boolean());
                  detect->add_expr
                     (new vhdl_var_ref(ivl_signal_basename(sig),
                                       vhdl_type::std_logic()));
                  test->add_expr(detect);
                  break;
               }
            }
         }

         // Generate rising_edge(..) calls for each posedge event
         for (int i = 0; i < npos; i++) {
            ivl_nexus_t nexus = ivl_event_pos(event, i);

            int nptrs = ivl_nexus_ptrs(nexus);
            for (int j = 0; j < nptrs; j++) {
               ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, j);

               ivl_signal_t sig;
               if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
                  vhdl_fcall *detect
                     = new vhdl_fcall("rising_edge", vhdl_type::boolean());
                  detect->add_expr
                     (new vhdl_var_ref(ivl_signal_basename(sig),
                                       vhdl_type::std_logic()));
                  test->add_expr(detect);
                  break;
               }
            }
         }

         // Add Name'Event terms for each non-edge-triggered signal
         string_list_t::iterator it;
         for (it = non_edges.begin(); it != non_edges.end(); ++it) {
            test->add_expr
               (new vhdl_var_ref((*it + "'Event").c_str(),
                                 vhdl_type::boolean()));
         }

         vhdl_if_stmt *edge_det = new vhdl_if_stmt(test);
         container->add_stmt(edge_det);

         draw_stmt(proc, edge_det->get_then_container(), sub_stmt);
      }
      else {
         // Don't bother generating an edge detector if there
         // are no edge-triggered events
         draw_stmt(proc, container, sub_stmt);
      }
   }

   return 0;
}

static int draw_if(vhdl_process *proc, stmt_container *container,
                   ivl_statement_t stmt)
{
   vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
   if (NULL == test)
      return 1;

   vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);

   draw_stmt(proc, vhdif->get_then_container(),
             ivl_stmt_cond_true(stmt));
   draw_stmt(proc, vhdif->get_else_container(),
             ivl_stmt_cond_false(stmt));

   container->add_stmt(vhdif);

   return 0;
}

/*
 * Generate VHDL statements for the given Verilog statement and
 * add them to the given VHDL process. The container is the
 * location to add statements: e.g. the process body, a branch
 * of an if statement, etc.
 */
int draw_stmt(vhdl_process *proc, stmt_container *container,
              ivl_statement_t stmt)
{
   switch (ivl_statement_type(stmt)) {
   case IVL_ST_STASK:
      return draw_stask(proc, container, stmt);
   case IVL_ST_BLOCK:
      return draw_block(proc, container, stmt);
   case IVL_ST_NOOP:
      return draw_noop(proc, container, stmt);
   case IVL_ST_ASSIGN_NB:
      return draw_nbassign(proc, container, stmt);
   case IVL_ST_DELAY:
      return draw_delay(proc, container, stmt);
   case IVL_ST_WAIT:
      return draw_wait(proc, container, stmt);
   case IVL_ST_CONDIT:
      return draw_if(proc, container, stmt);
   default:
      error("No VHDL translation for statement at %s:%d (type = %d)",
            ivl_stmt_file(stmt), ivl_stmt_lineno(stmt),
            ivl_statement_type(stmt));
      return 1;
   }
}
<commit_msg>Clean up the edge detector code a bit<commit_after>/*
 *  VHDL code generation for statements.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "vhdl_target.h"

#include <iostream>
#include <cstring>
#include <cassert>
#include <sstream>

/*
 * Generate VHDL for the $display system task.
 * This is implemented using the functions in std.textio. Each
 * parameter is written to a line variable in the process and
 * then the line is written to the special variable `Output'
 * (which represents the console). Subsequent $displays will
 * use the same line variable.
 *
 * It's possible, although quite unlikely, that there will be
 * name collision with an existing variable called
 * `Verilog_Display_Line' -- do something about this?
 */
static int draw_stask_display(vhdl_process *proc, stmt_container *container,
                              ivl_statement_t stmt)
{
   // Add the package requirement to the containing entity
   proc->get_parent()->get_parent()->requires_package("std.textio");

   const char *display_line = "Verilog_Display_Line";

   if (!proc->have_declared_var(display_line)) {
      vhdl_var_decl *line_var =
         new vhdl_var_decl(display_line, vhdl_type::line());
      line_var->set_comment("For generating $display output");
      proc->add_decl(line_var);
   }

   // Write the data into the line
   int count = ivl_stmt_parm_count(stmt);
   for (int i = 0; i < count; i++) {
      // $display may have an empty parameter, in which case
      // the expression will be null
      // The behaviour here seems to be to output a space
      ivl_expr_t net = ivl_stmt_parm(stmt, i);
      vhdl_expr *e = NULL;
      if (net) {
         vhdl_expr *base = translate_expr(net);
         if (NULL == base)
            return 1;

         // Need to add a call to Type'Image for types not
         // supported by std.textio
         if (base->get_type()->get_name() != VHDL_TYPE_STRING) {
            std::string name(base->get_type()->get_string());
            name += "'Image";

            vhdl_fcall *cast
               = new vhdl_fcall(name.c_str(), vhdl_type::string());
            cast->add_expr(base);
            e = cast;
         }
         else
            e = base;
      }
      else
         e = new vhdl_const_string(" ");

      vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write");
      vhdl_var_ref *ref =
         new vhdl_var_ref(display_line, vhdl_type::line());
      write->add_expr(ref);
      write->add_expr(e);

      container->add_stmt(write);
   }

   // WriteLine(Output, Verilog_Display_Line)
   vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine");
   vhdl_var_ref *output_ref =
      new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE));
   write_line->add_expr(output_ref);
   vhdl_var_ref *ref =
      new vhdl_var_ref(display_line, vhdl_type::line());
   write_line->add_expr(ref);
   container->add_stmt(write_line);

   return 0;
}

/*
 * VHDL has no real equivalent of Verilog's $finish task. The
 * current solution is to use `assert false ...' to terminate
 * the simulator. This isn't great, as the simulator will
 * return a failure exit code when in fact it completed
 * successfully.
 */
static int draw_stask_finish(vhdl_process *proc, stmt_container *container,
                             ivl_statement_t stmt)
{
   container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED"));
   return 0;
}

/*
 * Generate VHDL for system tasks (like $display). Not all of
 * these are supported.
 */
static int draw_stask(vhdl_process *proc, stmt_container *container,
                      ivl_statement_t stmt)
{
   const char *name = ivl_stmt_name(stmt);

   if (strcmp(name, "$display") == 0)
      return draw_stask_display(proc, container, stmt);
   else if (strcmp(name, "$finish") == 0)
      return draw_stask_finish(proc, container, stmt);
   else {
      error("No VHDL translation for system task %s", name);
      return 0;
   }
}

/*
 * Generate VHDL for a block of Verilog statements. This doesn't
 * actually do anything, other than recursively translate the
 * block's statements and add them to the process. This is OK as
 * the stmt_container class behaves like a Verilog block.
 */
static int draw_block(vhdl_process *proc, stmt_container *container,
                      ivl_statement_t stmt)
{
   int count = ivl_stmt_block_count(stmt);
   for (int i = 0; i < count; i++) {
      if (draw_stmt(proc, container, ivl_stmt_block_stmt(stmt, i)) != 0)
         return 1;
   }
   return 0;
}

/*
 * A no-op statement. This corresponds to a `null' statement in
 * VHDL.
 */
static int draw_noop(vhdl_process *proc, stmt_container *container,
                     ivl_statement_t stmt)
{
   container->add_stmt(new vhdl_null_stmt());
   return 0;
}

/*
 * A non-blocking assignment inside a process. The semantics for
 * this are essentially the same as VHDL's non-blocking signal
 * assignment.
 */
static int draw_nbassign(vhdl_process *proc, stmt_container *container,
                         ivl_statement_t stmt, vhdl_expr *after = NULL)
{
   int nlvals = ivl_stmt_lvals(stmt);
   if (nlvals != 1) {
      error("Can only have 1 lval at the moment (found %d)", nlvals);
      return 1;
   }

   ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
   ivl_signal_t sig;
   if ((sig = ivl_lval_sig(lval))) {
      const char *signame = get_renamed_signal(sig).c_str();

      vhdl_decl *decl = proc->get_parent()->get_decl(signame);
      assert(decl);

      vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt));
      if (NULL == rhs_raw)
         return 1;
      vhdl_expr *rhs = rhs_raw->cast(decl->get_type());

      // The type here can be null as it is never actually needed
      vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL);

      vhdl_nbassign_stmt *nbassign = new vhdl_nbassign_stmt(lval_ref, rhs);
      if (after != NULL)
         nbassign->set_after(after);
      container->add_stmt(nbassign);
   }
   else {
      error("Only signals as lvals supported at the moment");
      return 1;
   }

   return 0;
}

/*
 * Delay statements are equivalent to the `wait for' form of the
 * VHDL wait statement.
 */
static int draw_delay(vhdl_process *proc, stmt_container *container,
                      ivl_statement_t stmt)
{
   uint64_t value = ivl_stmt_delay_val(stmt);

   // This currently ignores the time units and precision
   // of the enclosing scope
   // A neat way to do this would be to make these values
   // constants in the scope (type is Time), and have the
   // VHDL wait statement compute the value from that.
   // The other solution is to add them as parameters to
   // the vhdl_process class
   vhdl_expr *time = new vhdl_const_int(value);

   // If the sub-statement is an assignment then VHDL lets
   // us put the delay after it, which is more compact and
   // idiomatic
   ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);
   ivl_statement_type_t type = ivl_statement_type(sub_stmt);
   if (type == IVL_ST_ASSIGN_NB) {
      draw_nbassign(proc, container, sub_stmt, time);
   }
   else {
      vhdl_wait_stmt *wait =
         new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, time);
      container->add_stmt(wait);

      // Expand the sub-statement as well
      // Often this would result in a useless `null' statement which
      // is caught here instead
      if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP)
         draw_stmt(proc, container, sub_stmt);

   }

   return 0;
}

/*
 * Make edge detectors from the signals in `nexus' and add them
 * to the expression `test'. Also adds the signals to the process
 * sensitivity list. Type should be one of `rising_edge' or
 * `falling_edge'.
 */
static void edge_detector(ivl_nexus_t nexus, vhdl_process *proc,
                          vhdl_binop_expr *test, const char *type)
{
   int nptrs = ivl_nexus_ptrs(nexus);
   for (int j = 0; j < nptrs; j++) {
      ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, j);

      ivl_signal_t sig;
      if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
         const char *signame = get_renamed_signal(sig).c_str();

         vhdl_fcall *detect
            = new vhdl_fcall(type, vhdl_type::boolean());
         detect->add_expr
            (new vhdl_var_ref(signame, vhdl_type::std_logic()));
         test->add_expr(detect);
         proc->add_sensitivity(signame);
         break;
      }
   }
}

/*
 * A wait statement waits for a level change on a @(..) list of
 * signals.
 */
static int draw_wait(vhdl_process *proc, stmt_container *container,
                     ivl_statement_t stmt)
{
   ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);

   int nevents = ivl_stmt_nevent(stmt);
   for (int i = 0; i < nevents; i++) {
      ivl_event_t event = ivl_stmt_events(stmt, i);

      // A list of the non-edge triggered signals to they can
      // be added to the edge-detecting `if' statement later
      string_list_t non_edges;

      int nany = ivl_event_nany(event);
      for (int i = 0; i < nany; i++) {
         ivl_nexus_t nexus = ivl_event_any(event, i);

         int nptrs = ivl_nexus_ptrs(nexus);
         for (int j = 0; j < nptrs; j++) {
            ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, j);

            ivl_signal_t sig;
            if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
               const char *signame = ivl_signal_basename(sig);

               // Only add this signal to the sensitivity if it's part
               // of the containing architecture (i.e. it has already
               // been declared)
               if (proc->get_parent()->have_declared(signame)) {
                  proc->add_sensitivity(signame);
                  non_edges.push_back(signame);
                  break;
               }
            }
            else {
               // Ignore all other types of nexus pointer
            }
         }
      }

      int nneg = ivl_event_nneg(event);
      int npos = ivl_event_npos(event);
      if (nneg + npos > 0) {
         vhdl_binop_expr *test =
            new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean());

         // Generate falling_edge(..) calls for each negedge event
         for (int i = 0; i < nneg; i++)
            edge_detector(ivl_event_neg(event, i), proc, test, "falling_edge");

         // Generate rising_edge(..) calls for each posedge event
         for (int i = 0; i < npos; i++)
            edge_detector(ivl_event_pos(event, i), proc, test, "rising_edge");

         // Add Name'Event terms for each non-edge-triggered signal
         string_list_t::iterator it;
         for (it = non_edges.begin(); it != non_edges.end(); ++it) {
            test->add_expr
               (new vhdl_var_ref((*it + "'Event").c_str(),
                                 vhdl_type::boolean()));
         }

         vhdl_if_stmt *edge_det = new vhdl_if_stmt(test);
         container->add_stmt(edge_det);

         draw_stmt(proc, edge_det->get_then_container(), sub_stmt);
      }
      else {
         // Don't bother generating an edge detector if there
         // are no edge-triggered events
         draw_stmt(proc, container, sub_stmt);
      }
   }

   return 0;
}

static int draw_if(vhdl_process *proc, stmt_container *container,
                   ivl_statement_t stmt)
{
   vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
   if (NULL == test)
      return 1;

   vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);

   draw_stmt(proc, vhdif->get_then_container(),
             ivl_stmt_cond_true(stmt));
   draw_stmt(proc, vhdif->get_else_container(),
             ivl_stmt_cond_false(stmt));

   container->add_stmt(vhdif);

   return 0;
}

/*
 * Generate VHDL statements for the given Verilog statement and
 * add them to the given VHDL process. The container is the
 * location to add statements: e.g. the process body, a branch
 * of an if statement, etc.
 */
int draw_stmt(vhdl_process *proc, stmt_container *container,
              ivl_statement_t stmt)
{
   switch (ivl_statement_type(stmt)) {
   case IVL_ST_STASK:
      return draw_stask(proc, container, stmt);
   case IVL_ST_BLOCK:
      return draw_block(proc, container, stmt);
   case IVL_ST_NOOP:
      return draw_noop(proc, container, stmt);
   case IVL_ST_ASSIGN_NB:
      return draw_nbassign(proc, container, stmt);
   case IVL_ST_DELAY:
      return draw_delay(proc, container, stmt);
   case IVL_ST_WAIT:
      return draw_wait(proc, container, stmt);
   case IVL_ST_CONDIT:
      return draw_if(proc, container, stmt);
   default:
      error("No VHDL translation for statement at %s:%d (type = %d)",
            ivl_stmt_file(stmt), ivl_stmt_lineno(stmt),
            ivl_statement_type(stmt));
      return 1;
   }
}
<|endoftext|>