<commit_before>#pragma once

namespace {
	namespace bitnodeNS {
		template <typename A>
		class bitnode final {
			template<typename B>
			using conref = const B &;

			using byte = unsigned char;
			using bit = bool;

			template <typename B>
			static inline void killPtr(B* &a) noexcept {
				if (a != nullptr) {
					delete a;
					a = nullptr;
				}
			}

		public:
			inline explicit bitnode(void) noexcept : zero{nullptr}, one{nullptr}, data{nullptr} {}

			template <typename... B>
			explicit bitnode(B... b) = delete;

			inline ~bitnode(void) noexcept {
				if (data != nullptr) {
					delete data;
				}
			}

			inline void dump(void) noexcept {
				bitnode<A>::killPtr<A>(data);
			}

			inline A* getData(void) const noexcept {
				return data;
			}

			inline void setData(conref<A> a) noexcept {
				this->dump();
				data = new A{a};
			}

			inline void setData(A* a) noexcept {
				this->dump();
				data = a;
			}

			inline void dumpZero(void) noexcept {
				bitnode<A>::killPtr<bitnode<A>>(zero);
			}

			inline bitnode<A>* getZero(void) const noexcept {
				return zero;
			}

			inline void setZero(bitnode<A>* a) noexcept {
				this->dumpZero();
				zero = a;
			}

			inline void dumpOne(void) noexcept {
				bitnode<A>::killPtr<bitnode<A>>(one);
			}

			inline bitnode<A>* getOne(void) const noexcept {
				return one;
			}

			inline void setOne(bitnode<A>* a) noexcept {
				this->dumpOne();
				one = a;
			}

			inline void dumpAll(void) noexcept {
				this->dump();
				this->dumpZero();
				this->dumpOne();
			}

			inline bool isEmpty(void) const noexcept {
				return data == nullptr;
			}

			inline bool isNotEmpty(void) const noexcept {
				return !this->isEmpty();
			}

			inline bool haveZero(void) const noexcept {
				return zero != nullptr;
			}

			inline bool noZero(void) const noexcept {
				return !this->haveZero();
			}

			inline bool haveOne(void) const noexcept {
				return one != nullptr;
			}

			inline bool noOne(void) const noexcept {
				return !this->haveOne();
			}

			inline bool isBarren(void) const noexcept {
				return this->noZero() && this->noOne();
			}

			inline bool isNotBarren(void) const noexcept {
				return !this->isBarren();
			}

		private:
			bitnode<A>* zero;
			bitnode<A>* one;

			A* data;
		};
	}
}
<commit_msg>no need for var name<commit_after>#pragma once

namespace {
	namespace bitnodeNS {
		template <typename A>
		class bitnode final {
			template<typename B>
			using conref = const B &;

			using byte = unsigned char;
			using bit = bool;

			template <typename B>
			static inline void killPtr(B* &a) noexcept {
				if (a != nullptr) {
					delete a;
					a = nullptr;
				}
			}

		public:
			inline explicit bitnode(void) noexcept : zero{nullptr}, one{nullptr}, data{nullptr} {}

			template <typename... B>
			explicit bitnode(B...) = delete;

			inline ~bitnode(void) noexcept {
				if (data != nullptr) {
					delete data;
				}
			}

			inline void dump(void) noexcept {
				bitnode<A>::killPtr<A>(data);
			}

			inline A* getData(void) const noexcept {
				return data;
			}

			inline void setData(conref<A> a) noexcept {
				this->dump();
				data = new A{a};
			}

			inline void setData(A* a) noexcept {
				this->dump();
				data = a;
			}

			inline void dumpZero(void) noexcept {
				bitnode<A>::killPtr<bitnode<A>>(zero);
			}

			inline bitnode<A>* getZero(void) const noexcept {
				return zero;
			}

			inline void setZero(bitnode<A>* a) noexcept {
				this->dumpZero();
				zero = a;
			}

			inline void dumpOne(void) noexcept {
				bitnode<A>::killPtr<bitnode<A>>(one);
			}

			inline bitnode<A>* getOne(void) const noexcept {
				return one;
			}

			inline void setOne(bitnode<A>* a) noexcept {
				this->dumpOne();
				one = a;
			}

			inline void dumpAll(void) noexcept {
				this->dump();
				this->dumpZero();
				this->dumpOne();
			}

			inline bool isEmpty(void) const noexcept {
				return data == nullptr;
			}

			inline bool isNotEmpty(void) const noexcept {
				return !this->isEmpty();
			}

			inline bool haveZero(void) const noexcept {
				return zero != nullptr;
			}

			inline bool noZero(void) const noexcept {
				return !this->haveZero();
			}

			inline bool haveOne(void) const noexcept {
				return one != nullptr;
			}

			inline bool noOne(void) const noexcept {
				return !this->haveOne();
			}

			inline bool isBarren(void) const noexcept {
				return this->noZero() && this->noOne();
			}

			inline bool isNotBarren(void) const noexcept {
				return !this->isBarren();
			}

		private:
			bitnode<A>* zero;
			bitnode<A>* one;

