<commit_before>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA  02110-1301 USA
// ===========================================================================
//
// Author: Jan Kotanski <jan.kotanski@desy.de>
// Created on: Nov 12, 2018
//

#include <gtest/gtest.h>
#include <h5cpp/file/functions.hpp>
#include <h5cpp/node/group.hpp>
#include <h5cpp/dataspace/hyperslab.hpp>
#include <boost/filesystem.hpp>
#ifndef _MSC_VER
#include <sys/time.h>
#endif

using namespace hdf5;
namespace fs = boost::filesystem;

struct DatasetWriteSpeedTest : public testing::Test
{
  long long unsigned int xdim = 867;
  long long unsigned int ydim = 700;
  long long unsigned int nframe = 33;
  hdf5::file::File f;
  hdf5::node::Group root;
  hdf5::dataspace::Simple space;
  hdf5::dataspace::Simple fullspace;
  hdf5::dataspace::Simple memspace;
  property::DatasetCreationList dcpl;
  property::LinkCreationList lcpl;
  property::DatasetAccessList dapl;
  std::vector<unsigned short int> frame;
  std::vector<unsigned short int> allframes;

  dataspace::Hyperslab framespace;
  property::DatasetTransferList dtpl;

  DatasetWriteSpeedTest()
  {
#if H5_VERSION_GE(1, 10, 0)
    property::FileCreationList fcpl;
    property::FileAccessList fapl;
    fapl.library_version_bounds(property::LibVersion::LATEST,
                                property::LibVersion::LATEST);
    f = file::create("dataset_write_speed.h5", file::AccessFlags::TRUNCATE, fcpl, fapl);
#else
    f = file::create("dataset_write_speed.h5", file::AccessFlags::TRUNCATE);
#endif
    root = f.root();
    space =  {{0, xdim, ydim}, {dataspace::Simple::UNLIMITED,
				dataspace::Simple::UNLIMITED,
				dataspace::Simple::UNLIMITED}};
    fullspace =  {{nframe, xdim, ydim}, {dataspace::Simple::UNLIMITED,
				dataspace::Simple::UNLIMITED,
				dataspace::Simple::UNLIMITED}};
    memspace = {{xdim, ydim}, {dataspace::Simple::UNLIMITED,
			       dataspace::Simple::UNLIMITED}};

    dcpl.layout(property::DatasetLayout::CHUNKED);
    dcpl.chunk({1, xdim, ydim});
    frame = std::vector<unsigned short int>(xdim * ydim);
    std::generate(frame.begin(), frame.end(), std::rand);
    framespace = dataspace::Hyperslab({{0, 0, 0}, {1, xdim, ydim}});

    allframes = std::vector<unsigned short int>(nframe * xdim * ydim);
    std::generate(allframes.begin(), allframes.end(), std::rand);
  }

protected:
  virtual void SetUp()
  {
    }

  virtual void TearDown() {
    fs::remove("dataset_write_speed.h5");
  }
};

#ifndef _MSC_VER
TEST_F(DatasetWriteSpeedTest, write_hyperslab)
{
  struct timeval stime1;
  struct timeval etime1;
  struct timeval stime0;
  struct timeval etime0;

  auto dtype = datatype::create<unsigned short int>();
  node::Dataset data0 = node::Dataset(root, "data0", dtype, space, lcpl, dcpl, dapl);
  gettimeofday(&stime0, NULL);
  for(long long unsigned int i = 0; i != nframe; i++){
    data0.extent(0, 1);
    framespace.offset({i, 0, 0});
    dataspace::Dataspace file_space = data0.dataspace();
    file_space.selection(dataspace::SelectionOperation::SET, framespace);
    data0.write(frame, dtype, memspace, file_space, dtpl);
  }
  gettimeofday(&etime0, NULL);

  node::Dataset data1 = node::Dataset(root,
				      "data1",
				      datatype::create<unsigned short int>(),
				      space,lcpl,dcpl,dapl);

  gettimeofday(&stime1, NULL);

  for(long long unsigned int i = 0; i != nframe; i++){
    data1.extent(0, 1);
    framespace.offset({i, 0, 0});

    data1.write(frame, framespace);
  }
  gettimeofday(&etime1, NULL);

  double time0 = (double)(etime0.tv_sec - stime0.tv_sec)
    + (double)(etime0.tv_usec - stime0.tv_usec)*0.000001;
  double time1 = (double)(etime1.tv_sec - stime1.tv_sec)
    + (double)(etime1.tv_usec - stime1.tv_usec)*0.000001;

  // std::cerr << time0 <<  std::endl;
  // std::cerr << time1 <<  std::endl;
  EXPECT_GT(14 * time1, time0);
  EXPECT_GT(14 * time0, time1);

  std::vector<unsigned short int> read_value(xdim * ydim);

  for(long long unsigned int i = 0; i != nframe; i++){
    data1.extent(0, 1);
    framespace.offset({i, 0, 0});
    data1.read(read_value, framespace);
    EXPECT_EQ(frame, read_value);
  }

}

TEST_F(DatasetWriteSpeedTest, write)
{
  struct timeval stime1;
  struct timeval etime1;
  struct timeval stime0;
  struct timeval etime0;

  auto dtype = datatype::create<unsigned short int>();
  node::Dataset data2 = node::Dataset(root, "data2", dtype, space, lcpl, dcpl, dapl);
  gettimeofday(&stime0, NULL);
  for(long long unsigned int i = 0; i != nframe; i++){
    data2.extent(0, 1);
    framespace.offset({i, 0, 0});
    dataspace::Dataspace file_space = data2.dataspace();
    file_space.selection(dataspace::SelectionOperation::SET, framespace);
    data2.write(frame, dtype, memspace, file_space, dtpl);
  }
  gettimeofday(&etime0, NULL);

  node::Dataset data3 = node::Dataset(root,
				      "data3",
				      datatype::create<unsigned short int>(),
				      fullspace, lcpl, dcpl, dapl);

  gettimeofday(&stime1, NULL);

  data3.write(allframes);
  gettimeofday(&etime1, NULL);

  double time0 = (double)(etime0.tv_sec - stime0.tv_sec)
    + (double)(etime0.tv_usec - stime0.tv_usec)*0.000001;
  double time1 = (double)(etime1.tv_sec - stime1.tv_sec)
    + (double)(etime1.tv_usec - stime1.tv_usec)*0.000001;

  // std::cerr << time0 <<  std::endl;
  // std::cerr << time1 <<  std::endl;
  EXPECT_GT(14 * time1, time0);
  EXPECT_GT(14 * time0, time1);

  std::vector<unsigned short int> read_value(xdim * ydim);

  for(long long unsigned int i = 0; i != nframe; i++){
    data3.extent(0, 1);
    framespace.offset({i, 0, 0});
    data3.read(read_value, framespace);
    auto first = allframes.begin() + i * xdim * ydim;
    auto last = allframes.begin() + (i + 1) * xdim * ydim;
    std::vector<unsigned short int> buffer(first, last);
    EXPECT_EQ(buffer, read_value);
  }

}

#endif
<commit_msg>remove a whitespace<commit_after>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA  02110-1301 USA
// ===========================================================================
//
// Author: Jan Kotanski <jan.kotanski@desy.de>
// Created on: Nov 12, 2018
//

#include <gtest/gtest.h>
#include <h5cpp/file/functions.hpp>
#include <h5cpp/node/group.hpp>
#include <h5cpp/dataspace/hyperslab.hpp>
#include <boost/filesystem.hpp>
#ifndef _MSC_VER
#include <sys/time.h>
#endif

using namespace hdf5;
namespace fs = boost::filesystem;

struct DatasetWriteSpeedTest : public testing::Test
{
  long long unsigned int xdim = 867;
  long long unsigned int ydim = 700;
  long long unsigned int nframe = 33;
  hdf5::file::File f;
  hdf5::node::Group root;
  hdf5::dataspace::Simple space;
  hdf5::dataspace::Simple fullspace;
  hdf5::dataspace::Simple memspace;
  property::DatasetCreationList dcpl;
  property::LinkCreationList lcpl;
  property::DatasetAccessList dapl;
  std::vector<unsigned short int> frame;
  std::vector<unsigned short int> allframes;

  dataspace::Hyperslab framespace;
  property::DatasetTransferList dtpl;

  DatasetWriteSpeedTest()
  {
#if H5_VERSION_GE(1, 10, 0)
    property::FileCreationList fcpl;
    property::FileAccessList fapl;
    fapl.library_version_bounds(property::LibVersion::LATEST,
                                property::LibVersion::LATEST);
    f = file::create("dataset_write_speed.h5", file::AccessFlags::TRUNCATE, fcpl, fapl);
#else
    f = file::create("dataset_write_speed.h5", file::AccessFlags::TRUNCATE);
#endif
    root = f.root();
    space =  {{0, xdim, ydim}, {dataspace::Simple::UNLIMITED,
				dataspace::Simple::UNLIMITED,
				dataspace::Simple::UNLIMITED}};
    fullspace =  {{nframe, xdim, ydim}, {dataspace::Simple::UNLIMITED,
				dataspace::Simple::UNLIMITED,
				dataspace::Simple::UNLIMITED}};
    memspace = {{xdim, ydim}, {dataspace::Simple::UNLIMITED,
			       dataspace::Simple::UNLIMITED}};

    dcpl.layout(property::DatasetLayout::CHUNKED);
    dcpl.chunk({1, xdim, ydim});
    frame = std::vector<unsigned short int>(xdim * ydim);
    std::generate(frame.begin(), frame.end(), std::rand);
    framespace = dataspace::Hyperslab({{0, 0, 0}, {1, xdim, ydim}});

    allframes = std::vector<unsigned short int>(nframe * xdim * ydim);
    std::generate(allframes.begin(), allframes.end(), std::rand);
  }

protected:
  virtual void SetUp()
  {
    }

  virtual void TearDown() {
    fs::remove("dataset_write_speed.h5");
  }
};

#ifndef _MSC_VER
TEST_F(DatasetWriteSpeedTest, write_hyperslab)
{
  struct timeval stime1;
  struct timeval etime1;
  struct timeval stime0;
  struct timeval etime0;

  auto dtype = datatype::create<unsigned short int>();
  node::Dataset data0 = node::Dataset(root, "data0", dtype, space, lcpl, dcpl, dapl);
  gettimeofday(&stime0, NULL);
  for(long long unsigned int i = 0; i != nframe; i++){
    data0.extent(0, 1);
    framespace.offset({i, 0, 0});
    dataspace::Dataspace file_space = data0.dataspace();
    file_space.selection(dataspace::SelectionOperation::SET, framespace);
    data0.write(frame, dtype, memspace, file_space, dtpl);
  }
  gettimeofday(&etime0, NULL);

  node::Dataset data1 = node::Dataset(root,
				      "data1",
				      datatype::create<unsigned short int>(),
				      space,lcpl,dcpl,dapl);

  gettimeofday(&stime1, NULL);

  for(long long unsigned int i = 0; i != nframe; i++){
    data1.extent(0, 1);
    framespace.offset({i, 0, 0});

    data1.write(frame, framespace);
  }
  gettimeofday(&etime1, NULL);

  double time0 = (double)(etime0.tv_sec - stime0.tv_sec)
    + (double)(etime0.tv_usec - stime0.tv_usec)*0.000001;
  double time1 = (double)(etime1.tv_sec - stime1.tv_sec)
    + (double)(etime1.tv_usec - stime1.tv_usec)*0.000001;

  // std::cerr << time0 <<  std::endl;
  // std::cerr << time1 <<  std::endl;
  EXPECT_GT(14 * time1, time0);
  EXPECT_GT(14 * time0, time1);

  std::vector<unsigned short int> read_value(xdim * ydim);

  for(long long unsigned int i = 0; i != nframe; i++){
    data1.extent(0, 1);
    framespace.offset({i, 0, 0});
    data1.read(read_value, framespace);
    EXPECT_EQ(frame, read_value);
  }

}

TEST_F(DatasetWriteSpeedTest, write)
{
  struct timeval stime1;
  struct timeval etime1;
  struct timeval stime0;
  struct timeval etime0;

  auto dtype = datatype::create<unsigned short int>();
  node::Dataset data2 = node::Dataset(root, "data2", dtype, space, lcpl, dcpl, dapl);
  gettimeofday(&stime0, NULL);
  for(long long unsigned int i = 0; i != nframe; i++){
    data2.extent(0, 1);
    framespace.offset({i, 0, 0});
    dataspace::Dataspace file_space = data2.dataspace();
    file_space.selection(dataspace::SelectionOperation::SET, framespace);
    data2.write(frame, dtype, memspace, file_space, dtpl);
  }
  gettimeofday(&etime0, NULL);

  node::Dataset data3 = node::Dataset(root,
				      "data3",
				      datatype::create<unsigned short int>(),
				      fullspace, lcpl, dcpl, dapl);

  gettimeofday(&stime1, NULL);

  data3.write(allframes);
  gettimeofday(&etime1, NULL);

  double time0 = (double)(etime0.tv_sec - stime0.tv_sec)
    + (double)(etime0.tv_usec - stime0.tv_usec)*0.000001;
  double time1 = (double)(etime1.tv_sec - stime1.tv_sec)
    + (double)(etime1.tv_usec - stime1.tv_usec)*0.000001;

  // std::cerr << time0 <<  std::endl;
  // std::cerr << time1 <<  std::endl;
  EXPECT_GT(14 * time1, time0);
  EXPECT_GT(14 * time0, time1);

  std::vector<unsigned short int> read_value(xdim * ydim);

  for(long long unsigned int i = 0; i != nframe; i++){
    data3.extent(0, 1);
    framespace.offset({i, 0, 0});
    data3.read(read_value, framespace);
    auto first = allframes.begin() + i * xdim * ydim;
    auto last = allframes.begin() + (i + 1) * xdim * ydim;
    std::vector<unsigned short int> buffer(first, last);
    EXPECT_EQ(buffer, read_value);
  }

}

#endif
<|endoftext|>


<commit_before>// RUN: rm -rf %T/clang-tidy/export-relpath
// RUN: mkdir -p %T/clang-tidy/export-relpath/subdir
// RUN: cp %s %T/clang-tidy/export-relpath/subdir/source.cpp
// RUN: echo '[{ "directory": "%T/clang-tidy/export-relpath/subdir", "command": "clang++ source.cpp", "file": "%T/clang-tidy/export-relpath/subdir/source.cpp"}]' > %T/clang-tidy/export-relpath/subdir/compile_commands.json
//
// Check that running clang-tidy in './subdir' and storing results
// in './fixes.yaml' works as expected.
//
// RUN: cd %T/clang-tidy/export-relpath
// RUN: clang-tidy -p subdir subdir/source.cpp -checks='-*,google-explicit-constructor,llvm-namespace-comment' -export-fixes=./fixes.yaml
// RUN: FileCheck -input-file=%T/clang-tidy/export-relpath/fixes.yaml -check-prefix=CHECK-YAML %s

namespace i {
void f(); // So that the namespace isn't empty.
}
// CHECK-YAML: ReplacementText: ' // namespace i'

class A { A(int i); };
// CHECK-YAML: ReplacementText: 'explicit '
<commit_msg>Ensure that test clang-tidy/export-relpath.cpp works with Windows path separators.<commit_after>// RUN: rm -rf %T/clang-tidy/export-relpath
// RUN: mkdir -p %T/clang-tidy/export-relpath/subdir
// RUN: cp %s %T/clang-tidy/export-relpath/subdir/source.cpp
// RUN: echo '[{ "directory": "%/T/clang-tidy/export-relpath/subdir", "command": "clang++ source.cpp", "file": "%/T/clang-tidy/export-relpath/subdir/source.cpp"}]' > %T/clang-tidy/export-relpath/subdir/compile_commands.json
//
// Check that running clang-tidy in './subdir' and storing results
// in './fixes.yaml' works as expected.
//
// RUN: cd %T/clang-tidy/export-relpath
// RUN: clang-tidy -p subdir subdir/source.cpp -checks='-*,google-explicit-constructor,llvm-namespace-comment' -export-fixes=./fixes.yaml
// RUN: FileCheck -input-file=%T/clang-tidy/export-relpath/fixes.yaml -check-prefix=CHECK-YAML %s

namespace i {
void f(); // So that the namespace isn't empty.
}
// CHECK-YAML: ReplacementText: ' // namespace i'

class A { A(int i); };
// CHECK-YAML: ReplacementText: 'explicit '
<|endoftext|>


<commit_before>#include "Halide.h"
#include <stdio.h>

// The check has to go in the Halide namespace, because get_source_location looks for the first thing outside of it
namespace Halide {
void check(const void *var, const std::string &type,
           const std::string &correct_name,
           const std::string &correct_file, int line) {
    std::string correct_loc = correct_file + ":" + std::to_string(line);
    std::string loc = Halide::Internal::Introspection::get_source_location();
    std::string name = Halide::Internal::Introspection::get_variable_name(var, type);

    if (name != correct_name) {
        printf("Mispredicted name: %s vs %s\n",
               name.c_str(), correct_name.c_str());
        exit(-1);
    }

    if (loc != correct_loc) {
        printf("Mispredicted source location: %s vs %s\n",
               loc.c_str(), correct_loc.c_str());
        exit(-1);
    }
}
}

using Halide::check;

int global_int = 7;

struct SomeStruct {
    int global_struct_a;
    int global_struct_b;
    static float static_float;
    static double static_member_double_array[17];
    static struct SubStruct {
        int a;
    } substruct;
} global_struct;

float SomeStruct::static_float = 3.0f;
double SomeStruct::static_member_double_array[17] = {0};
SomeStruct::SubStruct SomeStruct::substruct = {0};

float global_array[7];

namespace Foo {

int global_int_in_foo = 8;

namespace {
struct Bar {
    typedef int bint;
    bint bar_int;
    Bar(int x) : bar_int(x) {}
    ~Bar() {}
    void check_bar() {
        check(this, "Foo::{anonymous}::Bar", "b", __FILE__, __LINE__);
        check(&bar_int, "Foo::{anonymous}::Bar::bint", "b.bar_int", __FILE__, __LINE__);
    }
    int get() {
        return bar_int * 2;
    }
};

int g(int x) {
    Bar b(x*7);
    b.check_bar();
    return b.get();
}

}

int f(int x) {
    static float static_float_in_f = 0.3f;
    int y = g(x) + g(x-1);
    check(&y, "int", "y", __FILE__, __LINE__);
    check(&static_float_in_f, "float", "static_float_in_f", __FILE__, __LINE__);
    return y - 1;
}

}

typedef float fancy_float;

struct HeapObject {
    float f;
    fancy_float f2;
    int i;
    struct  {
        char c;
        double d;
        int i_array[20];
    } inner;
    HeapObject *ptr;
    struct inner2 {
        int a[5];
    };
    inner2 inner2_array[10];
};