			A* data;
		};
	}
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <iostream>
#include <cmath>
#include <tuple>
#include <mpl/mpl.hpp>

typedef std::tuple<double, double> double_2;

template<std::size_t dim, typename T, typename A>
void update_overlap(const mpl::cart_communicator &C,
		    mpl::distributed_grid<dim, T, A> &G, int tag=0) {
  mpl::shift_ranks ranks;
  mpl::irequest_pool r;
  for (std::size_t i=0; i<dim; ++i) {
    // send to left
    ranks=C.shift(i, -1);
    r.push(C.isend(G.data(), G.left_border_layout(i), ranks.dest, tag));
    r.push(C.irecv(G.data(), G.right_mirror_layout(i), ranks.source, tag));
    // send to right
    ranks=C.shift(i, +1);
    r.push(C.isend(G.data(), G.right_border_layout(i), ranks.dest, tag));
    r.push(C.irecv(G.data(), G.left_mirror_layout(i), ranks.source, tag));
  }
  r.waitall();
}

template<std::size_t dim, typename T, typename A>
void scatter(const mpl::cart_communicator &C, int root,
	     const mpl::local_grid<dim, T, A> &L,
	     mpl::distributed_grid<dim, T, A> &G) {
  mpl::irequest r(C.irecv(G.data(), G.interior_layout(), root));
  if (C.rank()==root)
    for (int i=0; i<C.size(); ++i)
      C.send(L.data(), L.sub_layout(i), i);
  r.wait();
}

template<std::size_t dim, typename T, typename A>
void scatter(const mpl::cart_communicator &C, int root,
	     mpl::distributed_grid<dim, T, A> &G) {
  C.recv(G.data(), G.interior_layout(), root);
}

template<std::size_t dim, typename T, typename A>
void gather(const mpl::cart_communicator &C, int root,
	    const mpl::distributed_grid<dim, T, A> &G,
	    mpl::local_grid<dim, T, A> &L) {
  mpl::irequest r(C.isend(G.data(), G.interior_layout(), root));
  if (C.rank()==root)
    for (int i=0; i<C.size(); ++i)
      C.recv(L.data(), L.sub_layout(i), i);
  r.wait();
}

template<std::size_t dim, typename T, typename A>
void gather(const mpl::cart_communicator &C, int root,
	    const mpl::distributed_grid<dim, T, A> &G) {
  C.send(G.data(), G.interior_layout(), root);
}

int main() {
  // world communicator
  const mpl::communicator & comm_world(mpl::environment::comm_world());
  // construct a two-dimensional Cartesian communicator with no periodic boundary conditions
  mpl::cart_communicator::sizes sizes( {{0, false}, {0, false}} );
  mpl::cart_communicator comm_c(comm_world,
				mpl::dims_create(comm_world.size(), sizes));
  // total number of inner grid points
  int Nx=768, Ny=512;
  // grid points with extremal indices (-1, Nx or Ny) hold fixed boundary data
  // grid lengths and grid spacings
  double l_x=1.5, l_y=1, dx=l_x/(Nx+1), dy=l_y/(Ny+1);
  // distributed grid that holds each processor's subgrid plus one row and
  // one collumn of neighboring data
  mpl::distributed_grid<2, double> u_d(comm_c, {{Nx, 1}, {Ny, 1}});
  // rank 0 inializes with some random data
  if (comm_c.rank()==0) {
    // local grid to store the whole set of inner grid points
    mpl::local_grid<2, double> u(comm_c, {Nx, Ny});
    for (auto j=u.begin(1), j_end=u.end(1); j<j_end; ++j)
      for (auto i=u.begin(0), i_end=u.end(0); i<i_end; ++i)
	u(i, j)=std::rand()/static_cast<double>(RAND_MAX);
    // scater data to each processors subgrid
    scatter(comm_c, 0, u, u_d);
  } else
    scatter(comm_c, 0, u_d);
  // initiallize boundary data, loop with obegin and oend over all
  // data including the overlap
  for (auto j : { u_d.obegin(1), u_d.oend(1)-1 } )
    for (auto i=u_d.obegin(0), i_end=u_d.oend(0); i<i_end; ++i) {
      if (u_d.gindex(0, i)<0 or u_d.gindex(1, j)<0)
	u_d(i, j)=1;
      if (u_d.gindex(0, i)>=Nx or u_d.gindex(1, j)>=Ny)
  	u_d(i, j)=0;
    }
  for (auto i : { u_d.obegin(0), u_d.oend(0)-1 } )
    for (auto j=u_d.obegin(1), j_end=u_d.oend(1); j<j_end; ++j) {
      if (u_d.gindex(0, i)<0 or u_d.gindex(1, j)<0)
	u_d(i, j)=1;
      if (u_d.gindex(0, i)>=Nx or u_d.gindex(1, j)>=Ny)
  	u_d(i, j)=0;
    }
  double w=1.875, // the over-relaxation parameter
    dx2=dx*dx, dy2=dy*dy;
   // loop until converged
  bool converged=false;
  while (not converged) {
    // exchange overlap data
    update_overlap(comm_c, u_d);
    // apply one successive over-relaxation step
    double Delta_u=0, sum_u=0;
    for (auto j=u_d.begin(1), j_end=u_d.end(1); j<j_end; ++j)
      for (auto i=u_d.begin(0), i_end=u_d.end(0); i<i_end; ++i) {
	double du=-w*u_d(i, j)+
	  w*(dy2*(u_d(i-1, j)+u_d(i+1, j)) + dx2*(u_d(i, j-1)+u_d(i, j+1)))/(2*(dx2+dy2));
  	u_d(i, j)+=du;
	Delta_u+=std::abs(du);
	sum_u+=std::abs(u_d(i, j));
      }
    // determine global sum of Delta_u and sum_u and distribute to all processors
    double_2 Delta_sum_u{ Delta_u, sum_u };  // pack into pair
    // use a lambda function for global reduction
    comm_c.allreduce([](double_2 a, double_2 b) {
	  // reduction adds component-by-component
	  return double_2{ std::get<0>(a)+std::get<0>(b), std::get<1>(a)+std::get<1>(b) };
	}, Delta_sum_u);
    std::tie(Delta_u, sum_u)=Delta_sum_u;  // unpack from pair
    converged=Delta_u/sum_u<1e-6;  // check for convergence
  }
  if (comm_c.rank()==0) {
    // local grid to store the whole set of inner grid points
    mpl::local_grid<2, double> u(comm_c, {Nx, Ny});
    // gather data and print result
    gather(comm_c, 0, u_d, u);
    for (auto j=u.begin(1), j_end=u.end(1); j<j_end; ++j) {
      for (auto i=u.begin(0), i_end=u.end(0); i<i_end; ++i)
	std::cout << u(i, j) << '\t';
      std::cout << '\n';
    }
  } else
    gather(comm_c, 0, u_d);
  return EXIT_SUCCESS;
}
<commit_msg>gatherv/scatterv for collective operations<commit_after>#include <cstdlib>
#include <iostream>
#include <cmath>
#include <tuple>
#include <mpl/mpl.hpp>

typedef std::tuple<double, double> double_2;

template<std::size_t dim, typename T, typename A>
void update_overlap(const mpl::cart_communicator &C,
		    mpl::distributed_grid<dim, T, A> &G, int tag=0) {
  mpl::shift_ranks ranks;
  mpl::irequest_pool r;
  for (std::size_t i=0; i<dim; ++i) {
    // send to left
    ranks=C.shift(i, -1);
    r.push(C.isend(G.data(), G.left_border_layout(i), ranks.dest, tag));
    r.push(C.irecv(G.data(), G.right_mirror_layout(i), ranks.source, tag));
    // send to right
    ranks=C.shift(i, +1);
    r.push(C.isend(G.data(), G.right_border_layout(i), ranks.dest, tag));
    r.push(C.irecv(G.data(), G.left_mirror_layout(i), ranks.source, tag));
  }
  r.waitall();
}

template<std::size_t dim, typename T, typename A>
void scatter(const mpl::cart_communicator &C, int root,
	     const mpl::local_grid<dim, T, A> &L,
	     mpl::distributed_grid<dim, T, A> &G) {
  C.scatterv(root,
	     L.data(), L.sub_layouts(), mpl::displacements(C.size()),
	     G.data(), G.interior_layout());
}

template<std::size_t dim, typename T, typename A>
void scatter(const mpl::cart_communicator &C, int root,
	     mpl::distributed_grid<dim, T, A> &G) {
  C.scatterv(root,
	     G.data(), G.interior_layout());
}

template<std::size_t dim, typename T, typename A>
void gather(const mpl::cart_communicator &C, int root,
	    const mpl::distributed_grid<dim, T, A> &G,
	    mpl::local_grid<dim, T, A> &L) {
  C.gatherv(root,
	    G.data(), G.interior_layout(),
	    L.data(), L.sub_layouts(), mpl::displacements(C.size()));
}

template<std::size_t dim, typename T, typename A>
void gather(const mpl::cart_communicator &C, int root,
	    const mpl::distributed_grid<dim, T, A> &G) {
  C.gatherv(root,
	    G.data(), G.interior_layout());
}

int main() {
  // world communicator
  const mpl::communicator & comm_world(mpl::environment::comm_world());
  // construct a two-dimensional Cartesian communicator with no periodic boundary conditions
  mpl::cart_communicator::sizes sizes( {{0, false}, {0, false}} );
  mpl::cart_communicator comm_c(comm_world,
				mpl::dims_create(comm_world.size(), sizes));
  // total number of inner grid points
  int Nx=768, Ny=512;
  // grid points with extremal indices (-1, Nx or Ny) hold fixed boundary data
  // grid lengths and grid spacings
  double l_x=1.5, l_y=1, dx=l_x/(Nx+1), dy=l_y/(Ny+1);
  // distributed grid that holds each processor's subgrid plus one row and
  // one collumn of neighboring data
  mpl::distributed_grid<2, double> u_d(comm_c, {{Nx, 1}, {Ny, 1}});
  // rank 0 inializes with some random data
  if (comm_c.rank()==0) {
    // local grid to store the whole set of inner grid points
    mpl::local_grid<2, double> u(comm_c, {Nx, Ny});
    for (auto j=u.begin(1), j_end=u.end(1); j<j_end; ++j)
      for (auto i=u.begin(0), i_end=u.end(0); i<i_end; ++i)
	u(i, j)=std::rand()/static_cast<double>(RAND_MAX);
    // scater data to each processors subgrid
    scatter(comm_c, 0, u, u_d);
  } else
    scatter(comm_c, 0, u_d);
  // initiallize boundary data, loop with obegin and oend over all
  // data including the overlap
  for (auto j : { u_d1.obegin(1), u_d1.oend(1)-1 } )
    for (auto i=u_d1.obegin(0), i_end=u_d1.oend(0); i<i_end; ++i) {
      if (u_d1.gindex(0, i)<0 or u_d1.gindex(1, j)<0)
	u_d1(i, j)=u_d2(i, j)=1;  // left boundary condition
      if (u_d1.gindex(0, i)>=Nx or u_d1.gindex(1, j)>=Ny)
  	u_d1(i, j)=u_d2(i, j)=0;  // right boundary condition
    }
  for (auto i : { u_d1.obegin(0), u_d1.oend(0)-1 } )
    for (auto j=u_d1.obegin(1), j_end=u_d1.oend(1); j<j_end; ++j) {
      if (u_d1.gindex(0, i)<0 or u_d1.gindex(1, j)<0)
	u_d1(i, j)=u_d2(i, j)=1;  // lower boundary condition
      if (u_d1.gindex(0, i)>=Nx or u_d1.gindex(1, j)>=Ny)
  	u_d1(i, j)=u_d2(i, j)=0;  // upper boundary condition
    }
  double w=1.875, // the over-relaxation parameter
    dx2=dx*dx, dy2=dy*dy;
  // loop until converged
  bool converged=false;
  while (not converged) {
    // exchange overlap data
    update_overlap(comm_c, u_d);
    // apply one successive over-relaxation step
    double Delta_u=0, sum_u=0;
    for (auto j=u_d.begin(1), j_end=u_d.end(1); j<j_end; ++j)
      for (auto i=u_d.begin(0), i_end=u_d.end(0); i<i_end; ++i) {
	double du=-w*u_d(i, j)+
	  w*(dy2*(u_d(i-1, j)+u_d(i+1, j)) + dx2*(u_d(i, j-1)+u_d(i, j+1)))/(2*(dx2+dy2));
  	u_d(i, j)+=du;
	Delta_u+=std::abs(du);
	sum_u+=std::abs(u_d(i, j));
      }
    // determine global sum of Delta_u and sum_u and distribute to all processors
    double_2 Delta_sum_u{ Delta_u, sum_u };  // pack into pair
    // use a lambda function for global reduction
    comm_c.allreduce([](double_2 a, double_2 b) {
	  // reduction adds component-by-component
	  return double_2{ std::get<0>(a)+std::get<0>(b), std::get<1>(a)+std::get<1>(b) };
	}, Delta_sum_u);
    std::tie(Delta_u, sum_u)=Delta_sum_u;  // unpack from pair
    converged=Delta_u/sum_u<1e-6;  // check for convergence
  }
  if (comm_c.rank()==0) {
    // local grid to store the whole set of inner grid points
    mpl::local_grid<2, double> u(comm_c, {Nx, Ny});
    // gather data and print result
    gather(comm_c, 0, u_d, u);
    for (auto j=u.begin(1), j_end=u.end(1); j<j_end; ++j) {
      for (auto i=u.begin(0), i_end=u.end(0); i<i_end; ++i)
	std::cout << u(i, j) << '\t';
      std::cout << '\n';
    }
  } else
    gather(comm_c, 0, u_d);
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015-2016 gRPC authors.
 *
 * 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.
 *
 */

#include <fstream>
#include <iostream>
#include <memory>
#include <set>

#include <grpcpp/impl/codegen/config_protobuf.h>

#include <gflags/gflags.h>
#include <grpc/support/log.h>

#include "test/cpp/qps/benchmark_config.h"
#include "test/cpp/qps/driver.h"
#include "test/cpp/qps/parse_json.h"
#include "test/cpp/qps/report.h"
#include "test/cpp/qps/server.h"
#include "test/cpp/util/test_config.h"
#include "test/cpp/util/test_credentials_provider.h"

DEFINE_string(scenarios_file, "",
              "JSON file containing an array of Scenario objects");
DEFINE_string(scenarios_json, "",
              "JSON string containing an array of Scenario objects");
DEFINE_bool(quit, false, "Quit the workers");
DEFINE_string(search_param, "",
              "The parameter, whose value is to be searched for to achieve "
              "targeted cpu load. For now, we have 'offered_load'. Later, "
              "'num_channels', 'num_outstanding_requests', etc. shall be "
              "added.");
DEFINE_double(
    initial_search_value, 0.0,
    "initial parameter value to start the search with (i.e. lower bound)");
DEFINE_double(targeted_cpu_load, 70.0,
              "Targeted cpu load (unit: %, range [0,100])");
DEFINE_double(stride, 1,
              "Defines each stride of the search. The larger the stride is, "
              "the coarser the result will be, but will also be faster.");
DEFINE_double(error_tolerance, 0.01,
              "Defines threshold for stopping the search. When current search "
              "range is narrower than the error_tolerance computed range, we "
              "stop the search.");

DEFINE_string(qps_server_target_override, "",
              "Override QPS server target to configure in client configs."
              "Only applicable if there is a single benchmark server.");

DEFINE_string(json_file_out, "", "File to write the JSON output to.");

DEFINE_string(credential_type, grpc::testing::kInsecureCredentialsType,
              "Credential type for communication with workers");
DEFINE_string(
    per_worker_credential_types, "",
    "A map of QPS worker addresses to credential types. When creating a "
    "channel to a QPS worker's driver port, the qps_json_driver first checks "
    "if the 'name:port' string is in the map, and it uses the corresponding "
    "credential type if so. If the QPS worker's 'name:port' string is not "
    "in the map, then the driver -> worker channel will be created with "
    "the credentials specified in --credential_type. The value of this flag "
    "is a semicolon-separated list of map entries, where each map entry is "
    "a comma-separated pair.");
DEFINE_bool(run_inproc, false, "Perform an in-process transport test");
DEFINE_int32(
    median_latency_collection_interval_millis, 0,
    "Specifies the period between gathering latency medians in "
    "milliseconds. The medians will be logged out on the client at the "
    "end of the benchmark run. If 0, this periodic collection is disabled.");

namespace grpc {
namespace testing {

static std::map<std::string, std::string>
ConstructPerWorkerCredentialTypesMap() {
  // Parse a list of the form: "addr1,cred_type1;addr2,cred_type2;..." into
  // a map.
  std::string remaining = FLAGS_per_worker_credential_types;
  std::map<std::string, std::string> out;
  while (remaining.size() > 0) {
    size_t next_semicolon = remaining.find(';');
    std::string next_entry = remaining.substr(0, next_semicolon);
    if (next_semicolon == std::string::npos) {
      remaining = "";
    } else {
      remaining = remaining.substr(next_semicolon + 1, std::string::npos);
    }
    size_t comma = next_entry.find(',');
    if (comma == std::string::npos) {
      gpr_log(GPR_ERROR,
              "Expectd --per_worker_credential_types to be a list "
              "of the form: 'addr1,cred_type1;addr2,cred_type2;...' "
              "into.");
      abort();
    }
    std::string addr = next_entry.substr(0, comma);
    std::string cred_type = next_entry.substr(comma + 1, std::string::npos);
    if (out.find(addr) != out.end()) {
      gpr_log(GPR_ERROR,
              "Found duplicate addr in per_worker_credential_types.");
      abort();
    }
    out[addr] = cred_type;
  }
  return out;
}

static std::unique_ptr<ScenarioResult> RunAndReport(
    const Scenario& scenario,
    const std::map<std::string, std::string>& per_worker_credential_types,
    bool* success) {
  std::cerr << "RUNNING SCENARIO: " << scenario.name() << "\n";
  auto result =
      RunScenario(scenario.client_config(), scenario.num_clients(),
                  scenario.server_config(), scenario.num_servers(),
                  scenario.warmup_seconds(), scenario.benchmark_seconds(),
                  !FLAGS_run_inproc ? scenario.spawn_local_worker_count() : -2,
                  FLAGS_qps_server_target_override, FLAGS_credential_type,
                  per_worker_credential_types, FLAGS_run_inproc,
                  FLAGS_median_latency_collection_interval_millis);

  // Amend the result with scenario config. Eventually we should adjust
  // RunScenario contract so we don't need to touch the result here.
  result->mutable_scenario()->CopyFrom(scenario);

  GetReporter()->ReportQPS(*result);
  GetReporter()->ReportQPSPerCore(*result);
  GetReporter()->ReportLatency(*result);
  GetReporter()->ReportTimes(*result);
  GetReporter()->ReportCpuUsage(*result);
  GetReporter()->ReportPollCount(*result);
  GetReporter()->ReportQueriesPerCpuSec(*result);

  for (int i = 0; *success && i < result->client_success_size(); i++) {
    *success = result->client_success(i);
  }
  for (int i = 0; *success && i < result->server_success_size(); i++) {
    *success = result->server_success(i);
  }

  if (FLAGS_json_file_out != "") {
    std::ofstream json_outfile;
    json_outfile.open(FLAGS_json_file_out);
    json_outfile << "{\"qps\": " << result->summary().qps() << "}\n";
    json_outfile.close();
  }

  return result;
}

static double GetCpuLoad(
    Scenario* scenario, double offered_load,
    const std::map<std::string, std::string>& per_worker_credential_types,
    bool* success) {
  scenario->mutable_client_config()
      ->mutable_load_params()
      ->mutable_poisson()
      ->set_offered_load(offered_load);
  auto result = RunAndReport(*scenario, per_worker_credential_types, success);
  return result->summary().server_cpu_usage();
}

static double BinarySearch(
    Scenario* scenario, double targeted_cpu_load, double low, double high,
    const std::map<std::string, std::string>& per_worker_credential_types,
    bool* success) {
  while (low <= high * (1 - FLAGS_error_tolerance)) {
    double mid = low + (high - low) / 2;
    double current_cpu_load =
        GetCpuLoad(scenario, mid, per_worker_credential_types, success);
    gpr_log(GPR_DEBUG, "Binary Search: current_offered_load %.0f", mid);
    if (!*success) {
      gpr_log(GPR_ERROR, "Client/Server Failure");
      break;
    }
    if (targeted_cpu_load <= current_cpu_load) {
      high = mid - FLAGS_stride;
    } else {
      low = mid + FLAGS_stride;
    }
  }

  return low;
}

static double SearchOfferedLoad(
    double initial_offered_load, double targeted_cpu_load, Scenario* scenario,
    const std::map<std::string, std::string>& per_worker_credential_types,
    bool* success) {
  std::cerr << "RUNNING SCENARIO: " << scenario->name() << "\n";
  double current_offered_load = initial_offered_load;
  double current_cpu_load = GetCpuLoad(scenario, current_offered_load,
                                       per_worker_credential_types, success);
  if (current_cpu_load > targeted_cpu_load) {
    gpr_log(GPR_ERROR, "Initial offered load too high");
    return -1;
  }

  while (*success && (current_cpu_load < targeted_cpu_load)) {
    current_offered_load *= 2;
    current_cpu_load = GetCpuLoad(scenario, current_offered_load,
                                  per_worker_credential_types, success);
    gpr_log(GPR_DEBUG, "Binary Search: current_offered_load  %.0f",
            current_offered_load);
  }

  double targeted_offered_load =
      BinarySearch(scenario, targeted_cpu_load, current_offered_load / 2,
                   current_offered_load, per_worker_credential_types, success);

  return targeted_offered_load;
}

static bool QpsDriver() {
  grpc::string json;

  bool scfile = (FLAGS_scenarios_file != "");
  bool scjson = (FLAGS_scenarios_json != "");
  if ((!scfile && !scjson && !FLAGS_quit) ||
      (scfile && (scjson || FLAGS_quit)) || (scjson && FLAGS_quit)) {
    gpr_log(GPR_ERROR,
            "Exactly one of --scenarios_file, --scenarios_json, "
            "or --quit must be set");
    abort();
  }

  auto per_worker_credential_types = ConstructPerWorkerCredentialTypesMap();
  if (scfile) {
    // Read the json data from disk
    FILE* json_file = fopen(FLAGS_scenarios_file.c_str(), "r");
    GPR_ASSERT(json_file != nullptr);
    fseek(json_file, 0, SEEK_END);
    long len = ftell(json_file);
    char* data = new char[len];
    fseek(json_file, 0, SEEK_SET);
    GPR_ASSERT(len == (long)fread(data, 1, len, json_file));
    fclose(json_file);
    json = grpc::string(data, data + len);
    delete[] data;
  } else if (scjson) {
    json = FLAGS_scenarios_json.c_str();
  } else if (FLAGS_quit) {
    return RunQuit(FLAGS_credential_type, per_worker_credential_types);
  }

  // Parse into an array of scenarios
  Scenarios scenarios;
  ParseJson(json.c_str(), "grpc.testing.Scenarios", &scenarios);
  bool success = true;

  // Make sure that there is at least some valid scenario here
  GPR_ASSERT(scenarios.scenarios_size() > 0);

  for (int i = 0; i < scenarios.scenarios_size(); i++) {
    if (FLAGS_search_param == "") {
      const Scenario& scenario = scenarios.scenarios(i);
      RunAndReport(scenario, per_worker_credential_types, &success);
    } else {
      if (FLAGS_search_param == "offered_load") {
        Scenario* scenario = scenarios.mutable_scenarios(i);
        double targeted_offered_load = SearchOfferedLoad(
            FLAGS_initial_search_value, FLAGS_targeted_cpu_load, scenario,
            per_worker_credential_types, &success);
        gpr_log(GPR_INFO, "targeted_offered_load %f", targeted_offered_load);
        GetCpuLoad(scenario, targeted_offered_load, per_worker_credential_types,
                   &success);
      } else {
        gpr_log(GPR_ERROR, "Unimplemented search param");
      }
    }
  }
  return success;
}

}  // namespace testing
}  // namespace grpc

int main(int argc, char** argv) {
  grpc::testing::InitTest(&argc, &argv, true);

  bool ok = grpc::testing::QpsDriver();

  return ok ? 0 : 1;
}
<commit_msg>fix clang tidy<commit_after>/*
 *
 * Copyright 2015-2016 gRPC authors.
 *
 * 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.
 *
 */

#include <fstream>
#include <iostream>
#include <memory>
#include <set>

#include <grpcpp/impl/codegen/config_protobuf.h>

#include <gflags/gflags.h>
#include <grpc/support/log.h>

#include "test/cpp/qps/benchmark_config.h"
#include "test/cpp/qps/driver.h"
#include "test/cpp/qps/parse_json.h"
#include "test/cpp/qps/report.h"
#include "test/cpp/qps/server.h"
#include "test/cpp/util/test_config.h"
#include "test/cpp/util/test_credentials_provider.h"

DEFINE_string(scenarios_file, "",
              "JSON file containing an array of Scenario objects");
DEFINE_string(scenarios_json, "",
              "JSON string containing an array of Scenario objects");
DEFINE_bool(quit, false, "Quit the workers");
DEFINE_string(search_param, "",
              "The parameter, whose value is to be searched for to achieve "
              "targeted cpu load. For now, we have 'offered_load'. Later, "
              "'num_channels', 'num_outstanding_requests', etc. shall be "
              "added.");
DEFINE_double(
    initial_search_value, 0.0,
    "initial parameter value to start the search with (i.e. lower bound)");
DEFINE_double(targeted_cpu_load, 70.0,
              "Targeted cpu load (unit: %, range [0,100])");
DEFINE_double(stride, 1,
              "Defines each stride of the search. The larger the stride is, "
              "the coarser the result will be, but will also be faster.");
DEFINE_double(error_tolerance, 0.01,
              "Defines threshold for stopping the search. When current search "
              "range is narrower than the error_tolerance computed range, we "
              "stop the search.");

DEFINE_string(qps_server_target_override, "",
              "Override QPS server target to configure in client configs."
              "Only applicable if there is a single benchmark server.");

DEFINE_string(json_file_out, "", "File to write the JSON output to.");

DEFINE_string(credential_type, grpc::testing::kInsecureCredentialsType,
              "Credential type for communication with workers");
DEFINE_string(
    per_worker_credential_types, "",
    "A map of QPS worker addresses to credential types. When creating a "
    "channel to a QPS worker's driver port, the qps_json_driver first checks "
    "if the 'name:port' string is in the map, and it uses the corresponding "
    "credential type if so. If the QPS worker's 'name:port' string is not "
    "in the map, then the driver -> worker channel will be created with "
    "the credentials specified in --credential_type. The value of this flag "
    "is a semicolon-separated list of map entries, where each map entry is "
    "a comma-separated pair.");
DEFINE_bool(run_inproc, false, "Perform an in-process transport test");
DEFINE_int32(
    median_latency_collection_interval_millis, 0,
    "Specifies the period between gathering latency medians in "
    "milliseconds. The medians will be logged out on the client at the "
    "end of the benchmark run. If 0, this periodic collection is disabled.");

namespace grpc {
namespace testing {

static std::map<std::string, std::string>
ConstructPerWorkerCredentialTypesMap() {
  // Parse a list of the form: "addr1,cred_type1;addr2,cred_type2;..." into
  // a map.
  std::string remaining = FLAGS_per_worker_credential_types;
  std::map<std::string, std::string> out;
  while (!remaining.empty()) {
    size_t next_semicolon = remaining.find(';');
    std::string next_entry = remaining.substr(0, next_semicolon);
    if (next_semicolon == std::string::npos) {
      remaining = "";
    } else {
      remaining = remaining.substr(next_semicolon + 1, std::string::npos);
    }
    size_t comma = next_entry.find(',');
    if (comma == std::string::npos) {
      gpr_log(GPR_ERROR,
              "Expectd --per_worker_credential_types to be a list "
              "of the form: 'addr1,cred_type1;addr2,cred_type2;...' "
              "into.");
      abort();
    }
    std::string addr = next_entry.substr(0, comma);
    std::string cred_type = next_entry.substr(comma + 1, std::string::npos);
    if (out.find(addr) != out.end()) {
      gpr_log(GPR_ERROR,
              "Found duplicate addr in per_worker_credential_types.");
      abort();
    }
    out[addr] = cred_type;
  }
  return out;
}

static std::unique_ptr<ScenarioResult> RunAndReport(
    const Scenario& scenario,
    const std::map<std::string, std::string>& per_worker_credential_types,
    bool* success) {
  std::cerr << "RUNNING SCENARIO: " << scenario.name() << "\n";
  auto result =
      RunScenario(scenario.client_config(), scenario.num_clients(),
                  scenario.server_config(), scenario.num_servers(),
                  scenario.warmup_seconds(), scenario.benchmark_seconds(),
                  !FLAGS_run_inproc ? scenario.spawn_local_worker_count() : -2,
                  FLAGS_qps_server_target_override, FLAGS_credential_type,
                  per_worker_credential_types, FLAGS_run_inproc,
                  FLAGS_median_latency_collection_interval_millis);

  // Amend the result with scenario config. Eventually we should adjust
  // RunScenario contract so we don't need to touch the result here.
  result->mutable_scenario()->CopyFrom(scenario);

  GetReporter()->ReportQPS(*result);
  GetReporter()->ReportQPSPerCore(*result);
  GetReporter()->ReportLatency(*result);
  GetReporter()->ReportTimes(*result);
  GetReporter()->ReportCpuUsage(*result);
  GetReporter()->ReportPollCount(*result);
  GetReporter()->ReportQueriesPerCpuSec(*result);

  for (int i = 0; *success && i < result->client_success_size(); i++) {
    *success = result->client_success(i);
  }
  for (int i = 0; *success && i < result->server_success_size(); i++) {
    *success = result->server_success(i);
  }

  if (FLAGS_json_file_out != "") {
    std::ofstream json_outfile;
    json_outfile.open(FLAGS_json_file_out);
    json_outfile << "{\"qps\": " << result->summary().qps() << "}\n";
    json_outfile.close();
  }

  return result;
}

static double GetCpuLoad(
    Scenario* scenario, double offered_load,
    const std::map<std::string, std::string>& per_worker_credential_types,
    bool* success) {
  scenario->mutable_client_config()
      ->mutable_load_params()
      ->mutable_poisson()
      ->set_offered_load(offered_load);
  auto result = RunAndReport(*scenario, per_worker_credential_types, success);
  return result->summary().server_cpu_usage();
}

static double BinarySearch(
    Scenario* scenario, double targeted_cpu_load, double low, double high,
    const std::map<std::string, std::string>& per_worker_credential_types,
    bool* success) {
  while (low <= high * (1 - FLAGS_error_tolerance)) {
    double mid = low + (high - low) / 2;
    double current_cpu_load =
        GetCpuLoad(scenario, mid, per_worker_credential_types, success);
    gpr_log(GPR_DEBUG, "Binary Search: current_offered_load %.0f", mid);
    if (!*success) {
      gpr_log(GPR_ERROR, "Client/Server Failure");
      break;
    }
    if (targeted_cpu_load <= current_cpu_load) {
      high = mid - FLAGS_stride;
    } else {
      low = mid + FLAGS_stride;
    }
  }

  return low;
}

static double SearchOfferedLoad(
    double initial_offered_load, double targeted_cpu_load, Scenario* scenario,
    const std::map<std::string, std::string>& per_worker_credential_types,
    bool* success) {
  std::cerr << "RUNNING SCENARIO: " << scenario->name() << "\n";
  double current_offered_load = initial_offered_load;
  double current_cpu_load = GetCpuLoad(scenario, current_offered_load,
                                       per_worker_credential_types, success);
  if (current_cpu_load > targeted_cpu_load) {
    gpr_log(GPR_ERROR, "Initial offered load too high");
    return -1;
  }

  while (*success && (current_cpu_load < targeted_cpu_load)) {
    current_offered_load *= 2;
    current_cpu_load = GetCpuLoad(scenario, current_offered_load,
                                  per_worker_credential_types, success);
    gpr_log(GPR_DEBUG, "Binary Search: current_offered_load  %.0f",
            current_offered_load);
  }

  double targeted_offered_load =
      BinarySearch(scenario, targeted_cpu_load, current_offered_load / 2,
                   current_offered_load, per_worker_credential_types, success);

  return targeted_offered_load;
}

static bool QpsDriver() {
  grpc::string json;

  bool scfile = (FLAGS_scenarios_file != "");
  bool scjson = (FLAGS_scenarios_json != "");
  if ((!scfile && !scjson && !FLAGS_quit) ||
      (scfile && (scjson || FLAGS_quit)) || (scjson && FLAGS_quit)) {
    gpr_log(GPR_ERROR,
            "Exactly one of --scenarios_file, --scenarios_json, "
            "or --quit must be set");
    abort();
  }

  auto per_worker_credential_types = ConstructPerWorkerCredentialTypesMap();
  if (scfile) {
    // Read the json data from disk
    FILE* json_file = fopen(FLAGS_scenarios_file.c_str(), "r");
    GPR_ASSERT(json_file != nullptr);
    fseek(json_file, 0, SEEK_END);
    long len = ftell(json_file);
    char* data = new char[len];
    fseek(json_file, 0, SEEK_SET);
    GPR_ASSERT(len == (long)fread(data, 1, len, json_file));
    fclose(json_file);
    json = grpc::string(data, data + len);
    delete[] data;
  } else if (scjson) {
    json = FLAGS_scenarios_json.c_str();
  } else if (FLAGS_quit) {
    return RunQuit(FLAGS_credential_type, per_worker_credential_types);
  }

  // Parse into an array of scenarios
  Scenarios scenarios;
  ParseJson(json.c_str(), "grpc.testing.Scenarios", &scenarios);
  bool success = true;

  // Make sure that there is at least some valid scenario here
  GPR_ASSERT(scenarios.scenarios_size() > 0);

  for (int i = 0; i < scenarios.scenarios_size(); i++) {
    if (FLAGS_search_param == "") {
      const Scenario& scenario = scenarios.scenarios(i);
      RunAndReport(scenario, per_worker_credential_types, &success);
    } else {
      if (FLAGS_search_param == "offered_load") {
        Scenario* scenario = scenarios.mutable_scenarios(i);
        double targeted_offered_load = SearchOfferedLoad(
            FLAGS_initial_search_value, FLAGS_targeted_cpu_load, scenario,
            per_worker_credential_types, &success);
        gpr_log(GPR_INFO, "targeted_offered_load %f", targeted_offered_load);
        GetCpuLoad(scenario, targeted_offered_load, per_worker_credential_types,
                   &success);
      } else {
        gpr_log(GPR_ERROR, "Unimplemented search param");
      }
    }
  }
  return success;
}

}  // namespace testing
}  // namespace grpc

int main(int argc, char** argv) {
  grpc::testing::InitTest(&argc, &argv, true);

  bool ok = grpc::testing::QpsDriver();

  return ok ? 0 : 1;
}
<|endoftext|>


<commit_before>#pragma once
#include <bts/blockchain/types.hpp>

namespace bts { namespace blockchain {

static std::unordered_map<uint32_t, bts::blockchain::block_id_type> CHECKPOINT_BLOCKS
{
    {       1, bts::blockchain::block_id_type( "8523e28fde6eed4eb749a84e28c9c7b56870c9cc" ) },
    {  172718, bts::blockchain::block_id_type( "e452dd44902bc86110923285da03ac12e8cfbe6f" ) },
    {  173585, bts::blockchain::block_id_type( "1d1695bc8ebd3ebae0168007afb2912269adbef1" ) },
    {  192000, bts::blockchain::block_id_type( "80910335f384f420930351deac69debd007f74c0" ) },
    {  236000, bts::blockchain::block_id_type( "049b5a56e3431c5020817d84ef56fbf22c1ac634" ) }
};

// Initialized in load_checkpoints()
static uint32_t LAST_CHECKPOINT_BLOCK_NUM = 0;

} } // bts::blockchain
<commit_msg>Update checkpoints<commit_after>#pragma once
#include <bts/blockchain/types.hpp>

namespace bts { namespace blockchain {

static std::unordered_map<uint32_t, bts::blockchain::block_id_type> CHECKPOINT_BLOCKS
{
    {       1, bts::blockchain::block_id_type( "8523e28fde6eed4eb749a84e28c9c7b56870c9cc" ) },
    {   25001, bts::blockchain::block_id_type( "f5bbb4c5728d809e3d0877354964ea24e9961904" ) },
    {  120001, bts::blockchain::block_id_type( "1557fee97884c893aaebba9a1fed803e7fd005d9" ) },
    {  129601, bts::blockchain::block_id_type( "18bcec3430d35538470d7fddc2a51a28cb71fcde" ) },
    {  172718, bts::blockchain::block_id_type( "e452dd44902bc86110923285da03ac12e8cfbe6f" ) },
    {  173585, bts::blockchain::block_id_type( "1d1695bc8ebd3ebae0168007afb2912269adbef1" ) },
    {  187001, bts::blockchain::block_id_type( "72d06a6ba3e79c02327d8048852f9e51b6c8ea71" ) },
    {  237501, bts::blockchain::block_id_type( "42d7bb317f51082f7faffee3f7c79bf59f47acac" ) },
    {  253000, bts::blockchain::block_id_type( "39ac82bf60cb8455c9d648da18616668d4f0d5ca" ) }
};

// Initialized in load_checkpoints()
static uint32_t LAST_CHECKPOINT_BLOCK_NUM = 0;

} } // bts::blockchain
<|endoftext|>


<commit_before>#pragma once
#include <bts/blockchain/types.hpp>

namespace bts { namespace blockchain {

static std::map<uint32_t, bts::blockchain::block_id_type> CHECKPOINT_BLOCKS
{
    {       1, bts::blockchain::block_id_type( "8523e28fde6eed4eb749a84e28c9c7b56870c9cc" ) },
    {   25001, bts::blockchain::block_id_type( "f5bbb4c5728d809e3d0877354964ea24e9961904" ) },
    {  120001, bts::blockchain::block_id_type( "1557fee97884c893aaebba9a1fed803e7fd005d9" ) },
    {  129601, bts::blockchain::block_id_type( "18bcec3430d35538470d7fddc2a51a28cb71fcde" ) },
    {  172718, bts::blockchain::block_id_type( "e452dd44902bc86110923285da03ac12e8cfbe6f" ) },
    {  173585, bts::blockchain::block_id_type( "1d1695bc8ebd3ebae0168007afb2912269adbef1" ) },
    {  187001, bts::blockchain::block_id_type( "72d06a6ba3e79c02327d8048852f9e51b6c8ea71" ) },
    {  237501, bts::blockchain::block_id_type( "42d7bb317f51082f7faffee3f7c79bf59f47acac" ) },
    {  650001, bts::blockchain::block_id_type( "f5d74cc87e68adf44af8c7b5528d3716e70f7102" ) },
    {  799900, bts::blockchain::block_id_type( "cab248195b20f9b8f93488fe666a7ead86e91156" ) }
};

// Initialized in load_checkpoints()
static uint32_t LAST_CHECKPOINT_BLOCK_NUM = 0;

} } // bts::blockchain
<commit_msg>Update checkpoint<commit_after>#pragma once
#include <bts/blockchain/types.hpp>

namespace bts { namespace blockchain {

static std::map<uint32_t, bts::blockchain::block_id_type> CHECKPOINT_BLOCKS
{
    {       1, bts::blockchain::block_id_type( "8523e28fde6eed4eb749a84e28c9c7b56870c9cc" ) },
    {   25001, bts::blockchain::block_id_type( "f5bbb4c5728d809e3d0877354964ea24e9961904" ) },
    {  120001, bts::blockchain::block_id_type( "1557fee97884c893aaebba9a1fed803e7fd005d9" ) },
    {  129601, bts::blockchain::block_id_type( "18bcec3430d35538470d7fddc2a51a28cb71fcde" ) },
    {  172718, bts::blockchain::block_id_type( "e452dd44902bc86110923285da03ac12e8cfbe6f" ) },
    {  173585, bts::blockchain::block_id_type( "1d1695bc8ebd3ebae0168007afb2912269adbef1" ) },
    {  187001, bts::blockchain::block_id_type( "72d06a6ba3e79c02327d8048852f9e51b6c8ea71" ) },
    {  237501, bts::blockchain::block_id_type( "42d7bb317f51082f7faffee3f7c79bf59f47acac" ) },
    {  650001, bts::blockchain::block_id_type( "f5d74cc87e68adf44af8c7b5528d3716e70f7102" ) },
    { 1275700, bts::blockchain::block_id_type( "d9dec580e5797b607065615c289dd866f5c647f6" ) }
};

// Initialized in load_checkpoints()
static uint32_t LAST_CHECKPOINT_BLOCK_NUM = 0;

} } // bts::blockchain
<|endoftext|>


<commit_before>#include <memory>
#include <type_traits>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/pointer.hpp>
#include <entt/meta/resolve.hpp>

template<typename Type>
struct wrapped_shared_ptr {
    wrapped_shared_ptr(Type init): ptr{new Type {init}} {}

    Type & deref() const { return *ptr; }

private:
    std::shared_ptr<Type> ptr;
};

template<typename Type>
struct adl_wrapped_shared_ptr: wrapped_shared_ptr<Type> {};

template<typename Type>
struct spec_wrapped_shared_ptr: wrapped_shared_ptr<Type> {};

template<typename Type>
struct entt::is_meta_pointer_like<adl_wrapped_shared_ptr<Type>>: std::true_type {};

template<typename Type>
struct entt::is_meta_pointer_like<spec_wrapped_shared_ptr<Type>>: std::true_type {};

template<typename Type>
Type & dereference_meta_pointer_like(const adl_wrapped_shared_ptr<Type> &ptr) {
    return ptr.deref();
}

template<typename Type>
struct entt::adl_meta_pointer_like<spec_wrapped_shared_ptr<Type>> {
    static decltype(auto) dereference(const spec_wrapped_shared_ptr<Type> &ptr) {
        return ptr.deref();
    }
};

void test_function() {}

struct not_copyable_t {
    not_copyable_t() = default;
    not_copyable_t(const not_copyable_t &) = delete;
    not_copyable_t(not_copyable_t &&) = default;
    not_copyable_t & operator=(const not_copyable_t &) = delete;
    not_copyable_t & operator=(not_copyable_t &&) = default;
};

TEST(MetaPointerLike, DereferenceOperatorInvalidType) {
    int value = 0;
    entt::meta_any any{value};

    ASSERT_FALSE(any.type().is_pointer());
    ASSERT_FALSE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<int>());

    auto deref = *any;

    ASSERT_FALSE(deref);
}

TEST(MetaPointerLike, DereferenceOperatorConstType) {
    const int value = 42;
    entt::meta_any any{&value};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<const int *>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    ASSERT_EQ(deref.try_cast<int>(), nullptr);
    ASSERT_EQ(deref.try_cast<const int>(), &value);
    ASSERT_DEATH(deref.cast<int &>() = 0, ".*");
    ASSERT_EQ(deref.cast<const int &>(), 42);
}

TEST(MetaPointerLike, DereferenceOperatorConstAny) {
    auto test = [](const entt::meta_any any) {
        auto deref = *any;

        ASSERT_TRUE(deref);
        ASSERT_FALSE(deref.type().is_pointer());
        ASSERT_FALSE(deref.type().is_pointer_like());
        ASSERT_EQ(deref.type(), entt::resolve<int>());

        ASSERT_EQ(deref.try_cast<int>(), nullptr);
        ASSERT_NE(deref.try_cast<const int>(), nullptr);
        ASSERT_DEATH(deref.cast<int &>() = 0, ".*");
        ASSERT_EQ(deref.cast<const int &>(), 42);
    };

    int value = 42;

    test(&value);
    test(&std::as_const(value));
}

TEST(MetaPointerLike, DereferenceOperatorRawPointer) {
    int value = 0;
    entt::meta_any any{&value};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<int *>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    deref.cast<int &>() = 42;

    ASSERT_EQ(*any.cast<int *>(), 42);
    ASSERT_EQ(value, 42);
}

TEST(MetaPointerLike, DereferenceOperatorSmartPointer) {
    auto value = std::make_shared<int>(0);
    entt::meta_any any{value};

    ASSERT_FALSE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<std::shared_ptr<int>>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    deref.cast<int &>() = 42;

    ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 42);
    ASSERT_EQ(*value, 42);
}

TEST(MetaPointerLike, PointerToConstMoveOnlyType) {
    const not_copyable_t instance;
    entt::meta_any any{&instance};
    auto deref = *any;

    ASSERT_TRUE(any);
    ASSERT_TRUE(deref);

    ASSERT_DEATH(deref.cast<not_copyable_t &>() = {}, ".*");
    ASSERT_EQ(deref.try_cast<not_copyable_t>(), nullptr);
    ASSERT_NE(deref.try_cast<const not_copyable_t>(), nullptr);
}

TEST(MetaPointerLike, AsRef) {
    int value = 0;
    int * ptr = &value;
    entt::meta_any any{std::ref(ptr)};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<int *>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    deref.cast<int &>() = 42;

    ASSERT_EQ(*any.cast<int *>(), 42);
    ASSERT_EQ(value, 42);
}

TEST(MetaPointerLike, AsConstRef) {
    int value = 42;
    int * ptr = &value;
    entt::meta_any any{std::cref(ptr)};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<int *>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    deref.cast<int &>() = 42;

    ASSERT_EQ(*any.cast<int *>(), 42);
    ASSERT_EQ(value, 42);
}

TEST(MetaPointerLike, DereferenceOverload) {
    auto test = [](entt::meta_any any) {
        ASSERT_FALSE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());

        auto deref = *any;

        ASSERT_TRUE(deref);
        ASSERT_FALSE(deref.type().is_pointer());
        ASSERT_FALSE(deref.type().is_pointer_like());
        ASSERT_EQ(deref.type(), entt::resolve<int>());

        ASSERT_EQ(deref.cast<int &>(), 42);
        ASSERT_EQ(deref.cast<const int &>(), 42);
    };

    test(adl_wrapped_shared_ptr<int>{42});
    test(spec_wrapped_shared_ptr<int>{42});
}