int main(int argc, char **argv) {
    bool result = HalideIntrospectionCanary::test();

    if (result) {
        printf("Halide C++ introspection claims to be working with this build config\n");
    } else {
        printf("Halide C++ introspection doesn't claim to work with this build config. Not continuing.\n");
        return 0;
    }

    printf("Continuing with further tests...\n");

    Foo::f(17);

    // Make sure it works all the way up to main
    int secret_int = 5;
    check(&secret_int, "int", "secret_int", __FILE__, __LINE__);

    // Make sure it rejects heap variables
    int *on_the_heap = new int;
    check(on_the_heap, "int", "", __FILE__, __LINE__);
    delete on_the_heap;

    // .. unless they're members of explicitly registered objects
    HeapObject *obj = new HeapObject;
    static HeapObject *dummy_heap_object_ptr = nullptr;
    check(&dummy_heap_object_ptr, "HeapObject *", "dummy_heap_object_ptr", __FILE__, __LINE__);
    Halide::Internal::Introspection::register_heap_object(obj, sizeof(HeapObject), &dummy_heap_object_ptr);
    check(&(obj->f), "float", "f", __FILE__, __LINE__);
    check(&(obj->f2), "fancy_float", "f2", __FILE__, __LINE__);
    check(&(obj->f2), "float", "f2", __FILE__, __LINE__);
    check(&(obj->i), "int", "i", __FILE__, __LINE__);
    check(&(obj->inner.c), "char", "inner.c", __FILE__, __LINE__);
    check(&(obj->inner.d), "double", "inner.d", __FILE__, __LINE__);
    check(&(obj->ptr), "HeapObject *", "ptr", __FILE__, __LINE__);
    // TODO:
    check(&(obj->inner.i_array[10]), "int", "inner.i_array[10]", __FILE__, __LINE__);
    check(&(obj->inner2_array[4].a[2]), "int", "inner2_array[4].a[2]", __FILE__, __LINE__);
    check(&(obj->inner.i_array), "int [20]", "inner.i_array", __FILE__, __LINE__);
    Halide::Internal::Introspection::deregister_heap_object(obj, sizeof(HeapObject));
    delete obj;

    // Make sure it works for arrays.
    float an_array[17];
    check(&an_array[5], "float", "an_array[5]", __FILE__, __LINE__);

    // Check what happens with lexical blocks which may reuse stack positions
    {
        int block_a = 3;
        (void)block_a;
        check(&block_a, "int", "block_a", __FILE__, __LINE__);
    }

    {
        int block_b = 3;
        (void)block_b;
        check(&block_b, "int", "block_b", __FILE__, __LINE__);
    }

    {
        int block_c = 3;
        (void)block_c;
        check(&block_c, "int", "block_c", __FILE__, __LINE__);
    }

    // Check we can name globals
    check(&global_int, "int", "global_int", __FILE__, __LINE__);
    check(&Foo::global_int_in_foo, "int", "Foo::global_int_in_foo", __FILE__, __LINE__);

    // Check we can name members of globals
    check(&global_struct.global_struct_a, "int", "global_struct.global_struct_a", __FILE__, __LINE__);
    check(&global_struct.global_struct_b, "int", "global_struct.global_struct_b", __FILE__, __LINE__);

    check(&global_array[4], "float", "global_array[4]", __FILE__, __LINE__);

    check(&SomeStruct::static_float, "float", "SomeStruct::static_float", __FILE__, __LINE__);

    check(&SomeStruct::static_member_double_array[5], "double", "SomeStruct::static_member_double_array[5]", __FILE__, __LINE__);

    check(&SomeStruct::substruct.a, "int", "SomeStruct::substruct.a", __FILE__, __LINE__);

    printf("Success!\n");

    return 0;
}
<commit_msg>Fix introspection test<commit_after>#include "Halide.h"
#include <stdio.h>

// The check has to go in the Halide namespace, because get_source_location looks for the first thing outside of it
namespace Halide {
void check(const void *var, const std::string &type,
           const std::string &correct_name,
           const std::string &correct_file, int line) {
    std::string correct_loc = correct_file + ":" + std::to_string(line);
    std::string loc = Halide::Internal::Introspection::get_source_location();
    std::string name = Halide::Internal::Introspection::get_variable_name(var, type);

    if (name != correct_name) {
        printf("Mispredicted name: %s vs %s\n",
               name.c_str(), correct_name.c_str());
        exit(-1);
    }

    if (loc != correct_loc) {
        printf("Mispredicted source location: %s vs %s\n",
               loc.c_str(), correct_loc.c_str());
        exit(-1);
    }
}
}

using Halide::check;

int global_int = 7;

struct SomeStruct {
    int global_struct_a;
    int global_struct_b;
    static float static_float;
    static double static_member_double_array[17];
    static struct SubStruct {
        int a;
    } substruct;
} global_struct;

float SomeStruct::static_float = 3.0f;
double SomeStruct::static_member_double_array[17] = {0};
SomeStruct::SubStruct SomeStruct::substruct = {0};

float global_array[7];

namespace Foo {

int global_int_in_foo = 8;

namespace {
struct Bar {
    typedef int bint;
    bint bar_int;
    Bar(int x) : bar_int(x) {}
    ~Bar() {}
    void check_bar() {
        check(this, "Foo::{anonymous}::Bar", "b", __FILE__, __LINE__);
        check(&bar_int, "Foo::{anonymous}::Bar::bint", "b.bar_int", __FILE__, __LINE__);
    }
    int get() {
        return bar_int * 2;
    }
};

int g(int x) {
    Bar b(x*7);
    b.check_bar();
    return b.get();
}

}

int f(int x) {
    static float static_float_in_f = 0.3f;
    int y = g(x) + g(x-1);
    check(&y, "int", "y", __FILE__, __LINE__);
    check(&static_float_in_f, "float", "static_float_in_f", __FILE__, __LINE__);
    return y - 1;
}

}

typedef float fancy_float;

struct HeapObject {
    float f;
    fancy_float f2;
    int i;
    struct  {
        char c;
        double d;
        int i_array[20];
    } inner;
    HeapObject *ptr;
    struct inner2 {
        int a[5];
    };
    inner2 inner2_array[10];
};

int main(int argc, char **argv) {
    bool result = HalideIntrospectionCanary::test(&HalideIntrospectionCanary::test_a);

    if (result) {
        printf("Halide C++ introspection claims to be working with this build config\n");
    } else {
        printf("Halide C++ introspection doesn't claim to work with this build config. Not continuing.\n");
        return 0;
    }

    printf("Continuing with further tests...\n");

    Foo::f(17);

    // Make sure it works all the way up to main
    int secret_int = 5;
    check(&secret_int, "int", "secret_int", __FILE__, __LINE__);

    // Make sure it rejects heap variables
    int *on_the_heap = new int;
    check(on_the_heap, "int", "", __FILE__, __LINE__);
    delete on_the_heap;

    // .. unless they're members of explicitly registered objects
    HeapObject *obj = new HeapObject;
    static HeapObject *dummy_heap_object_ptr = nullptr;
    check(&dummy_heap_object_ptr, "HeapObject *", "dummy_heap_object_ptr", __FILE__, __LINE__);
    Halide::Internal::Introspection::register_heap_object(obj, sizeof(HeapObject), &dummy_heap_object_ptr);
    check(&(obj->f), "float", "f", __FILE__, __LINE__);
    check(&(obj->f2), "fancy_float", "f2", __FILE__, __LINE__);
    check(&(obj->f2), "float", "f2", __FILE__, __LINE__);
    check(&(obj->i), "int", "i", __FILE__, __LINE__);
    check(&(obj->inner.c), "char", "inner.c", __FILE__, __LINE__);
    check(&(obj->inner.d), "double", "inner.d", __FILE__, __LINE__);
    check(&(obj->ptr), "HeapObject *", "ptr", __FILE__, __LINE__);
    // TODO:
    check(&(obj->inner.i_array[10]), "int", "inner.i_array[10]", __FILE__, __LINE__);
    check(&(obj->inner2_array[4].a[2]), "int", "inner2_array[4].a[2]", __FILE__, __LINE__);
    check(&(obj->inner.i_array), "int [20]", "inner.i_array", __FILE__, __LINE__);
    Halide::Internal::Introspection::deregister_heap_object(obj, sizeof(HeapObject));
    delete obj;

    // Make sure it works for arrays.
    float an_array[17];
    check(&an_array[5], "float", "an_array[5]", __FILE__, __LINE__);

    // Check what happens with lexical blocks which may reuse stack positions
    {
        int block_a = 3;
        (void)block_a;
        check(&block_a, "int", "block_a", __FILE__, __LINE__);
    }

    {
        int block_b = 3;
        (void)block_b;
        check(&block_b, "int", "block_b", __FILE__, __LINE__);
    }

    {
        int block_c = 3;
        (void)block_c;
        check(&block_c, "int", "block_c", __FILE__, __LINE__);
    }

    // Check we can name globals
    check(&global_int, "int", "global_int", __FILE__, __LINE__);
    check(&Foo::global_int_in_foo, "int", "Foo::global_int_in_foo", __FILE__, __LINE__);

    // Check we can name members of globals
    check(&global_struct.global_struct_a, "int", "global_struct.global_struct_a", __FILE__, __LINE__);
    check(&global_struct.global_struct_b, "int", "global_struct.global_struct_b", __FILE__, __LINE__);

    check(&global_array[4], "float", "global_array[4]", __FILE__, __LINE__);

    check(&SomeStruct::static_float, "float", "SomeStruct::static_float", __FILE__, __LINE__);

    check(&SomeStruct::static_member_double_array[5], "double", "SomeStruct::static_member_double_array[5]", __FILE__, __LINE__);

    check(&SomeStruct::substruct.a, "int", "SomeStruct::substruct.a", __FILE__, __LINE__);

    printf("Success!\n");

    return 0;
}
<|endoftext|>


<commit_before>//===--- CSClosure.cpp - Closures -----------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements constraint generation and solution application for
// closures. It provides part of the implementation of the ConstraintSystem
// class.
//
//===----------------------------------------------------------------------===//

#include "TypeChecker.h"
#include "swift/Sema/ConstraintSystem.h"

using namespace swift;
using namespace swift::constraints;

namespace {

// MARK: Constraint generation

/// Statement visitor that generates constraints for a given closure body.
class ClosureConstraintGenerator
    : public StmtVisitor<ClosureConstraintGenerator, void> {
  friend StmtVisitor<ClosureConstraintGenerator, void>;

  ConstraintSystem &cs;
  ClosureExpr *closure;

public:
  /// Whether an error was encountered while generating constraints.
  bool hadError = false;

  ClosureConstraintGenerator(ConstraintSystem &cs, ClosureExpr *closure)
      : cs(cs), closure(closure) {}

private:
  void visitDecl(Decl *decl) {
    // Just ignore #if; the chosen children should appear in the
    // surrounding context.  This isn't good for source tools but it
    // at least works.
    if (isa<IfConfigDecl>(decl))
      return;

    // Skip #warning/#error; we'll handle them when applying the closure.
    if (isa<PoundDiagnosticDecl>(decl))
      return;

    // Ignore variable declarations, because they're always handled within
    // their enclosing pattern bindings.
    if (isa<VarDecl>(decl))
      return;

    llvm_unreachable("Unimplemented case for closure body");
  }

  void visitBraceStmt(BraceStmt *braceStmt) {
    for (auto node : braceStmt->getElements()) {
      if (auto expr = node.dyn_cast<Expr *>()) {
        auto generatedExpr = cs.generateConstraints(
            expr, closure, /*isInputExpression=*/false);
        if (!generatedExpr) {
          hadError = true;
        }
      } else if (auto stmt = node.dyn_cast<Stmt *>()) {
        visit(stmt);
      } else {
        visitDecl(node.get<Decl *>());
      }
    }
  }

  void visitReturnStmt(ReturnStmt *returnStmt) {
    auto expr = returnStmt->getResult();

    // FIXME: Implies Void return?
    if (!expr)
      return;

    // FIXME: Use SolutionApplicationTarget?
    expr = cs.generateConstraints(expr, closure, /*isInputExpression=*/false);
    if (!expr) {
      hadError = true;
      return;
    }

    // FIXME: Locator should point at the return statement?
    bool hasReturn = hasExplicitResult(closure);
    cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
                     cs.getClosureType(closure)->getResult(),
                     cs.getConstraintLocator(
                         closure, LocatorPathElt::ClosureBody(hasReturn)));
  }

#define UNSUPPORTED_STMT(STMT) void visit##STMT##Stmt(STMT##Stmt *) { \
      llvm_unreachable("Unsupported statement kind " #STMT);          \
  }
  UNSUPPORTED_STMT(Yield)
  UNSUPPORTED_STMT(Defer)
  UNSUPPORTED_STMT(If)
  UNSUPPORTED_STMT(Guard)
  UNSUPPORTED_STMT(While)
  UNSUPPORTED_STMT(Do)
  UNSUPPORTED_STMT(DoCatch)
  UNSUPPORTED_STMT(RepeatWhile)
  UNSUPPORTED_STMT(ForEach)
  UNSUPPORTED_STMT(Switch)
  UNSUPPORTED_STMT(Case)
  UNSUPPORTED_STMT(Break)
  UNSUPPORTED_STMT(Continue)
  UNSUPPORTED_STMT(Fallthrough)
  UNSUPPORTED_STMT(Fail)
  UNSUPPORTED_STMT(Throw)
  UNSUPPORTED_STMT(PoundAssert)
#undef UNSUPPORTED_STMT
};

}