TEST(MetaPointerLike, DereferencePointerToConstOverload) {
    auto test = [](entt::meta_any any) {
        ASSERT_FALSE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());

        auto deref = *any;

        ASSERT_TRUE(deref);
        ASSERT_FALSE(deref.type().is_pointer());
        ASSERT_FALSE(deref.type().is_pointer_like());
        ASSERT_EQ(deref.type(), entt::resolve<int>());

        ASSERT_DEATH(deref.cast<int &>() = 42, ".*");
        ASSERT_EQ(deref.cast<const int &>(), 42);
    };

    test(adl_wrapped_shared_ptr<const int>{42});
    test(spec_wrapped_shared_ptr<const int>{42});
}

TEST(MetaPointerLike, DereferencePointerToVoid) {
    auto test = [](entt::meta_any any) {
        ASSERT_TRUE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());
        ASSERT_EQ(any.type().remove_pointer(), entt::resolve<void>());

        auto deref = *any;

        ASSERT_FALSE(deref);
    };

    test(static_cast<void *>(nullptr));
    test(static_cast<const void *>(nullptr));
}

TEST(MetaPointerLike, DereferenceSmartPointerToVoid) {
    auto test = [](entt::meta_any any) {
        ASSERT_TRUE(any.type().is_class());
        ASSERT_FALSE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());

        auto deref = *any;

        ASSERT_FALSE(deref);
    };

    test(std::shared_ptr<void>{});
    test(std::unique_ptr<void, void(*)(void *)>{nullptr, nullptr});
}

TEST(MetaPointerLike, DereferencePointerToFunction) {
    entt::meta_any any{&test_function};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type().remove_pointer(), entt::resolve<void()>());

    auto deref = *any;

    ASSERT_TRUE(deref.type().is_pointer());
    ASSERT_TRUE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type().remove_pointer(), entt::resolve<void()>());
}
<commit_msg>meta: more tests for meta pointers (code coverage)<commit_after>#include <memory>
#include <type_traits>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/pointer.hpp>
#include <entt/meta/resolve.hpp>

template<typename Type>
struct wrapped_shared_ptr {
    wrapped_shared_ptr(Type init): ptr{new Type {init}} {}

    Type & deref() const { return *ptr; }

private:
    std::shared_ptr<Type> ptr;
};

template<typename Type>
struct adl_wrapped_shared_ptr: wrapped_shared_ptr<Type> {};

template<typename Type>
struct spec_wrapped_shared_ptr: wrapped_shared_ptr<Type> {};

template<typename Type>
struct entt::is_meta_pointer_like<adl_wrapped_shared_ptr<Type>>: std::true_type {};

template<typename Type>
struct entt::is_meta_pointer_like<spec_wrapped_shared_ptr<Type>>: std::true_type {};

template<typename Type>
Type & dereference_meta_pointer_like(const adl_wrapped_shared_ptr<Type> &ptr) {
    return ptr.deref();
}