bool ConstraintSystem::generateConstraints(ClosureExpr *closure) {
  ClosureConstraintGenerator generator(*this, closure);
  generator.visit(closure->getBody());
  return generator.hadError;
}

// MARK: Solution application

namespace {

/// Statement visitor that applies constraints for a given closure body.
class ClosureConstraintApplication
    : public StmtVisitor<ClosureConstraintApplication, ASTNode> {
  friend StmtVisitor<ClosureConstraintApplication, ASTNode>;

  Solution &solution;
  ClosureExpr *closure;
  Type resultType;
  RewriteTargetFn rewriteTarget;
  bool isSingleExpression;

public:
  /// Whether an error was encountered while generating constraints.
  bool hadError = false;

  ClosureConstraintApplication(
      Solution &solution, ClosureExpr *closure, Type resultType,
      RewriteTargetFn rewriteTarget)
    : solution(solution), closure(closure), resultType(resultType),
      rewriteTarget(rewriteTarget),
      isSingleExpression(closure->hasSingleExpressionBody()) { }

private:
  /// Rewrite an expression without any particularly special context.
  Expr *rewriteExpr(Expr *expr) {
    auto result = rewriteTarget(
      SolutionApplicationTarget(expr, closure, CTP_Unused, Type(),
                                /*isDiscarded=*/false));
    if (result)
      return result->getAsExpr();

    return nullptr;
  }

  void visitDecl(Decl *decl) {

    if (isa<IfConfigDecl>(decl))
      return;

    llvm_unreachable("Unimplemented case for closure body");
  }

  ASTNode visitBraceStmt(BraceStmt *braceStmt) {
    for (auto &node : braceStmt->getElements()) {
      if (auto expr = node.dyn_cast<Expr *>()) {
        // Rewrite the expression.
        if (auto rewrittenExpr = rewriteExpr(expr))
          node = expr;
        else
          hadError = true;
      } else if (auto stmt = node.dyn_cast<Stmt *>()) {
        node = visit(stmt);
      } else {
        visitDecl(node.get<Decl *>());
      }
    }

    return braceStmt;
  }

  ASTNode visitReturnStmt(ReturnStmt *returnStmt) {
    auto resultExpr = returnStmt->getResult();
    if (!resultExpr)
      return returnStmt;

    enum {
      convertToResult,
      coerceToVoid,
      coerceFromNever,
    } mode;

    auto resultExprType =
        solution.simplifyType(solution.getType(resultExpr))->getRValueType();
    // A closure with a non-void return expression can coerce to a closure
    // that returns Void.
    if (resultType->isVoid() && !resultExprType->isVoid()) {
      mode = coerceToVoid;

      // A single-expression closure with a Never expression type
      // coerces to any other function type.
    } else if (isSingleExpression && resultExprType->isUninhabited()) {
      mode = coerceFromNever;

      // Normal rule is to coerce to the return expression to the closure type.
    } else {
      mode = convertToResult;
    }

    SolutionApplicationTarget resultTarget(
        resultExpr, closure,
        mode == convertToResult ? CTP_ReturnStmt : CTP_Unused,
        mode == convertToResult ? resultType : Type(),
        /*isDiscarded=*/false);
    if (auto newResultTarget = rewriteTarget(resultTarget))
      resultExpr = newResultTarget->getAsExpr();

    switch (mode) {
    case convertToResult:
      // Record the coerced expression.
      returnStmt->setResult(resultExpr);
      return returnStmt;

    case coerceToVoid: {
      // Evaluate the expression, then produce a return statement that
      // returns nothing.
      TypeChecker::checkIgnoredExpr(resultExpr);
      auto &ctx = solution.getConstraintSystem().getASTContext();
      auto newReturnStmt =
          new (ctx) ReturnStmt(
            returnStmt->getStartLoc(), nullptr, /*implicit=*/true);
      ASTNode elements[2] = { resultExpr, newReturnStmt };
      return BraceStmt::create(ctx, returnStmt->getStartLoc(),
                               elements, returnStmt->getEndLoc(),
                               /*implicit*/ true);
    }

    case coerceFromNever:
      // Replace the return statement with its expression, so that the
      // expression is evaluated directly. This only works because coercion
      // from never is limited to single-expression closures.
      return resultExpr;
    }

    return returnStmt;
  }

#define UNSUPPORTED_STMT(STMT) ASTNode visit##STMT##Stmt(STMT##Stmt *) { \
      llvm_unreachable("Unsupported statement kind " #STMT);          \
  }
  UNSUPPORTED_STMT(Yield)
  UNSUPPORTED_STMT(Defer)
  UNSUPPORTED_STMT(If)
  UNSUPPORTED_STMT(Guard)
  UNSUPPORTED_STMT(While)
  UNSUPPORTED_STMT(Do)
  UNSUPPORTED_STMT(DoCatch)
  UNSUPPORTED_STMT(RepeatWhile)
  UNSUPPORTED_STMT(ForEach)
  UNSUPPORTED_STMT(Switch)
  UNSUPPORTED_STMT(Case)
  UNSUPPORTED_STMT(Break)
  UNSUPPORTED_STMT(Continue)
  UNSUPPORTED_STMT(Fallthrough)
  UNSUPPORTED_STMT(Fail)
  UNSUPPORTED_STMT(Throw)
  UNSUPPORTED_STMT(PoundAssert)
#undef UNSUPPORTED_STMT

};

}

SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
    Solution &solution, AnyFunctionRef fn,
    DeclContext *&currentDC,
    RewriteTargetFn rewriteTarget) {
  auto &cs = solution.getConstraintSystem();
  auto closure = dyn_cast_or_null<ClosureExpr>(fn.getAbstractClosureExpr());
  FunctionType *closureFnType = nullptr;
  if (closure) {
    // Update the closure's type.
    auto closureType = solution.simplifyType(cs.getType(closure));
    cs.setType(closure, closureType);

    // Coerce the parameter types.
    closureFnType = closureType->castTo<FunctionType>();
    auto *params = closure->getParameters();
    TypeChecker::coerceParameterListToType(params, closureFnType);

    // Coerce the result type, if it was written explicitly.
    if (closure->hasExplicitResultType()) {
      closure->setExplicitResultType(closureFnType->getResult());
    }
  }

  // Enter the context of the function before performing any additional
  // transformations.
  llvm::SaveAndRestore<DeclContext *> savedDC(currentDC, fn.getAsDeclContext());

  // Apply the result builder transform, if there is one.
  if (auto transform = solution.getAppliedBuilderTransform(fn)) {
    // Apply the result builder to the closure. We want to be in the
    // context of the closure for subsequent transforms.
    auto newBody = applyResultBuilderTransform(
        solution, *transform, fn.getBody(), fn.getAsDeclContext(),
        [&](SolutionApplicationTarget target) {
          auto resultTarget = rewriteTarget(target);
          if (resultTarget) {
            if (auto expr = resultTarget->getAsExpr())
              solution.setExprTypes(expr);
          }

          return resultTarget;
        });
    if (!newBody)
      return SolutionApplicationToFunctionResult::Failure;

    fn.setTypecheckedBody(newBody, /*isSingleExpression=*/false);
    if (closure) {
      solution.setExprTypes(closure);
    }

    return SolutionApplicationToFunctionResult::Success;

  }
  assert(closure && "Can only get here with a closure at the moment");

  // If this closure is checked as part of the enclosing expression, handle
  // that now.
  if (shouldTypeCheckInEnclosingExpression(closure)) {
    ClosureConstraintApplication application(
        solution, closure, closureFnType->getResult(), rewriteTarget);
    application.visit(fn.getBody());
    closure->setBodyState(ClosureExpr::BodyState::TypeCheckedWithSignature);

    return SolutionApplicationToFunctionResult::Success;
  }

  // Otherwise, we need to delay type checking of the closure until later.
  solution.setExprTypes(closure);
  closure->setBodyState(ClosureExpr::BodyState::ReadyForTypeChecking);
  return SolutionApplicationToFunctionResult::Delay;
}
<commit_msg>[CSClosure] Use rewritten expression when applying solution to a brace statement<commit_after>//===--- CSClosure.cpp - Closures -----------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements constraint generation and solution application for
// closures. It provides part of the implementation of the ConstraintSystem
// class.
//
//===----------------------------------------------------------------------===//

#include "TypeChecker.h"
#include "swift/Sema/ConstraintSystem.h"

using namespace swift;
using namespace swift::constraints;

namespace {

// MARK: Constraint generation

/// Statement visitor that generates constraints for a given closure body.
class ClosureConstraintGenerator
    : public StmtVisitor<ClosureConstraintGenerator, void> {
  friend StmtVisitor<ClosureConstraintGenerator, void>;

  ConstraintSystem &cs;
  ClosureExpr *closure;

public:
  /// Whether an error was encountered while generating constraints.
  bool hadError = false;

  ClosureConstraintGenerator(ConstraintSystem &cs, ClosureExpr *closure)
      : cs(cs), closure(closure) {}

private:
  void visitDecl(Decl *decl) {
    // Just ignore #if; the chosen children should appear in the
    // surrounding context.  This isn't good for source tools but it
    // at least works.
    if (isa<IfConfigDecl>(decl))
      return;

    // Skip #warning/#error; we'll handle them when applying the closure.
    if (isa<PoundDiagnosticDecl>(decl))
      return;

    // Ignore variable declarations, because they're always handled within
    // their enclosing pattern bindings.
    if (isa<VarDecl>(decl))
      return;

    llvm_unreachable("Unimplemented case for closure body");
  }

  void visitBraceStmt(BraceStmt *braceStmt) {
    for (auto node : braceStmt->getElements()) {
      if (auto expr = node.dyn_cast<Expr *>()) {
        auto generatedExpr = cs.generateConstraints(
            expr, closure, /*isInputExpression=*/false);
        if (!generatedExpr) {
          hadError = true;
        }
      } else if (auto stmt = node.dyn_cast<Stmt *>()) {
        visit(stmt);
      } else {
        visitDecl(node.get<Decl *>());
      }
    }
  }

  void visitReturnStmt(ReturnStmt *returnStmt) {
    auto expr = returnStmt->getResult();

    // FIXME: Implies Void return?
    if (!expr)
      return;

    // FIXME: Use SolutionApplicationTarget?
    expr = cs.generateConstraints(expr, closure, /*isInputExpression=*/false);
    if (!expr) {
      hadError = true;
      return;
    }

    // FIXME: Locator should point at the return statement?
    bool hasReturn = hasExplicitResult(closure);
    cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
                     cs.getClosureType(closure)->getResult(),
                     cs.getConstraintLocator(
                         closure, LocatorPathElt::ClosureBody(hasReturn)));
  }

#define UNSUPPORTED_STMT(STMT) void visit##STMT##Stmt(STMT##Stmt *) { \
      llvm_unreachable("Unsupported statement kind " #STMT);          \
  }
  UNSUPPORTED_STMT(Yield)
  UNSUPPORTED_STMT(Defer)
  UNSUPPORTED_STMT(If)
  UNSUPPORTED_STMT(Guard)
  UNSUPPORTED_STMT(While)
  UNSUPPORTED_STMT(Do)
  UNSUPPORTED_STMT(DoCatch)
  UNSUPPORTED_STMT(RepeatWhile)
  UNSUPPORTED_STMT(ForEach)
  UNSUPPORTED_STMT(Switch)
  UNSUPPORTED_STMT(Case)
  UNSUPPORTED_STMT(Break)
  UNSUPPORTED_STMT(Continue)
  UNSUPPORTED_STMT(Fallthrough)
  UNSUPPORTED_STMT(Fail)
  UNSUPPORTED_STMT(Throw)
  UNSUPPORTED_STMT(PoundAssert)
#undef UNSUPPORTED_STMT
};

}

bool ConstraintSystem::generateConstraints(ClosureExpr *closure) {
  ClosureConstraintGenerator generator(*this, closure);
  generator.visit(closure->getBody());
  return generator.hadError;
}

// MARK: Solution application

namespace {

/// Statement visitor that applies constraints for a given closure body.
class ClosureConstraintApplication
    : public StmtVisitor<ClosureConstraintApplication, ASTNode> {
  friend StmtVisitor<ClosureConstraintApplication, ASTNode>;

  Solution &solution;
  ClosureExpr *closure;
  Type resultType;
  RewriteTargetFn rewriteTarget;
  bool isSingleExpression;

public:
  /// Whether an error was encountered while generating constraints.
  bool hadError = false;

  ClosureConstraintApplication(
      Solution &solution, ClosureExpr *closure, Type resultType,
      RewriteTargetFn rewriteTarget)
    : solution(solution), closure(closure), resultType(resultType),
      rewriteTarget(rewriteTarget),
      isSingleExpression(closure->hasSingleExpressionBody()) { }

private:
  /// Rewrite an expression without any particularly special context.
  Expr *rewriteExpr(Expr *expr) {
    auto result = rewriteTarget(
      SolutionApplicationTarget(expr, closure, CTP_Unused, Type(),
                                /*isDiscarded=*/false));
    if (result)
      return result->getAsExpr();

    return nullptr;
  }

  void visitDecl(Decl *decl) {

    if (isa<IfConfigDecl>(decl))
      return;

    llvm_unreachable("Unimplemented case for closure body");
  }

  ASTNode visitBraceStmt(BraceStmt *braceStmt) {
    for (auto &node : braceStmt->getElements()) {
      if (auto expr = node.dyn_cast<Expr *>()) {
        // Rewrite the expression.
        if (auto rewrittenExpr = rewriteExpr(expr))
          node = rewrittenExpr;
        else
          hadError = true;
      } else if (auto stmt = node.dyn_cast<Stmt *>()) {
        node = visit(stmt);
      } else {
        visitDecl(node.get<Decl *>());
      }
    }

    return braceStmt;
  }

  ASTNode visitReturnStmt(ReturnStmt *returnStmt) {
    auto resultExpr = returnStmt->getResult();
    if (!resultExpr)
      return returnStmt;

    enum {
      convertToResult,
      coerceToVoid,
      coerceFromNever,
    } mode;

    auto resultExprType =
        solution.simplifyType(solution.getType(resultExpr))->getRValueType();
    // A closure with a non-void return expression can coerce to a closure
    // that returns Void.
    if (resultType->isVoid() && !resultExprType->isVoid()) {
      mode = coerceToVoid;

      // A single-expression closure with a Never expression type
      // coerces to any other function type.
    } else if (isSingleExpression && resultExprType->isUninhabited()) {
      mode = coerceFromNever;

      // Normal rule is to coerce to the return expression to the closure type.
    } else {
      mode = convertToResult;
    }

    SolutionApplicationTarget resultTarget(
        resultExpr, closure,
        mode == convertToResult ? CTP_ReturnStmt : CTP_Unused,
        mode == convertToResult ? resultType : Type(),
        /*isDiscarded=*/false);
    if (auto newResultTarget = rewriteTarget(resultTarget))
      resultExpr = newResultTarget->getAsExpr();

    switch (mode) {
    case convertToResult:
      // Record the coerced expression.
      returnStmt->setResult(resultExpr);
      return returnStmt;

    case coerceToVoid: {
      // Evaluate the expression, then produce a return statement that
      // returns nothing.
      TypeChecker::checkIgnoredExpr(resultExpr);
      auto &ctx = solution.getConstraintSystem().getASTContext();
      auto newReturnStmt =
          new (ctx) ReturnStmt(
            returnStmt->getStartLoc(), nullptr, /*implicit=*/true);
      ASTNode elements[2] = { resultExpr, newReturnStmt };
      return BraceStmt::create(ctx, returnStmt->getStartLoc(),
                               elements, returnStmt->getEndLoc(),
                               /*implicit*/ true);
    }

    case coerceFromNever:
      // Replace the return statement with its expression, so that the
      // expression is evaluated directly. This only works because coercion
      // from never is limited to single-expression closures.
      return resultExpr;
    }

    return returnStmt;
  }

#define UNSUPPORTED_STMT(STMT) ASTNode visit##STMT##Stmt(STMT##Stmt *) { \
      llvm_unreachable("Unsupported statement kind " #STMT);          \
  }
  UNSUPPORTED_STMT(Yield)
  UNSUPPORTED_STMT(Defer)
  UNSUPPORTED_STMT(If)
  UNSUPPORTED_STMT(Guard)
  UNSUPPORTED_STMT(While)
  UNSUPPORTED_STMT(Do)
  UNSUPPORTED_STMT(DoCatch)
  UNSUPPORTED_STMT(RepeatWhile)
  UNSUPPORTED_STMT(ForEach)
  UNSUPPORTED_STMT(Switch)
  UNSUPPORTED_STMT(Case)
  UNSUPPORTED_STMT(Break)
  UNSUPPORTED_STMT(Continue)
  UNSUPPORTED_STMT(Fallthrough)
  UNSUPPORTED_STMT(Fail)
  UNSUPPORTED_STMT(Throw)
  UNSUPPORTED_STMT(PoundAssert)
#undef UNSUPPORTED_STMT

};

}

SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
    Solution &solution, AnyFunctionRef fn,
    DeclContext *&currentDC,
    RewriteTargetFn rewriteTarget) {
  auto &cs = solution.getConstraintSystem();
  auto closure = dyn_cast_or_null<ClosureExpr>(fn.getAbstractClosureExpr());
  FunctionType *closureFnType = nullptr;
  if (closure) {
    // Update the closure's type.
    auto closureType = solution.simplifyType(cs.getType(closure));
    cs.setType(closure, closureType);

    // Coerce the parameter types.
    closureFnType = closureType->castTo<FunctionType>();
    auto *params = closure->getParameters();
    TypeChecker::coerceParameterListToType(params, closureFnType);

    // Coerce the result type, if it was written explicitly.
    if (closure->hasExplicitResultType()) {
      closure->setExplicitResultType(closureFnType->getResult());
    }
  }

  // Enter the context of the function before performing any additional
  // transformations.
  llvm::SaveAndRestore<DeclContext *> savedDC(currentDC, fn.getAsDeclContext());

  // Apply the result builder transform, if there is one.
  if (auto transform = solution.getAppliedBuilderTransform(fn)) {
    // Apply the result builder to the closure. We want to be in the
    // context of the closure for subsequent transforms.
    auto newBody = applyResultBuilderTransform(
        solution, *transform, fn.getBody(), fn.getAsDeclContext(),
        [&](SolutionApplicationTarget target) {
          auto resultTarget = rewriteTarget(target);
          if (resultTarget) {
            if (auto expr = resultTarget->getAsExpr())
              solution.setExprTypes(expr);
          }

          return resultTarget;
        });
    if (!newBody)
      return SolutionApplicationToFunctionResult::Failure;

    fn.setTypecheckedBody(newBody, /*isSingleExpression=*/false);
    if (closure) {
      solution.setExprTypes(closure);
    }

    return SolutionApplicationToFunctionResult::Success;

  }
  assert(closure && "Can only get here with a closure at the moment");

  // If this closure is checked as part of the enclosing expression, handle
  // that now.
  if (shouldTypeCheckInEnclosingExpression(closure)) {
    ClosureConstraintApplication application(
        solution, closure, closureFnType->getResult(), rewriteTarget);
    application.visit(fn.getBody());
    closure->setBodyState(ClosureExpr::BodyState::TypeCheckedWithSignature);

    return SolutionApplicationToFunctionResult::Success;
  }

  // Otherwise, we need to delay type checking of the closure until later.
  solution.setExprTypes(closure);
  closure->setBodyState(ClosureExpr::BodyState::ReadyForTypeChecking);
  return SolutionApplicationToFunctionResult::Delay;
}
<|endoftext|>