template<typename Type>
struct entt::adl_meta_pointer_like<spec_wrapped_shared_ptr<Type>> {
    static decltype(auto) dereference(const spec_wrapped_shared_ptr<Type> &ptr) {
        return ptr.deref();
    }
};

int test_function() { return 42; }

struct not_copyable_t {
    not_copyable_t() = default;
    not_copyable_t(const not_copyable_t &) = delete;
    not_copyable_t(not_copyable_t &&) = default;
    not_copyable_t & operator=(const not_copyable_t &) = delete;
    not_copyable_t & operator=(not_copyable_t &&) = default;
};

TEST(MetaPointerLike, DereferenceOperatorInvalidType) {
    int value = 0;
    entt::meta_any any{value};

    ASSERT_FALSE(any.type().is_pointer());
    ASSERT_FALSE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<int>());

    auto deref = *any;

    ASSERT_FALSE(deref);
}

TEST(MetaPointerLike, DereferenceOperatorConstType) {
    const int value = 42;
    entt::meta_any any{&value};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<const int *>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    ASSERT_EQ(deref.try_cast<int>(), nullptr);
    ASSERT_EQ(deref.try_cast<const int>(), &value);
    ASSERT_DEATH(deref.cast<int &>() = 0, ".*");
    ASSERT_EQ(deref.cast<const int &>(), 42);
}

TEST(MetaPointerLike, DereferenceOperatorConstAny) {
    auto test = [](const entt::meta_any any) {
        auto deref = *any;

        ASSERT_TRUE(deref);
        ASSERT_FALSE(deref.type().is_pointer());
        ASSERT_FALSE(deref.type().is_pointer_like());
        ASSERT_EQ(deref.type(), entt::resolve<int>());

        ASSERT_EQ(deref.try_cast<int>(), nullptr);
        ASSERT_NE(deref.try_cast<const int>(), nullptr);
        ASSERT_DEATH(deref.cast<int &>() = 0, ".*");
        ASSERT_EQ(deref.cast<const int &>(), 42);
    };

    int value = 42;

    test(&value);
    test(&std::as_const(value));
}

TEST(MetaPointerLike, DereferenceOperatorRawPointer) {
    int value = 0;
    entt::meta_any any{&value};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<int *>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    deref.cast<int &>() = 42;

    ASSERT_EQ(*any.cast<int *>(), 42);
    ASSERT_EQ(value, 42);
}

TEST(MetaPointerLike, DereferenceOperatorSmartPointer) {
    auto value = std::make_shared<int>(0);
    entt::meta_any any{value};

    ASSERT_FALSE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<std::shared_ptr<int>>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    deref.cast<int &>() = 42;

    ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 42);
    ASSERT_EQ(*value, 42);
}

TEST(MetaPointerLike, PointerToConstMoveOnlyType) {
    const not_copyable_t instance;
    entt::meta_any any{&instance};
    auto deref = *any;

    ASSERT_TRUE(any);
    ASSERT_TRUE(deref);

    ASSERT_DEATH(deref.cast<not_copyable_t &>() = {}, ".*");
    ASSERT_EQ(deref.try_cast<not_copyable_t>(), nullptr);
    ASSERT_NE(deref.try_cast<const not_copyable_t>(), nullptr);
}

TEST(MetaPointerLike, AsRef) {
    int value = 0;
    int * ptr = &value;
    entt::meta_any any{std::ref(ptr)};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<int *>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    deref.cast<int &>() = 42;

    ASSERT_EQ(*any.cast<int *>(), 42);
    ASSERT_EQ(value, 42);
}

TEST(MetaPointerLike, AsConstRef) {
    int value = 42;
    int * ptr = &value;
    entt::meta_any any{std::cref(ptr)};

    ASSERT_TRUE(any.type().is_pointer());
    ASSERT_TRUE(any.type().is_pointer_like());
    ASSERT_EQ(any.type(), entt::resolve<int *>());

    auto deref = *any;

    ASSERT_TRUE(deref);
    ASSERT_FALSE(deref.type().is_pointer());
    ASSERT_FALSE(deref.type().is_pointer_like());
    ASSERT_EQ(deref.type(), entt::resolve<int>());

    deref.cast<int &>() = 42;

    ASSERT_EQ(*any.cast<int *>(), 42);
    ASSERT_EQ(value, 42);
}

TEST(MetaPointerLike, DereferenceOverload) {
    auto test = [](entt::meta_any any) {
        ASSERT_FALSE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());

        auto deref = *any;

        ASSERT_TRUE(deref);
        ASSERT_FALSE(deref.type().is_pointer());
        ASSERT_FALSE(deref.type().is_pointer_like());
        ASSERT_EQ(deref.type(), entt::resolve<int>());

        ASSERT_EQ(deref.cast<int &>(), 42);
        ASSERT_EQ(deref.cast<const int &>(), 42);
    };

    test(adl_wrapped_shared_ptr<int>{42});
    test(spec_wrapped_shared_ptr<int>{42});
}

TEST(MetaPointerLike, DereferencePointerToConstOverload) {
    auto test = [](entt::meta_any any) {
        ASSERT_FALSE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());

        auto deref = *any;

        ASSERT_TRUE(deref);
        ASSERT_FALSE(deref.type().is_pointer());
        ASSERT_FALSE(deref.type().is_pointer_like());
        ASSERT_EQ(deref.type(), entt::resolve<int>());

        ASSERT_DEATH(deref.cast<int &>() = 42, ".*");
        ASSERT_EQ(deref.cast<const int &>(), 42);
    };

    test(adl_wrapped_shared_ptr<const int>{42});
    test(spec_wrapped_shared_ptr<const int>{42});
}

TEST(MetaPointerLike, DereferencePointerToVoid) {
    auto test = [](entt::meta_any any) {
        ASSERT_TRUE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());
        ASSERT_EQ(any.type().remove_pointer(), entt::resolve<void>());

        auto deref = *any;

        ASSERT_FALSE(deref);
    };

    test(static_cast<void *>(nullptr));
    test(static_cast<const void *>(nullptr));
}

TEST(MetaPointerLike, DereferenceSmartPointerToVoid) {
    auto test = [](entt::meta_any any) {
        ASSERT_TRUE(any.type().is_class());
        ASSERT_FALSE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());

        auto deref = *any;

        ASSERT_FALSE(deref);
    };

    test(std::shared_ptr<void>{});
    test(std::unique_ptr<void, void(*)(void *)>{nullptr, nullptr});
}

TEST(MetaPointerLike, DereferencePointerToFunction) {
    auto test = [](entt::meta_any any) {
        ASSERT_TRUE(any.type().is_pointer());
        ASSERT_TRUE(any.type().is_pointer_like());
        ASSERT_EQ(any.type().remove_pointer(), entt::resolve<int()>());
        ASSERT_NE(any.try_cast<int(*)()>(), nullptr);
        ASSERT_EQ(any.cast<int(*)()>()(), 42);
    };

    test(entt::meta_any{&test_function});
    test(*entt::meta_any{&test_function});
    test(**entt::meta_any{&test_function});
}
<|endoftext|>


<commit_before>/** @file

    A brief file description

    @section license License

    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you 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.
*/

// This is total BS, because our libraries are riddled with cross dependencies.
// TODO: Clean up the dependency mess, and get rid of this.

#include "libts.h"
#include "LogObject.h"

#if defined(solaris)
#include <sys/types.h>
#include <unistd.h>
#endif

#include "P_Net.h"

int fds_limit = 8000;
UDPNetProcessor &udpNet;

ClassAllocator<UDPPacketInternal> udpPacketAllocator("udpPacketAllocator");

void
UDPConnection::Release()
{
  ink_release_assert(false);
}

void
UDPNetProcessor::FreeBandwidth(Continuation * udpConn)
{
  ink_release_assert(false);
}

NetProcessor& netProcessor;

Action *
UnixNetProcessor::connect_re_internal(Continuation * cont, unsigned int ip, int port,  NetVCOptions * opt)
{
  ink_release_assert(false);
  return NULL;
}

#include "InkAPIInternal.h"
ConfigUpdateCbTable *global_config_cbs = NULL;

void
ConfigUpdateCbTable::invoke(const char *name)
{
  ink_release_assert(false);
}

const char *
event_int_to_string(int event, int blen, char *buffer)
{
  ink_release_assert(false);
  return NULL;
}

struct Machine;
Machine *
this_machine()
{
  ink_release_assert(false);
  return NULL;
}

#include "LogConfig.h"
void
LogConfig::setup_collation(LogConfig * prev_config)
{
  ink_release_assert(false);
}

void
LogConfig::create_pre_defined_objects_with_filter(const PreDefinedFormatInfoList & pre_def_info_list, size_t num_filters,
                                                  LogFilter ** filter, const char *filt_name, bool force_extension)
{
  ink_release_assert(false);
}

int
LogHost::write(LogBuffer * lb, size_t * to_disk, size_t * to_net, size_t * to_pipe)
{
  ink_release_assert(false);
  return 0;
}

NetVCOptions const Connection::DEFAULT_OPTIONS;
NetProcessor::AcceptOptions const NetProcessor::DEFAULT_ACCEPT_OPTIONS;

NetProcessor::AcceptOptions&
NetProcessor::AcceptOptions::reset()
{
  ink_release_assert(false);
  return *this;
}
<commit_msg>TS-655 More fixes for Solaris<commit_after>/** @file

    A brief file description

    @section license License

    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you 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.
*/

// This is total BS, because our libraries are riddled with cross dependencies.
// TODO: Clean up the dependency mess, and get rid of this.

#include "libts.h"
#include "LogObject.h"

#if defined(solaris)
#include <sys/types.h>
#include <unistd.h>
#endif

#include "P_Net.h"

int fds_limit = 8000;
UDPNetProcessor &udpNet;

ClassAllocator<UDPPacketInternal> udpPacketAllocator("udpPacketAllocator");

void
UDPConnection::Release()
{
  ink_release_assert(false);
}

void
UDPNetProcessor::FreeBandwidth(Continuation * udpConn)
{
  ink_release_assert(false);
}

NetProcessor& netProcessor;

Action *
UnixNetProcessor::connect_re_internal(Continuation * cont, unsigned int ip, int port,  NetVCOptions * opt)
{
  ink_release_assert(false);
  return NULL;
}

#include "InkAPIInternal.h"
ConfigUpdateCbTable *global_config_cbs = NULL;

void
ConfigUpdateCbTable::invoke(const char *name)
{
  ink_release_assert(false);
}