<commit_before>#ifndef BST_HPP
#define BST_HPP
#include "BSTNode.hpp"
#include "BSTIterator.hpp"
#include <utility> // for std::pair

template<typename Data>
class BST {

protected:

  /** Pointer to the root of this BST, or nullptr if the BST is empty */
  BSTNode<Data>* root;

  /** Number of Data items stored in this BST. */
  unsigned int isize;

public:

  /** iterator is an aliased typename for BSTIterator<Data>. */
  typedef BSTIterator<Data> iterator;

  /** Default constructor.
      Initialize an empty BST.
   */
  BST() : root(nullptr), isize(0)
  {
  }

  /** Default destructor.
   *  It is virtual, to allow appropriate destruction of subclass objects.
   *  Delete every node in this BST.
   */ // TODO
  virtual ~BST()
  {
     delete this->root;
     delete this->isize;
     this->isize = NULL;
     this = NULL;
  }

  /** Insert a Data item in the BST.
   *  Return a pair, with the pair's first member set to an
   *  iterator pointing to either the newly inserted element
   *  or to the equivalent element already in the set.
   *  The pair's second element is set to true
   *  if a new element was inserted or false if an
   *  equivalent element already existed.
   */ // TODO
  virtual std::pair<iterator,bool> insert(const Data& item)
  {
    bool inserted;
    if ((*this)->root == NULL){
      (*this)->root = new BSTNode<Data>(item);
      BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
      inserted = true;
      ++isize;
      return std::make_pair(iter,inserted);
    }
    BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
    while (iter->curr != NULL){
      if (iter->curr->value > item){
        iter->curr = iter->curr->left;
      }
      else if (iter->curr->value < item){
        iter->curr = iter->curr->right;
      }
      else { //iter->curr->value == item
        inserted = false;
        ++isize;
        return std::make_pair(iter, inserted);
      }
    }
    iter->curr = new BSTNode<Data>(item);
    inserted = true;
    ++isize;
<<<<<<< HEAD
    return std::make_pair(iter,inserted);
=======
>>>>>>> 7c95b2c5028a68144d7bbbfd41b94c7e8823b5b9
  }

  /** Find a Data item in the BST.
   *  Return an iterator pointing to the item, or the end
   *  iterator if the item is not in the BST.
   */ // TODO
  iterator find(const Data& item) const
  {
    if ((*this)->root == NULL){
      (*this)->root = new BSTNode<Data>(item);
      BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
      return iter;
    }
    BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
    while (iter->curr != NULL && iter->curr->value != item){
      if (iter->curr->value > item){
        iter->curr = iter->curr->left;
      }
      if (iter->curr->value < item){
        iter->curr = iter->curr->right;
      }
    }
    return iter;
  }

  /** Return the number of items currently in the BST.
   */ // TODO
  unsigned int size() const
  {
    return isize;
  }

  /** Remove all elements from this BST, and destroy them,
   *  leaving this BST with a size of 0.
   */ // TODO
  void clear()
  {
    delete BSTNode<Data> (*this)->root;
    (*this)->root = NULL;
    isize = 0;
  }

  /** Return true if the BST is empty, else false.
   */ // TODO
  bool empty() const
  {
    return ( isize == 0 );
  }

  /** Return an iterator pointing to the first item in the BST.
   */ // TODO
  iterator begin() const
  {
    BSTNode<Data> temp = ( (*this)->root );
    while (temp->left)
      temp = temp->left;

    return new BSTIterator<Data>(temp);
  }

  /** Return an iterator pointing past the last item in the BST.
   */
  iterator end() const
  {
    return typename BST<Data>::iterator(nullptr);
  }

 };

#endif //BST_HPP
<commit_msg>Updated BST.hpp<commit_after>#ifndef BST_HPP
#define BST_HPP
#include "BSTNode.hpp"
#include "BSTIterator.hpp"
#include <utility> // for std::pair

template<typename Data>
class BST {

protected:

  /** Pointer to the root of this BST, or nullptr if the BST is empty */
  BSTNode<Data>* root;

  /** Number of Data items stored in this BST. */
  unsigned int isize;

public:

  /** iterator is an aliased typename for BSTIterator<Data>. */
  typedef BSTIterator<Data> iterator;

  /** Default constructor.
      Initialize an empty BST.
   */
  BST() : root(nullptr), isize(0)
  {
  }

  /** Default destructor.
   *  It is virtual, to allow appropriate destruction of subclass objects.
   *  Delete every node in this BST.
   */ // TODO
  virtual ~BST()
  {
     delete this->root;
     delete this->isize;
     this->isize = NULL;
     this = NULL;
  }

  /** Insert a Data item in the BST.
   *  Return a pair, with the pair's first member set to an
   *  iterator pointing to either the newly inserted element
   *  or to the equivalent element already in the set.
   *  The pair's second element is set to true
   *  if a new element was inserted or false if an
   *  equivalent element already existed.
   */ // TODO
  virtual std::pair<iterator,bool> insert(const Data& item)
  {
    bool inserted;
    if ((*this)->root == NULL){
      (*this)->root = new BSTNode<Data>(item);
      BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
      inserted = true;
      ++isize;
      return std::make_pair(iter,inserted);
    }
    BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
    while (iter->curr != NULL){
      if (iter->curr->value > item){
        iter->curr = iter->curr->left;
      }
      else if (iter->curr->value < item){
        iter->curr = iter->curr->right;
      }
      else { //iter->curr->value == item
        inserted = false;
        ++isize;
        return std::make_pair(iter, inserted);
      }
    }
    iter->curr = new BSTNode<Data>(item);
    inserted = true;
    ++isize;
    return std::make_pair(iter,inserted);
  }

  /** Find a Data item in the BST.
   *  Return an iterator pointing to the item, or the end
   *  iterator if the item is not in the BST.
   */ // TODO
  iterator find(const Data& item) const
  {
    if ((*this)->root == NULL){
      (*this)->root = new BSTNode<Data>(item);
      BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
      return iter;
    }
    BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
    while (iter->curr != NULL && iter->curr->value != item){
      if (iter->curr->value > item){
        iter->curr = iter->curr->left;
      }
      if (iter->curr->value < item){
        iter->curr = iter->curr->right;
      }
    }
    return iter;
  }

  /** Return the number of items currently in the BST.
   */ // TODO
  unsigned int size() const
  {
    return isize;
  }

  /** Remove all elements from this BST, and destroy them,
   *  leaving this BST with a size of 0.
   */ // TODO
  void clear()
  {
    delete BSTNode<Data> (*this)->root;
    (*this)->root = NULL;
    isize = 0;
  }

  /** Return true if the BST is empty, else false.
   */ // TODO
  bool empty() const
  {
    return ( isize == 0 );
  }

  /** Return an iterator pointing to the first item in the BST.
   */ // TODO
  iterator begin() const
  {
    BSTNode<Data> temp = ( (*this)->root );
    while (temp->left)
      temp = temp->left;

    return new BSTIterator<Data>(temp);
  }

  /** Return an iterator pointing past the last item in the BST.
   */
  iterator end() const
  {
    return typename BST<Data>::iterator(nullptr);
  }

 };

#endif //BST_HPP
<|endoftext|>


<commit_before>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/

#include <vector>
#include <iostream>

#include <boost/thread.hpp>
#include <boost/bind.hpp>

#include <alcommon-ng/ippc.hpp>
#include <boost/shared_ptr.hpp>
#include <alcommon-ng/tools/dataperftimer.hpp>
#include <alcommon-ng/tools/sleep.hpp>

using namespace AL::Messaging;
using AL::Test::DataPerfTimer;

//using AL::ALPtr;

static const int gThreadCount = 10;
static const int gLoopCount   = 10000;

class ServiceHandler :  public MessageHandler
{
public:
  // to call function on current process
  boost::shared_ptr<AL::Messaging::ResultDefinition> onMessage(const AL::Messaging::CallDefinition & def)
  {
    boost::shared_ptr<AL::Messaging::ResultDefinition> res(new AL::Messaging::ResultDefinition());

    if (def.methodName() == "test2")
    {
      //printf("Method: test2\n");
      std::vector<AL::Messaging::VariableValue>    params = def.args();
      res->value((int)params.front().as<std::string>().size());
    }

    else if (def.methodName() == "echo")
    {
      std::cout << "Method: Echo" << std::endl;
      std::vector<AL::Messaging::VariableValue>    params = def.args();
      res->value(params.front());
    }
    return res;
  }
};

static const std::string gServerAddress = "tcp://127.0.0.1:5555";
static const std::string gClientAddress = "tcp://127.0.0.1:5555";

int main_server()
{
  ServiceHandler           module2Callback;
  boost::shared_ptr<Server>       fIppcServer  = boost::shared_ptr<Server>(new Server());
  fIppcServer->serve(gServerAddress);
  fIppcServer->setMessageHandler(&module2Callback);
  fIppcServer->run();
  return 0;
}

int main_client(int clientId)
{
  std::stringstream sstream;

  AL::Messaging::Client client;
  client.connect(gClientAddress);
  AL::Messaging::ResultDefinition res;

  DataPerfTimer dt;

  for (int i = 0; i < 12; ++i)
  {
    unsigned int                  numBytes = (unsigned int)pow(2.0f,(int)i);
    std::string                   request = std::string(numBytes, 'B');
    AL::Messaging::CallDefinition def;

    def.methodName() = "test2";
    def.args().push_back(request);

    dt.start(gLoopCount, numBytes);
    for (int j = 0; j< gLoopCount; ++j)
    {
      res = client.send(def);
      //assert(tosend == torecv);
    }
    dt.stop();
  }

  return 0;
}

int main(int argc, char **argv)
{

  if (argc > 1 && !strcmp(argv[1], "--client"))
  {
    boost::thread thd[gThreadCount];

    for (int i = 0; i < gThreadCount; ++i)
    {
      std::cout << "starting thread: " << i << std::endl;
      thd[i] = boost::thread(boost::bind(&main_client, i));
    }

    for (int i = 0; i < gThreadCount; ++i)
      thd[i].join();
  }
  else if (argc > 1 && !strcmp(argv[1], "--server"))
  {
    return main_server();
  }
  else
  {
    boost::thread             threadServer(&main_server);
    sleep(1);
    boost::thread             threadClient(boost::bind(&main_client, 0));
    threadClient.join();
    sleep(1);
  }
  return 0;
}
<commit_msg>Added messaging ping and echo tests<commit_after>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/

#include <vector>
#include <iostream>

#include <boost/thread.hpp>
#include <boost/bind.hpp>

#include <alcommon-ng/ippc.hpp>
#include <boost/shared_ptr.hpp>
#include <alcommon-ng/tools/dataperftimer.hpp>
#include <alcommon-ng/tools/sleep.hpp>

using namespace AL::Messaging;
using AL::Test::DataPerfTimer;

static const int gThreadCount = 10;
static const int gLoopCount   = 10000;

class ServiceHandler :  public MessageHandler
{
public:
  // to call function on current process
  boost::shared_ptr<AL::Messaging::ResultDefinition> onMessage(const AL::Messaging::CallDefinition & def)
  {
    boost::shared_ptr<AL::Messaging::ResultDefinition> res(new AL::Messaging::ResultDefinition());

    if (def.methodName() == "ping")
    {
      // do nothing
    }

    if (def.methodName() == "size")
    {
      res->value((int)def.args().front().as<std::string>().size());
    }

    else if (def.methodName() == "echo")
    {
      std::string result = def.args().front().as<std::string>();
      res->value(result);
    }
    return res;
  }
};

static const std::string gServerAddress = "tcp://127.0.0.1:5555";
static const std::string gClientAddress = "tcp://127.0.0.1:5555";

int main_server()
{
  ServiceHandler           module2Callback;
  boost::shared_ptr<Server>       fIppcServer  = boost::shared_ptr<Server>(new Server());
  fIppcServer->serve(gServerAddress);
  fIppcServer->setMessageHandler(&module2Callback);
  fIppcServer->run();
  return 0;
}

int main_client(int clientId)
{
  std::stringstream sstream;

  AL::Messaging::Client client;
  client.connect(gClientAddress);
  AL::Messaging::ResultDefinition res;

  DataPerfTimer dt("Messaging void -> ping -> void");
  dt.start(gLoopCount);
  for (int j = 0; j< gLoopCount; ++j)
  {
    client.send(CallDefinition("ping"));
  }
  dt.stop();

  dt.printHeader("Messaging string -> size -> int");
  for (int i = 0; i < 12; ++i)
  {
    unsigned int                  numBytes = (unsigned int)pow(2.0f,(int)i);
    std::string                   request = std::string(numBytes, 'B');

    dt.start(gLoopCount, numBytes);
    for (int j = 0; j< gLoopCount; ++j)
    {
      res = client.send(CallDefinition("size", request));
      int size = res.value().as<int>();
      //assert(tosend == torecv);
    }
    dt.stop();
  }

  dt.printHeader("Messaging string -> echo -> string");
  for (int i = 0; i < 12; ++i)
  {
    unsigned int                  numBytes = (unsigned int)pow(2.0f,(int)i);
    std::string                   request = std::string(numBytes, 'B');
    dt.start(gLoopCount, numBytes);
    for (int j = 0; j< gLoopCount; ++j)
    {
      AL::Messaging::CallDefinition def("echo", std::string(request));
      res = client.send(def);
      std::string result = res.value().as<std::string>();
    }
    dt.stop();
  }

  return 0;
}

int main(int argc, char **argv)
{

  if (argc > 1 && !strcmp(argv[1], "--client"))
  {
    boost::thread thd[gThreadCount];

    for (int i = 0; i < gThreadCount; ++i)
    {
      std::cout << "starting thread: " << i << std::endl;
      thd[i] = boost::thread(boost::bind(&main_client, i));
    }

    for (int i = 0; i < gThreadCount; ++i)
      thd[i].join();
  }
  else if (argc > 1 && !strcmp(argv[1], "--server"))
  {
    return main_server();
  }
  else
  {
    boost::thread             threadServer(&main_server);
    sleep(1);
    boost::thread             threadClient(boost::bind(&main_client, 0));
    threadClient.join();
    sleep(1);
  }
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Assembler tests for instructions in the "Extension Instruction" section
// of the SPIR-V spec.

#include "unit_spirv.h"

#include "test_fixture.h"
#include "gmock/gmock.h"
#include "spirv/1.0/GLSL.std.450.h"
#include "spirv/1.0/OpenCL.std.h"

namespace {

using spvtest::Concatenate;
using spvtest::MakeInstruction;
using spvtest::MakeVector;
using spvtest::TextToBinaryTest;
using ::testing::Combine;
using ::testing::Eq;
using ::testing::Values;
using ::testing::ValuesIn;

TEST_F(TextToBinaryTest, InvalidExtInstImportName) {
  EXPECT_THAT(CompileFailure("%1 = OpExtInstImport \"Haskell.std\""),
              Eq("Invalid extended instruction import 'Haskell.std'"));
}

TEST_F(TextToBinaryTest, InvalidImportId) {
  EXPECT_THAT(CompileFailure("%1 = OpTypeVoid\n"
                             "%2 = OpExtInst %1 %1"),
              Eq("Invalid extended instruction import Id 2"));
}

TEST_F(TextToBinaryTest, InvalidImportInstruction) {
  const std::string input = R"(%1 = OpTypeVoid
                               %2 = OpExtInstImport "OpenCL.std"
                               %3 = OpExtInst %1 %2 not_in_the_opencl)";
  EXPECT_THAT(CompileFailure(input),
              Eq("Invalid extended instruction name 'not_in_the_opencl'."));
}

TEST_F(TextToBinaryTest, MultiImport) {
  const std::string input = R"(%2 = OpExtInstImport "OpenCL.std"
                               %2 = OpExtInstImport "OpenCL.std")";
  EXPECT_THAT(CompileFailure(input),
              Eq("Import Id is being defined a second time"));
}

TEST_F(TextToBinaryTest, TooManyArguments) {
  const std::string input = R"(%opencl = OpExtInstImport "OpenCL.std"
                               %2 = OpExtInst %float %opencl cos %x %oops")";
  EXPECT_THAT(CompileFailure(input), Eq("Expected '=', found end of stream."));
}

TEST_F(TextToBinaryTest, ExtInstFromTwoDifferentImports) {
  const std::string input = R"(%1 = OpExtInstImport "OpenCL.std"
%2 = OpExtInstImport "GLSL.std.450"
%4 = OpExtInst %3 %1 native_sqrt %5
%7 = OpExtInst %6 %2 MatrixInverse %8
)";

  // Make sure it assembles correctly.
  EXPECT_THAT(
      CompiledInstructions(input),
      Eq(Concatenate({
          MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("OpenCL.std")),
          MakeInstruction(SpvOpExtInstImport, {2}, MakeVector("GLSL.std.450")),
          MakeInstruction(
              SpvOpExtInst,
              {3, 4, 1, uint32_t(OpenCLLIB::Entrypoints::Native_sqrt), 5}),
          MakeInstruction(SpvOpExtInst,
                          {6, 7, 2, uint32_t(GLSLstd450MatrixInverse), 8}),
      })));

  // Make sure it disassembles correctly.
  EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
}

// A test case for assembling into words in an instruction.
struct AssemblyCase {
  std::string input;
  std::vector<uint32_t> expected;
};

using ExtensionRoundTripTest = spvtest::TextToBinaryTestBase<
    ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;

TEST_P(ExtensionRoundTripTest, Samples) {
  const spv_target_env& env = std::get<0>(GetParam());
  const AssemblyCase& ac = std::get<1>(GetParam());

  // Check that it assembles correctly.
  EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));

  // Check round trip through the disassembler.
  EXPECT_THAT(EncodeAndDecodeSuccessfully(ac.input,
                                          SPV_BINARY_TO_TEXT_OPTION_NONE, env),
              Eq(ac.input));
}

// SPV_KHR_shader_ballot

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_shader_ballot, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability SubgroupBallotKHR\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilitySubgroupBallotKHR})},
                {"%2 = OpSubgroupBallotKHR %1 %3\n",
                 MakeInstruction(SpvOpSubgroupBallotKHR, {1, 2, 3})},
                {"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
                 MakeInstruction(SpvOpSubgroupFirstInvocationKHR, {1, 2, 3})},
                {"OpDecorate %1 BuiltIn SubgroupEqMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupEqMaskKHR})},
                {"OpDecorate %1 BuiltIn SubgroupGeMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupGeMaskKHR})},
                {"OpDecorate %1 BuiltIn SubgroupGtMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupGtMaskKHR})},
                {"OpDecorate %1 BuiltIn SubgroupLeMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupLeMaskKHR})},
                {"OpDecorate %1 BuiltIn SubgroupLtMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupLtMaskKHR})},
            })), );

// SPV_KHR_shader_draw_parameters

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_shader_draw_parameters, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(
        Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
               SPV_ENV_VULKAN_1_0),
        ValuesIn(std::vector<AssemblyCase>{
            {"OpCapability DrawParameters\n",
             MakeInstruction(SpvOpCapability, {SpvCapabilityDrawParameters})},
            {"OpDecorate %1 BuiltIn BaseVertex\n",
             MakeInstruction(SpvOpDecorate,
                             {1, SpvDecorationBuiltIn, SpvBuiltInBaseVertex})},
            {"OpDecorate %1 BuiltIn BaseInstance\n",
             MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                             SpvBuiltInBaseInstance})},
            {"OpDecorate %1 BuiltIn DrawIndex\n",
             MakeInstruction(SpvOpDecorate,
                             {1, SpvDecorationBuiltIn, SpvBuiltInDrawIndex})},
        })), );

// SPV_KHR_subgroup_vote

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_subgroup_vote, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(
        Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
               SPV_ENV_VULKAN_1_0),
        ValuesIn(std::vector<AssemblyCase>{
            {"OpCapability SubgroupVoteKHR\n",
             MakeInstruction(SpvOpCapability, {SpvCapabilitySubgroupVoteKHR})},
            {"%2 = OpSubgroupAnyKHR %1 %3\n",
             MakeInstruction(SpvOpSubgroupAnyKHR, {1, 2, 3})},
            {"%2 = OpSubgroupAllKHR %1 %3\n",
             MakeInstruction(SpvOpSubgroupAllKHR, {1, 2, 3})},
            {"%2 = OpSubgroupAllEqualKHR %1 %3\n",
             MakeInstruction(SpvOpSubgroupAllEqualKHR, {1, 2, 3})},
        })), );