const char *
event_int_to_string(int event, int blen, char *buffer)
{
  ink_release_assert(false);
  return NULL;
}

struct Machine;
Machine *
this_machine()
{
  ink_release_assert(false);
  return NULL;
}

#include "LogConfig.h"
void
LogConfig::setup_collation(LogConfig * prev_config)
{
  ink_release_assert(false);
}

void
LogConfig::create_pre_defined_objects_with_filter(const PreDefinedFormatInfoList & pre_def_info_list, size_t num_filters,
                                                  LogFilter ** filter, const char *filt_name, bool force_extension)
{
  ink_release_assert(false);
}

int
LogHost::write(LogBuffer * lb, size_t * to_disk, size_t * to_net, size_t * to_pipe)
{
  ink_release_assert(false);
  return 0;
}

NetVCOptions const Connection::DEFAULT_OPTIONS;
NetProcessor::AcceptOptions const NetProcessor::DEFAULT_ACCEPT_OPTIONS;

NetProcessor::AcceptOptions&
NetProcessor::AcceptOptions::reset()
{
  ink_release_assert(false);
  return *this;
}

int
net_accept(NetAccept * na, void *ep, bool blockable)
{
  ink_release_assert(false);
  return 0;
}
<|endoftext|>


<commit_before>//===- SparcV9PreSelection.cpp - Specialize LLVM code for SparcV9 ---------===//
//
//                     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 file defines the PreSelection pass which specializes LLVM code for
// the SparcV9 instruction selector, while remaining in legal portable LLVM
// form and preserving type information and type safety. This is meant to enable
// dataflow optimizations on SparcV9-specific operations such as accesses to
// constants, globals, and array indexing.
//
//===----------------------------------------------------------------------===//

#include "SparcV9Internals.h"
#include "SparcV9BurgISel.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/InstVisitor.h"
#include "llvm/Support/GetElementPtrTypeIterator.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include <algorithm>
using namespace llvm;

namespace {

  //===--------------------------------------------------------------------===//
  // PreSelection Pass - Specialize LLVM code for the SparcV9 instr. selector.
  //
  class PreSelection : public FunctionPass, public InstVisitor<PreSelection> {
    const TargetInstrInfo &instrInfo;

  public:
    PreSelection(const TargetMachine &T)
      : instrInfo(*T.getInstrInfo()) {}

    // runOnFunction - apply this pass to each Function
    bool runOnFunction(Function &F) {
      visit(F);
      return true;
    }
    const char *getPassName() const { return "SparcV9 Instr. Pre-selection"; }

    // These methods do the actual work of specializing code
    void visitInstruction(Instruction &I);   // common work for every instr.
    void visitGetElementPtrInst(GetElementPtrInst &I);
    void visitCallInst(CallInst &I);
    void visitPHINode(PHINode &PN);

    void visitBasicBlock(BasicBlock &BB) {
      if (isa<UnreachableInst>(BB.getTerminator())) {
        BB.getInstList().pop_back();
        const Type *RetTy = BB.getParent()->getReturnType();
        Value *RetVal = RetTy == Type::VoidTy ? 0 : UndefValue::get(RetTy);
        new ReturnInst(RetVal, &BB);
      }
    }

    // Helper functions for visiting operands of every instruction
    //
    // visitOperands() works on every operand in [firstOp, lastOp-1].
    // If lastOp==0, lastOp defaults to #operands or #incoming Phi values.
    //
    // visitOneOperand() does all the work for one operand.
    //
    void visitOperands(Instruction &I, int firstOp=0);
    void visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                         Instruction& insertBefore);
  };

#if 0
  // Register the pass...
  RegisterPass<PreSelection> X("preselect",
                               "Specialize LLVM code for a target machine"
                               createPreselectionPass);
#endif

}  // end anonymous namespace

//------------------------------------------------------------------------------
// Helper functions used by methods of class PreSelection
//------------------------------------------------------------------------------

// getGlobalAddr(): Put address of a global into a v. register.
static GetElementPtrInst* getGlobalAddr(Value* ptr, Instruction& insertBefore) {

  return (isa<GlobalVariable>(ptr))
    ? new GetElementPtrInst(ptr,
                    std::vector<Value*>(1, ConstantSInt::get(Type::LongTy, 0U)),
                    "addrOfGlobal:" + ptr->getName(), &insertBefore)
    : NULL;
}

// Wrapper on Constant::classof to use in find_if
inline static bool nonConstant(const Use& U) {
  return ! isa<Constant>(U);
}

static Instruction* DecomposeConstantExpr(ConstantExpr* CE,
                                          Instruction& insertBefore)
{
  Value *getArg1, *getArg2;

  switch(CE->getOpcode())
    {
    case Instruction::Cast:
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      return new CastInst(getArg1, CE->getType(), "constantCast",&insertBefore);

    case Instruction::GetElementPtr:
      assert(std::find_if(CE->op_begin()+1, CE->op_end(),
                          nonConstant) == CE->op_end()
             && "All indices in ConstantExpr getelementptr must be constant!");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore))
        getArg1 = gep;
      return new GetElementPtrInst(getArg1,
                          std::vector<Value*>(CE->op_begin()+1, CE->op_end()),
                          "constantGEP:" + getArg1->getName(), &insertBefore);

    case Instruction::Select: {
      Value *C, *S1, *S2;
      C = CE->getOperand (0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (C))
        C = DecomposeConstantExpr (CEarg, insertBefore);
      S1 = CE->getOperand (1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (S1))
        S1 = DecomposeConstantExpr (CEarg, insertBefore);
      S2 = CE->getOperand (2);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (S2))
        S2 = DecomposeConstantExpr (CEarg, insertBefore);
      return new SelectInst (C, S1, S2, "constantSelect", &insertBefore);
    }

    default:                            // must be a binary operator
      assert(CE->getOpcode() >= Instruction::BinaryOpsBegin &&
             CE->getOpcode() <  Instruction::BinaryOpsEnd &&
             "Unhandled opcode in ConstantExpr");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      getArg2 = CE->getOperand(1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
        getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
      return BinaryOperator::create((Instruction::BinaryOps) CE->getOpcode(),
                                    getArg1, getArg2,
                                    "constantBinaryOp", &insertBefore);
    }
}

static inline bool ConstantTypeMustBeLoaded(const Type* CVT) {
  assert(CVT->isPrimitiveType() || isa<PointerType>(CVT));
  return !(CVT->isIntegral() || isa<PointerType>(CVT));
}

//------------------------------------------------------------------------------
// Instruction visitor methods to perform instruction-specific operations
//------------------------------------------------------------------------------
inline void
PreSelection::visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                              Instruction& insertBefore)
{
  assert(&insertBefore != NULL && "Must have instruction to insert before.");

  if (GetElementPtrInst* gep = getGlobalAddr(Op, insertBefore)) {
    I.setOperand(opNum, gep);           // replace global operand
    return;                             // nothing more to do for this op.
  }

  Constant* CV  = dyn_cast<Constant>(Op);
  if (CV == NULL)
    return;

  if (ConstantExpr* CE = dyn_cast<ConstantExpr>(CV)) {
    // load-time constant: factor it out so we optimize as best we can
    Instruction* computeConst = DecomposeConstantExpr(CE, insertBefore);
    I.setOperand(opNum, computeConst); // replace expr operand with result
  } else if (ConstantTypeMustBeLoaded(CV->getType())) {
    // load address of constant into a register, then load the constant
    // this is now done during instruction selection
    // the constant will live in the MachineConstantPool later on
  } else if (ConstantMayNotFitInImmedField(CV, &I)) {
    // put the constant into a virtual register using a cast
    CastInst* castI = new CastInst(CV, CV->getType(), "copyConst",
                                   &insertBefore);
    I.setOperand(opNum, castI);      // replace operand with copy in v.reg.
  }
}

/// visitOperands - transform individual operands of all instructions:
/// -- Load "large" int constants into a virtual register.  What is large
///    depends on the type of instruction and on the target architecture.
/// -- For any constants that cannot be put in an immediate field,
///    load address into virtual register first, and then load the constant.
///
/// firstOp and lastOp can be used to skip leading and trailing operands.
/// If lastOp is 0, it defaults to #operands or #incoming Phi values.
///
inline void PreSelection::visitOperands(Instruction &I, int firstOp) {
  // For any instruction other than PHI, copies go just before the instr.
  for (unsigned i = firstOp, e = I.getNumOperands(); i != e; ++i)
    visitOneOperand(I, I.getOperand(i), i, I);
}

void PreSelection::visitPHINode(PHINode &PN) {
  // For a PHI, operand copies must be before the terminator of the
  // appropriate predecessor basic block.  Remaining logic is simple
  // so just handle PHIs and other instructions separately.
  //
  for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
    visitOneOperand(PN, PN.getIncomingValue(i),
                    PN.getOperandNumForIncomingValue(i),
                    *PN.getIncomingBlock(i)->getTerminator());
  // do not call visitOperands!
}

// Common work for *all* instructions.  This needs to be called explicitly
// by other visit<InstructionType> functions.
inline void PreSelection::visitInstruction(Instruction &I) {
  visitOperands(I);              // Perform operand transformations
}

// GetElementPtr instructions: check if pointer is a global
void PreSelection::visitGetElementPtrInst(GetElementPtrInst &I) {
  Instruction* curI = &I;

  // The Sparc backend doesn't handle array indexes that are not long types, so
  // insert a cast from whatever it is to long, if the sequential type index is
  // not a long already.
  unsigned Idx = 1;
  for (gep_type_iterator TI = gep_type_begin(I), E = gep_type_end(I); TI != E;
       ++TI, ++Idx)
    if (isa<SequentialType>(*TI) &&
        I.getOperand(Idx)->getType() != Type::LongTy) {
      Value *Op = I.getOperand(Idx);
      if (Op->getType()->isUnsigned())    // Must sign extend!
        Op = new CastInst(Op, Op->getType()->getSignedVersion(), "v9", &I);
      if (Op->getType() != Type::LongTy)
        Op = new CastInst(Op, Type::LongTy, "v9", &I);
      I.setOperand(Idx, Op);
    }

  // Decompose multidimensional array references
  if (I.getNumIndices() >= 2) {
    // DecomposeArrayRef() replaces I and deletes it, if successful,
    // so remember predecessor in order to find the replacement instruction.
    // Also remember the basic block in case there is no predecessor.
    Instruction* prevI = I.getPrev();
    BasicBlock* bb = I.getParent();
    if (DecomposeArrayRef(&I))
      // first instr. replacing I
      curI = cast<GetElementPtrInst>(prevI? prevI->getNext() : &bb->front());
  }

  // Perform other transformations common to all instructions
  visitInstruction(*curI);
}

void PreSelection::visitCallInst(CallInst &I) {
  // Tell visitOperands to ignore the function name if this is a direct call.
  visitOperands(I, (/*firstOp=*/ I.getCalledFunction()? 1 : 0));
}