// SPV_KHR_16bit_storage

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_16bit_storage, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability StorageUniformBufferBlock16\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityStorageUniformBufferBlock16})},
                {"OpCapability StorageUniform16\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityStorageUniform16})},
                {"OpCapability StoragePushConstant16\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityStoragePushConstant16})},
                {"OpCapability StorageInputOutput16\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityStorageInputOutput16})},
            })), );

// SPV_KHR_device_group

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_device_group, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability DeviceGroup\n",
                 MakeInstruction(SpvOpCapability, {SpvCapabilityDeviceGroup})},
                {"OpDecorate %1 BuiltIn DeviceIndex\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInDeviceIndex})},
            })), );

// SPV_KHR_multiview

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_multiview, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability MultiView\n",
                 MakeInstruction(SpvOpCapability, {SpvCapabilityMultiView})},
                {"OpDecorate %1 BuiltIn ViewIndex\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInViewIndex})},
            })), );

// SPV_AMD_gcn_shader

#define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_gcn_shader\"\n"
INSTANTIATE_TEST_CASE_P(
    SPV_AMD_gcn_shader, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceCoordAMD %4\n",
                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
                                              MakeVector("SPV_AMD_gcn_shader")),
                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4})})},
                {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceIndexAMD %4\n",
                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
                                              MakeVector("SPV_AMD_gcn_shader")),
                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4})})},
                {PREAMBLE "%3 = OpExtInst %2 %1 TimeAMD\n",
                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
                                              MakeVector("SPV_AMD_gcn_shader")),
                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 3})})},
            })), );
#undef PREAMBLE

}  // anonymous namespace
<commit_msg>Test asm,dis support for SPV_KHR_variable_pointers<commit_after>// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Assembler tests for instructions in the "Extension Instruction" section
// of the SPIR-V spec.

#include "unit_spirv.h"

#include "test_fixture.h"
#include "gmock/gmock.h"
#include "spirv/1.0/GLSL.std.450.h"
#include "spirv/1.0/OpenCL.std.h"

namespace {

using spvtest::Concatenate;
using spvtest::MakeInstruction;
using spvtest::MakeVector;
using spvtest::TextToBinaryTest;
using ::testing::Combine;
using ::testing::Eq;
using ::testing::Values;
using ::testing::ValuesIn;

TEST_F(TextToBinaryTest, InvalidExtInstImportName) {
  EXPECT_THAT(CompileFailure("%1 = OpExtInstImport \"Haskell.std\""),
              Eq("Invalid extended instruction import 'Haskell.std'"));
}

TEST_F(TextToBinaryTest, InvalidImportId) {
  EXPECT_THAT(CompileFailure("%1 = OpTypeVoid\n"
                             "%2 = OpExtInst %1 %1"),
              Eq("Invalid extended instruction import Id 2"));
}

TEST_F(TextToBinaryTest, InvalidImportInstruction) {
  const std::string input = R"(%1 = OpTypeVoid
                               %2 = OpExtInstImport "OpenCL.std"
                               %3 = OpExtInst %1 %2 not_in_the_opencl)";
  EXPECT_THAT(CompileFailure(input),
              Eq("Invalid extended instruction name 'not_in_the_opencl'."));
}

TEST_F(TextToBinaryTest, MultiImport) {
  const std::string input = R"(%2 = OpExtInstImport "OpenCL.std"
                               %2 = OpExtInstImport "OpenCL.std")";
  EXPECT_THAT(CompileFailure(input),
              Eq("Import Id is being defined a second time"));
}

TEST_F(TextToBinaryTest, TooManyArguments) {
  const std::string input = R"(%opencl = OpExtInstImport "OpenCL.std"
                               %2 = OpExtInst %float %opencl cos %x %oops")";
  EXPECT_THAT(CompileFailure(input), Eq("Expected '=', found end of stream."));
}

TEST_F(TextToBinaryTest, ExtInstFromTwoDifferentImports) {
  const std::string input = R"(%1 = OpExtInstImport "OpenCL.std"
%2 = OpExtInstImport "GLSL.std.450"
%4 = OpExtInst %3 %1 native_sqrt %5
%7 = OpExtInst %6 %2 MatrixInverse %8
)";

  // Make sure it assembles correctly.
  EXPECT_THAT(
      CompiledInstructions(input),
      Eq(Concatenate({
          MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("OpenCL.std")),
          MakeInstruction(SpvOpExtInstImport, {2}, MakeVector("GLSL.std.450")),
          MakeInstruction(
              SpvOpExtInst,
              {3, 4, 1, uint32_t(OpenCLLIB::Entrypoints::Native_sqrt), 5}),
          MakeInstruction(SpvOpExtInst,
                          {6, 7, 2, uint32_t(GLSLstd450MatrixInverse), 8}),
      })));

  // Make sure it disassembles correctly.
  EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
}

// A test case for assembling into words in an instruction.
struct AssemblyCase {
  std::string input;
  std::vector<uint32_t> expected;
};

using ExtensionRoundTripTest = spvtest::TextToBinaryTestBase<
    ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;

TEST_P(ExtensionRoundTripTest, Samples) {
  const spv_target_env& env = std::get<0>(GetParam());
  const AssemblyCase& ac = std::get<1>(GetParam());

  // Check that it assembles correctly.
  EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));

  // Check round trip through the disassembler.
  EXPECT_THAT(EncodeAndDecodeSuccessfully(ac.input,
                                          SPV_BINARY_TO_TEXT_OPTION_NONE, env),
              Eq(ac.input));
}

// SPV_KHR_shader_ballot

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_shader_ballot, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability SubgroupBallotKHR\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilitySubgroupBallotKHR})},
                {"%2 = OpSubgroupBallotKHR %1 %3\n",
                 MakeInstruction(SpvOpSubgroupBallotKHR, {1, 2, 3})},
                {"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
                 MakeInstruction(SpvOpSubgroupFirstInvocationKHR, {1, 2, 3})},
                {"OpDecorate %1 BuiltIn SubgroupEqMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupEqMaskKHR})},
                {"OpDecorate %1 BuiltIn SubgroupGeMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupGeMaskKHR})},
                {"OpDecorate %1 BuiltIn SubgroupGtMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupGtMaskKHR})},
                {"OpDecorate %1 BuiltIn SubgroupLeMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupLeMaskKHR})},
                {"OpDecorate %1 BuiltIn SubgroupLtMaskKHR\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInSubgroupLtMaskKHR})},
            })), );

// SPV_KHR_shader_draw_parameters

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_shader_draw_parameters, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(
        Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
               SPV_ENV_VULKAN_1_0),
        ValuesIn(std::vector<AssemblyCase>{
            {"OpCapability DrawParameters\n",
             MakeInstruction(SpvOpCapability, {SpvCapabilityDrawParameters})},
            {"OpDecorate %1 BuiltIn BaseVertex\n",
             MakeInstruction(SpvOpDecorate,
                             {1, SpvDecorationBuiltIn, SpvBuiltInBaseVertex})},
            {"OpDecorate %1 BuiltIn BaseInstance\n",
             MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                             SpvBuiltInBaseInstance})},
            {"OpDecorate %1 BuiltIn DrawIndex\n",
             MakeInstruction(SpvOpDecorate,
                             {1, SpvDecorationBuiltIn, SpvBuiltInDrawIndex})},
        })), );

// SPV_KHR_subgroup_vote

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_subgroup_vote, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(
        Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
               SPV_ENV_VULKAN_1_0),
        ValuesIn(std::vector<AssemblyCase>{
            {"OpCapability SubgroupVoteKHR\n",
             MakeInstruction(SpvOpCapability, {SpvCapabilitySubgroupVoteKHR})},
            {"%2 = OpSubgroupAnyKHR %1 %3\n",
             MakeInstruction(SpvOpSubgroupAnyKHR, {1, 2, 3})},
            {"%2 = OpSubgroupAllKHR %1 %3\n",
             MakeInstruction(SpvOpSubgroupAllKHR, {1, 2, 3})},
            {"%2 = OpSubgroupAllEqualKHR %1 %3\n",
             MakeInstruction(SpvOpSubgroupAllEqualKHR, {1, 2, 3})},
        })), );

// SPV_KHR_16bit_storage

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_16bit_storage, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability StorageUniformBufferBlock16\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityStorageUniformBufferBlock16})},
                {"OpCapability StorageUniform16\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityStorageUniform16})},
                {"OpCapability StoragePushConstant16\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityStoragePushConstant16})},
                {"OpCapability StorageInputOutput16\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityStorageInputOutput16})},
            })), );

// SPV_KHR_device_group

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_device_group, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability DeviceGroup\n",
                 MakeInstruction(SpvOpCapability, {SpvCapabilityDeviceGroup})},
                {"OpDecorate %1 BuiltIn DeviceIndex\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInDeviceIndex})},
            })), );

// SPV_KHR_multiview

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_multiview, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability MultiView\n",
                 MakeInstruction(SpvOpCapability, {SpvCapabilityMultiView})},
                {"OpDecorate %1 BuiltIn ViewIndex\n",
                 MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
                                                 SpvBuiltInViewIndex})},
            })), );

// SPV_AMD_gcn_shader

#define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_gcn_shader\"\n"
INSTANTIATE_TEST_CASE_P(
    SPV_AMD_gcn_shader, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceCoordAMD %4\n",
                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
                                              MakeVector("SPV_AMD_gcn_shader")),
                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4})})},
                {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceIndexAMD %4\n",
                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
                                              MakeVector("SPV_AMD_gcn_shader")),
                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4})})},
                {PREAMBLE "%3 = OpExtInst %2 %1 TimeAMD\n",
                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
                                              MakeVector("SPV_AMD_gcn_shader")),
                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 3})})},
            })), );
#undef PREAMBLE

// SPV_KHR_variable_pointers

INSTANTIATE_TEST_CASE_P(
    SPV_KHR_variable_pointers, ExtensionRoundTripTest,
    // We'll get coverage over operand tables by trying the universal
    // environments, and at least one specific environment.
    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
                   SPV_ENV_VULKAN_1_0),
            ValuesIn(std::vector<AssemblyCase>{
                {"OpCapability VariablePointers\n",
                 MakeInstruction(SpvOpCapability,
                                 {SpvCapabilityVariablePointers})},
                {"OpCapability VariablePointersUniformBufferBlock\n",
                 MakeInstruction(
                     SpvOpCapability,
                     {SpvCapabilityVariablePointersUniformBufferBlock})},
            })), );

}  // anonymous namespace
<|endoftext|>