/// createPreSelectionPass - Public entry point for the PreSelection pass
///
FunctionPass* llvm::createPreSelectionPass(const TargetMachine &TM) {
  return new PreSelection(TM);
}
<commit_msg>Added support for decomposing constant expressions containing shr and shl instructions. Review of this commit would be greatly appreciated.<commit_after>//===- SparcV9PreSelection.cpp - Specialize LLVM code for SparcV9 ---------===//
//
//                     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 file defines the PreSelection pass which specializes LLVM code for
// the SparcV9 instruction selector, while remaining in legal portable LLVM
// form and preserving type information and type safety. This is meant to enable
// dataflow optimizations on SparcV9-specific operations such as accesses to
// constants, globals, and array indexing.
//
//===----------------------------------------------------------------------===//

#include "SparcV9Internals.h"
#include "SparcV9BurgISel.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/InstVisitor.h"
#include "llvm/Support/GetElementPtrTypeIterator.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include <algorithm>
using namespace llvm;

namespace {

  //===--------------------------------------------------------------------===//
  // PreSelection Pass - Specialize LLVM code for the SparcV9 instr. selector.
  //
  class PreSelection : public FunctionPass, public InstVisitor<PreSelection> {
    const TargetInstrInfo &instrInfo;

  public:
    PreSelection(const TargetMachine &T)
      : instrInfo(*T.getInstrInfo()) {}

    // runOnFunction - apply this pass to each Function
    bool runOnFunction(Function &F) {
      visit(F);
      return true;
    }
    const char *getPassName() const { return "SparcV9 Instr. Pre-selection"; }

    // These methods do the actual work of specializing code
    void visitInstruction(Instruction &I);   // common work for every instr.
    void visitGetElementPtrInst(GetElementPtrInst &I);
    void visitCallInst(CallInst &I);
    void visitPHINode(PHINode &PN);

    void visitBasicBlock(BasicBlock &BB) {
      if (isa<UnreachableInst>(BB.getTerminator())) {
        BB.getInstList().pop_back();
        const Type *RetTy = BB.getParent()->getReturnType();
        Value *RetVal = RetTy == Type::VoidTy ? 0 : UndefValue::get(RetTy);
        new ReturnInst(RetVal, &BB);
      }
    }

    // Helper functions for visiting operands of every instruction
    //
    // visitOperands() works on every operand in [firstOp, lastOp-1].
    // If lastOp==0, lastOp defaults to #operands or #incoming Phi values.
    //
    // visitOneOperand() does all the work for one operand.
    //
    void visitOperands(Instruction &I, int firstOp=0);
    void visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                         Instruction& insertBefore);
  };

#if 0
  // Register the pass...
  RegisterPass<PreSelection> X("preselect",
                               "Specialize LLVM code for a target machine"
                               createPreselectionPass);
#endif

}  // end anonymous namespace

//------------------------------------------------------------------------------
// Helper functions used by methods of class PreSelection
//------------------------------------------------------------------------------

// getGlobalAddr(): Put address of a global into a v. register.
static GetElementPtrInst* getGlobalAddr(Value* ptr, Instruction& insertBefore) {

  return (isa<GlobalVariable>(ptr))
    ? new GetElementPtrInst(ptr,
                    std::vector<Value*>(1, ConstantSInt::get(Type::LongTy, 0U)),
                    "addrOfGlobal:" + ptr->getName(), &insertBefore)
    : NULL;
}

// Wrapper on Constant::classof to use in find_if
inline static bool nonConstant(const Use& U) {
  return ! isa<Constant>(U);
}

static Instruction* DecomposeConstantExpr(ConstantExpr* CE,
                                          Instruction& insertBefore)
{
  Value *getArg1, *getArg2;

  switch(CE->getOpcode())
    {
    case Instruction::Cast:
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      return new CastInst(getArg1, CE->getType(), "constantCast",&insertBefore);

    case Instruction::GetElementPtr:
      assert(std::find_if(CE->op_begin()+1, CE->op_end(),
                          nonConstant) == CE->op_end()
             && "All indices in ConstantExpr getelementptr must be constant!");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore))
        getArg1 = gep;
      return new GetElementPtrInst(getArg1,
                          std::vector<Value*>(CE->op_begin()+1, CE->op_end()),
                          "constantGEP:" + getArg1->getName(), &insertBefore);

    case Instruction::Select: {
      Value *C, *S1, *S2;
      C = CE->getOperand (0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (C))
        C = DecomposeConstantExpr (CEarg, insertBefore);
      S1 = CE->getOperand (1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (S1))
        S1 = DecomposeConstantExpr (CEarg, insertBefore);
      S2 = CE->getOperand (2);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (S2))
        S2 = DecomposeConstantExpr (CEarg, insertBefore);
      return new SelectInst (C, S1, S2, "constantSelect", &insertBefore);
    }

    case Instruction::Shr: {
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      getArg2 = CE->getOperand(1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
        getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
      return new ShiftInst (static_cast<Instruction::OtherOps>(CE->getOpcode()),
                            getArg1, getArg2,
                            "constantShr:" + getArg1->getName(), &insertBefore);
    }

    case Instruction::Shl: {
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      getArg2 = CE->getOperand(1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
        getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
      return new ShiftInst (static_cast<Instruction::OtherOps>(CE->getOpcode()),
                            getArg1, getArg2,
                            "constantShl:" + getArg1->getName(), &insertBefore);
    }

    default:                            // must be a binary operator
      assert(CE->getOpcode() >= Instruction::BinaryOpsBegin &&
             CE->getOpcode() <  Instruction::BinaryOpsEnd &&
             "Unhandled opcode in ConstantExpr");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      getArg2 = CE->getOperand(1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
        getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
      return BinaryOperator::create((Instruction::BinaryOps) CE->getOpcode(),
                                    getArg1, getArg2,
                                    "constantBinaryOp", &insertBefore);
    }
}

static inline bool ConstantTypeMustBeLoaded(const Type* CVT) {
  assert(CVT->isPrimitiveType() || isa<PointerType>(CVT));
  return !(CVT->isIntegral() || isa<PointerType>(CVT));
}

//------------------------------------------------------------------------------
// Instruction visitor methods to perform instruction-specific operations
//------------------------------------------------------------------------------
inline void
PreSelection::visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                              Instruction& insertBefore)
{
  assert(&insertBefore != NULL && "Must have instruction to insert before.");

  if (GetElementPtrInst* gep = getGlobalAddr(Op, insertBefore)) {
    I.setOperand(opNum, gep);           // replace global operand
    return;                             // nothing more to do for this op.
  }

  Constant* CV  = dyn_cast<Constant>(Op);
  if (CV == NULL)
    return;

  if (ConstantExpr* CE = dyn_cast<ConstantExpr>(CV)) {
    // load-time constant: factor it out so we optimize as best we can
    Instruction* computeConst = DecomposeConstantExpr(CE, insertBefore);
    I.setOperand(opNum, computeConst); // replace expr operand with result
  } else if (ConstantTypeMustBeLoaded(CV->getType())) {
    // load address of constant into a register, then load the constant
    // this is now done during instruction selection
    // the constant will live in the MachineConstantPool later on
  } else if (ConstantMayNotFitInImmedField(CV, &I)) {
    // put the constant into a virtual register using a cast
    CastInst* castI = new CastInst(CV, CV->getType(), "copyConst",
                                   &insertBefore);
    I.setOperand(opNum, castI);      // replace operand with copy in v.reg.
  }
}

/// visitOperands - transform individual operands of all instructions:
/// -- Load "large" int constants into a virtual register.  What is large
///    depends on the type of instruction and on the target architecture.
/// -- For any constants that cannot be put in an immediate field,
///    load address into virtual register first, and then load the constant.
///
/// firstOp and lastOp can be used to skip leading and trailing operands.
/// If lastOp is 0, it defaults to #operands or #incoming Phi values.
///
inline void PreSelection::visitOperands(Instruction &I, int firstOp) {
  // For any instruction other than PHI, copies go just before the instr.
  for (unsigned i = firstOp, e = I.getNumOperands(); i != e; ++i)
    visitOneOperand(I, I.getOperand(i), i, I);
}

void PreSelection::visitPHINode(PHINode &PN) {
  // For a PHI, operand copies must be before the terminator of the
  // appropriate predecessor basic block.  Remaining logic is simple
  // so just handle PHIs and other instructions separately.
  //
  for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
    visitOneOperand(PN, PN.getIncomingValue(i),
                    PN.getOperandNumForIncomingValue(i),
                    *PN.getIncomingBlock(i)->getTerminator());
  // do not call visitOperands!
}

// Common work for *all* instructions.  This needs to be called explicitly
// by other visit<InstructionType> functions.
inline void PreSelection::visitInstruction(Instruction &I) {
  visitOperands(I);              // Perform operand transformations
}

// GetElementPtr instructions: check if pointer is a global
void PreSelection::visitGetElementPtrInst(GetElementPtrInst &I) {
  Instruction* curI = &I;

  // The Sparc backend doesn't handle array indexes that are not long types, so
  // insert a cast from whatever it is to long, if the sequential type index is
  // not a long already.
  unsigned Idx = 1;
  for (gep_type_iterator TI = gep_type_begin(I), E = gep_type_end(I); TI != E;
       ++TI, ++Idx)
    if (isa<SequentialType>(*TI) &&
        I.getOperand(Idx)->getType() != Type::LongTy) {
      Value *Op = I.getOperand(Idx);
      if (Op->getType()->isUnsigned())    // Must sign extend!
        Op = new CastInst(Op, Op->getType()->getSignedVersion(), "v9", &I);
      if (Op->getType() != Type::LongTy)
        Op = new CastInst(Op, Type::LongTy, "v9", &I);
      I.setOperand(Idx, Op);
    }

  // Decompose multidimensional array references
  if (I.getNumIndices() >= 2) {
    // DecomposeArrayRef() replaces I and deletes it, if successful,
    // so remember predecessor in order to find the replacement instruction.
    // Also remember the basic block in case there is no predecessor.
    Instruction* prevI = I.getPrev();
    BasicBlock* bb = I.getParent();
    if (DecomposeArrayRef(&I))
      // first instr. replacing I
      curI = cast<GetElementPtrInst>(prevI? prevI->getNext() : &bb->front());
  }

  // Perform other transformations common to all instructions
  visitInstruction(*curI);
}

void PreSelection::visitCallInst(CallInst &I) {
  // Tell visitOperands to ignore the function name if this is a direct call.
  visitOperands(I, (/*firstOp=*/ I.getCalledFunction()? 1 : 0));
}

/// createPreSelectionPass - Public entry point for the PreSelection pass
///
FunctionPass* llvm::createPreSelectionPass(const TargetMachine &TM) {
  return new PreSelection(TM);
}
<|endoftext|>