<commit_before>/* Copyright 2019 Google LLC. All Rights Reserved.

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 "tensorflow/lite/experimental/ruy/trmul.h"

#include <cstring>

#include "profiling/instrumentation.h"
#include "tensorflow/lite/experimental/ruy/allocator.h"
#include "tensorflow/lite/experimental/ruy/block_map.h"
#include "tensorflow/lite/experimental/ruy/common.h"
#include "tensorflow/lite/experimental/ruy/opt_set.h"
#include "tensorflow/lite/experimental/ruy/side_pair.h"
#include "tensorflow/lite/experimental/ruy/spec.h"
#include "tensorflow/lite/experimental/ruy/thread_pool.h"
#include "tensorflow/lite/experimental/ruy/trace.h"

namespace ruy {

namespace {

struct TrMulTask final : Task {
  TrMulTask(TrMulParams* params_, const BlockMap& block_map_,
            std::atomic<int>* atomic_block_id_, int thread_id_,
            SidePair<std::atomic<bool>*> packed_,
            TuningResolver* tuning_resolver_, Allocator* local_allocator_,
            Trace* trace_)
      : params(params_),
        block_map(block_map_),
        atomic_block_id(atomic_block_id_),
        thread_id(thread_id_),
        packed(packed_),
        tuning_resolver(tuning_resolver_),
        local_allocator(local_allocator_),
        trace(trace_) {}

  void Run() override {
    TraceRecordThreadStart(thread_id, trace);

    // Local indicators of packedness to avoid the overhead of atomic ops.
    SidePair<bool*> local_packed{nullptr, nullptr};

    for (Side side : {Side::kLhs, Side::kRhs}) {
      if (packed[side]) {
        const int size = NumBlocksPerSide(side, block_map);
        local_allocator->Allocate(size, &local_packed[side]);
        memset(local_packed[side], 0, size * sizeof(bool));
      }
    }

    const int num_blocks = NumBlocks(block_map);

    const Tuning tuning = tuning_resolver->Resolve();

    TraceRecordThreadLoopStart(thread_id, trace);

    SidePair<int> block;
    SidePair<int> start;
    SidePair<int> end;

    // Each thread starts by initially reserving the block whose id
    // is the thread id.
    int block_id = thread_id;
    TraceRecordBlockReserved(thread_id, block_id, trace);

    while (block_id < num_blocks) {
      // Reserve the next block to handle. In order to hide the latency
      // (typically comparable to an access to the level of data cache that
      // is shared among CPU cores, e.g. 60 cycles on an ARM CPU as of 2019)
      // of this atomic operation, we structure this code so as to avoid
      // immediately depending on the `next_n` result.
      const int next_block_id =
          atomic_block_id->fetch_add(1, std::memory_order_relaxed);
      TraceRecordBlockReserved(thread_id, next_block_id, trace);
      // Get coordinates of the current block to handle, in "block space".
      GetBlockByIndex(block_map, block_id, &block);
      // Get coordinates of the current block to handle, in matrix space.
      GetBlockMatrixCoords(block_map, block, &start, &end);
      TraceRecordBlockCoordsComputed(block_id, trace);
      // Maybe pack the current LHS/RHS block, if not already packed.
      for (Side side : {Side::kLhs, Side::kRhs}) {
        EnsurePacked(side, block_id, local_packed, block, start, end, tuning);
      }
      // Actually do matrix multiplication work
      params->RunKernel(tuning, start, end);
      TraceRecordBlockFinished(block_id, trace);
      // Move on to the next block as obtained by the atomic increment
      // at the start of this while loop iteration.
      block_id = next_block_id;
    }

    local_allocator->FreeAll();

    TraceRecordThreadEnd(thread_id, trace);
  }

 private:
  void EnsurePacked(Side side, int block_id, const SidePair<bool*> local_packed,
                    const SidePair<int>& block, const SidePair<int>& start,
                    const SidePair<int>& end, Tuning tuning) {
    // If two threads concurrently hit the same block to pack,
    // we allow them to concurrently pack it, writing the same packed matrix
    // data to the same location. That is considered worth it to avoid
    // having one thread blocked on another one. Avoiding that is considered
    // important especially on mobile, where there can be large speed
    // discrepancy between threads, e.g. if different threads are scheduled
    // on CPU cores of different types (big/little), different clock speed,
    // different contention with other processes.
    if (local_packed[side] && !local_packed[side][block[side]]) {
      if (!packed[side][block[side]].load(std::memory_order_acquire)) {
        params->RunPack(side, tuning, start, end);
        TraceRecordBlockPacked(side, block_id, trace);
        local_packed[side][block[side]] = true;
        packed[side][block[side]].store(true, std::memory_order_release);
      }
    }
  }

  TrMulParams* params;
  const BlockMap& block_map;
  std::atomic<int>* atomic_block_id;
  int thread_id;
  SidePair<std::atomic<bool>*> packed;
  TuningResolver* tuning_resolver;
  Allocator* local_allocator;
  Trace* trace;
};

void AllocatePMatrix(Allocator* allocator, PMatrix* packed) {
  packed->data = allocator->AllocateBytes(DataSize(*packed));
  packed->sums = allocator->AllocateBytes(SumsSize(*packed));
}

int GetThreadCount(Context* context, int rows, int cols, int depth) {
  // Empirically determined rule for reasonable number of
  // threads to use. This is proportional to the number of arithmetic ops
  // in this Mul (product of the 3 sizes).
  int guess = (std::uint64_t(rows) * cols * depth) >> 13;
  return clamp(guess, 1, context->max_num_threads);
}

LoopStructure GetLoopStructure(int thread_count, int rows, int cols, int depth,
                               int cache_friendly_traversal_threshold) {
  if (thread_count == 1 &&
      (rows + cols) * depth < cache_friendly_traversal_threshold) {
    return LoopStructure::kSimple;
  }
  return LoopStructure::kGeneral;
}

}  // namespace

void TrMul(TrMulParams* params, Context* context) {
  gemmlowp::ScopedProfilingLabel label("TrMul");

  PMatrix& packed_lhs = params->packed[Side::kLhs];
  PMatrix& packed_rhs = params->packed[Side::kRhs];
  DMatrix& lhs = params->src[Side::kLhs];
  DMatrix& rhs = params->src[Side::kRhs];

  const int rows = lhs.layout.cols;
  const int cols = rhs.layout.cols;
  const int depth = lhs.layout.rows;

  int thread_count = GetThreadCount(context, rows, cols, depth);
  const auto loop_structure =
      GetLoopStructure(thread_count, rows, cols, depth,
                       params->cache_friendly_traversal_threshold);
  Allocator* allocator = context->GetMainAllocator();

  // Allocate packed matrices
  for (Side side : {Side::kLhs, Side::kRhs}) {
    if (!params->is_prepacked[side]) {
      AllocatePMatrix(allocator, &params->packed[side]);
    }
  }

  // Case of running this TrMul as a simple loop.
  // This is a good place to start reading this function: all the rest
  // of this function is just an optimized, but functionally equivalent,
  // version of that.
  if (loop_structure == LoopStructure::kSimple) {
    gemmlowp::ScopedProfilingLabel label_simple("TrMulImpl, simple loop");
    Tuning tuning = context->GetMainThreadTuning();

    const SidePair<int> origin{0, 0};
    const SidePair<int> rounded_dims{packed_lhs.layout.cols,
                                     packed_rhs.layout.cols};
    for (Side side : {Side::kLhs, Side::kRhs}) {
      if (!params->is_prepacked[side]) {
        params->RunPack(side, tuning, origin, rounded_dims);
      }
    }
    params->RunKernel(tuning, origin, rounded_dims);

    allocator->FreeAll();
    return;
  }

  gemmlowp::ScopedProfilingLabel label_general("TrMulImpl, general case");

  auto* trace = NewTraceOrNull(&context->tracing, rows, depth, cols);
  TraceRecordStart(trace);

  // Initialize block map.
  BlockMap block_map;
  MakeBlockMap(packed_lhs.layout.cols, packed_rhs.layout.cols, depth,
               packed_lhs.layout.kernel.cols, packed_rhs.layout.kernel.cols,
               packed_lhs.data_type.size, packed_rhs.data_type.size,
               params->cache_friendly_traversal_threshold, &block_map);

  // Initialize per-thread state.
  thread_count = clamp(thread_count, 1, NumBlocks(block_map));
  context->EnsureNPerThreadStates(thread_count);
  for (auto& per_thread_state : context->per_thread_states) {
    per_thread_state->tuning_resolver.SetTuning(context->explicit_tuning);
  }

  // Allocate and initialize atomic values tracking already-packed blocks.
  SidePair<std::atomic<bool>*> packed{nullptr, nullptr};
  for (Side side : {Side::kLhs, Side::kRhs}) {
    if (!params->is_prepacked[side]) {
      const int size = NumBlocksPerSide(side, block_map);
      allocator->Allocate(size, &packed[side]);
      for (int i = 0; i < size; i++) {
        packed[side][i].store(false, std::memory_order_relaxed);
      }
    }
  }

  // Create the atomic block id, allocate it using Allocator so that
  // we get the alignment ensuring that it sits alone in its exclusives
  // reservation granule.
  std::atomic<int>* atomic_block_id;
  allocator->Allocate(1, &atomic_block_id);

  // Create task objects.
  TrMulTask* tasks;
  allocator->Allocate(thread_count, &tasks);

  atomic_block_id->store(thread_count);

  for (int i = 0; i < thread_count; i++) {
    new (tasks + i) TrMulTask(params, block_map, atomic_block_id, i, packed,
                              &context->per_thread_states[i]->tuning_resolver,
                              &context->per_thread_states[i]->allocator, trace);
  }

  // Do the computation.
  TraceRecordExecute(trace);
  TraceStartRecordingBlockAndThreadFields(block_map, thread_count, trace);

  context->workers_pool.Execute(thread_count, tasks);

  // Finish up.
  for (int i = 0; i < thread_count; i++) {
    tasks[i].~TrMulTask();
  }

  TraceRecordEnd(trace);

  allocator->FreeAll();
}

}  // namespace ruy
<commit_msg>Oops: we were never taking advantage of a read of the atomic 'packed' indicator returning true, to update the local_packed indicator. In other words, when another thread had packed a block, and we had obtained that information from an expensive atomic read, we did not cache that precious information to avoid subsequent expensive atomic reads.<commit_after>/* Copyright 2019 Google LLC. All Rights Reserved.

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 "tensorflow/lite/experimental/ruy/trmul.h"

#include <cstring>

#include "profiling/instrumentation.h"
#include "tensorflow/lite/experimental/ruy/allocator.h"
#include "tensorflow/lite/experimental/ruy/block_map.h"
#include "tensorflow/lite/experimental/ruy/common.h"
#include "tensorflow/lite/experimental/ruy/opt_set.h"
#include "tensorflow/lite/experimental/ruy/side_pair.h"
#include "tensorflow/lite/experimental/ruy/spec.h"
#include "tensorflow/lite/experimental/ruy/thread_pool.h"
#include "tensorflow/lite/experimental/ruy/trace.h"

namespace ruy {

namespace {

struct TrMulTask final : Task {
  TrMulTask(TrMulParams* params_, const BlockMap& block_map_,
            std::atomic<int>* atomic_block_id_, int thread_id_,
            SidePair<std::atomic<bool>*> packed_,
            TuningResolver* tuning_resolver_, Allocator* local_allocator_,
            Trace* trace_)
      : params(params_),
        block_map(block_map_),
        atomic_block_id(atomic_block_id_),
        thread_id(thread_id_),
        packed(packed_),
        tuning_resolver(tuning_resolver_),
        local_allocator(local_allocator_),
        trace(trace_) {}

  void Run() override {
    TraceRecordThreadStart(thread_id, trace);

    // Local indicators of packedness to avoid the overhead of atomic ops.
    SidePair<bool*> local_packed{nullptr, nullptr};

    for (Side side : {Side::kLhs, Side::kRhs}) {
      if (packed[side]) {
        const int size = NumBlocksPerSide(side, block_map);
        local_allocator->Allocate(size, &local_packed[side]);
        memset(local_packed[side], 0, size * sizeof(bool));
      }
    }

    const int num_blocks = NumBlocks(block_map);

    const Tuning tuning = tuning_resolver->Resolve();

    TraceRecordThreadLoopStart(thread_id, trace);

    SidePair<int> block;
    SidePair<int> start;
    SidePair<int> end;

    // Each thread starts by initially reserving the block whose id
    // is the thread id.
    int block_id = thread_id;
    TraceRecordBlockReserved(thread_id, block_id, trace);

    while (block_id < num_blocks) {
      // Reserve the next block to handle. In order to hide the latency
      // (typically comparable to an access to the level of data cache that
      // is shared among CPU cores, e.g. 60 cycles on an ARM CPU as of 2019)
      // of this atomic operation, we structure this code so as to avoid
      // immediately depending on the `next_n` result.
      const int next_block_id =
          atomic_block_id->fetch_add(1, std::memory_order_relaxed);
      TraceRecordBlockReserved(thread_id, next_block_id, trace);
      // Get coordinates of the current block to handle, in "block space".
      GetBlockByIndex(block_map, block_id, &block);
      // Get coordinates of the current block to handle, in matrix space.
      GetBlockMatrixCoords(block_map, block, &start, &end);
      TraceRecordBlockCoordsComputed(block_id, trace);
      // Maybe pack the current LHS/RHS block, if not already packed.
      for (Side side : {Side::kLhs, Side::kRhs}) {
        EnsurePacked(side, block_id, local_packed, block, start, end, tuning);
      }
      // Actually do matrix multiplication work
      params->RunKernel(tuning, start, end);
      TraceRecordBlockFinished(block_id, trace);
      // Move on to the next block as obtained by the atomic increment
      // at the start of this while loop iteration.
      block_id = next_block_id;
    }

    local_allocator->FreeAll();

    TraceRecordThreadEnd(thread_id, trace);
  }

 private:
  void EnsurePacked(Side side, int block_id, const SidePair<bool*> local_packed,
                    const SidePair<int>& block, const SidePair<int>& start,
                    const SidePair<int>& end, Tuning tuning) {
    // If two threads concurrently hit the same block to pack,
    // we allow them to concurrently pack it, writing the same packed matrix
    // data to the same location. That is considered worth it to avoid
    // having one thread blocked on another one. Avoiding that is considered
    // important especially on mobile, where there can be large speed
    // discrepancy between threads, e.g. if different threads are scheduled
    // on CPU cores of different types (big/little), different clock speed,
    // different contention with other processes.
    if (local_packed[side] && !local_packed[side][block[side]]) {
      if (!packed[side][block[side]].load(std::memory_order_acquire)) {
        params->RunPack(side, tuning, start, end);
        TraceRecordBlockPacked(side, block_id, trace);
        packed[side][block[side]].store(true, std::memory_order_release);
      }
      local_packed[side][block[side]] = true;
    }
  }

  TrMulParams* params;
  const BlockMap& block_map;
  std::atomic<int>* atomic_block_id;
  int thread_id;
  SidePair<std::atomic<bool>*> packed;
  TuningResolver* tuning_resolver;
  Allocator* local_allocator;
  Trace* trace;
};

void AllocatePMatrix(Allocator* allocator, PMatrix* packed) {
  packed->data = allocator->AllocateBytes(DataSize(*packed));
  packed->sums = allocator->AllocateBytes(SumsSize(*packed));
}

int GetThreadCount(Context* context, int rows, int cols, int depth) {
  // Empirically determined rule for reasonable number of
  // threads to use. This is proportional to the number of arithmetic ops
  // in this Mul (product of the 3 sizes).
  int guess = (std::uint64_t(rows) * cols * depth) >> 13;
  return clamp(guess, 1, context->max_num_threads);
}

LoopStructure GetLoopStructure(int thread_count, int rows, int cols, int depth,
                               int cache_friendly_traversal_threshold) {
  if (thread_count == 1 &&
      (rows + cols) * depth < cache_friendly_traversal_threshold) {
    return LoopStructure::kSimple;
  }
  return LoopStructure::kGeneral;
}

}  // namespace

void TrMul(TrMulParams* params, Context* context) {
  gemmlowp::ScopedProfilingLabel label("TrMul");

  PMatrix& packed_lhs = params->packed[Side::kLhs];
  PMatrix& packed_rhs = params->packed[Side::kRhs];
  DMatrix& lhs = params->src[Side::kLhs];
  DMatrix& rhs = params->src[Side::kRhs];

  const int rows = lhs.layout.cols;
  const int cols = rhs.layout.cols;
  const int depth = lhs.layout.rows;

  int thread_count = GetThreadCount(context, rows, cols, depth);
  const auto loop_structure =
      GetLoopStructure(thread_count, rows, cols, depth,
                       params->cache_friendly_traversal_threshold);
  Allocator* allocator = context->GetMainAllocator();

  // Allocate packed matrices
  for (Side side : {Side::kLhs, Side::kRhs}) {
    if (!params->is_prepacked[side]) {
      AllocatePMatrix(allocator, &params->packed[side]);
    }
  }

  // Case of running this TrMul as a simple loop.
  // This is a good place to start reading this function: all the rest
  // of this function is just an optimized, but functionally equivalent,
  // version of that.
  if (loop_structure == LoopStructure::kSimple) {
    gemmlowp::ScopedProfilingLabel label_simple("TrMulImpl, simple loop");
    Tuning tuning = context->GetMainThreadTuning();

    const SidePair<int> origin{0, 0};
    const SidePair<int> rounded_dims{packed_lhs.layout.cols,
                                     packed_rhs.layout.cols};
    for (Side side : {Side::kLhs, Side::kRhs}) {
      if (!params->is_prepacked[side]) {
        params->RunPack(side, tuning, origin, rounded_dims);
      }
    }
    params->RunKernel(tuning, origin, rounded_dims);

    allocator->FreeAll();
    return;
  }

  gemmlowp::ScopedProfilingLabel label_general("TrMulImpl, general case");

  auto* trace = NewTraceOrNull(&context->tracing, rows, depth, cols);
  TraceRecordStart(trace);

  // Initialize block map.
  BlockMap block_map;
  MakeBlockMap(packed_lhs.layout.cols, packed_rhs.layout.cols, depth,
               packed_lhs.layout.kernel.cols, packed_rhs.layout.kernel.cols,
               packed_lhs.data_type.size, packed_rhs.data_type.size,
               params->cache_friendly_traversal_threshold, &block_map);

  // Initialize per-thread state.
  thread_count = clamp(thread_count, 1, NumBlocks(block_map));
  context->EnsureNPerThreadStates(thread_count);
  for (auto& per_thread_state : context->per_thread_states) {
    per_thread_state->tuning_resolver.SetTuning(context->explicit_tuning);
  }

  // Allocate and initialize atomic values tracking already-packed blocks.
  SidePair<std::atomic<bool>*> packed{nullptr, nullptr};
  for (Side side : {Side::kLhs, Side::kRhs}) {
    if (!params->is_prepacked[side]) {
      const int size = NumBlocksPerSide(side, block_map);
      allocator->Allocate(size, &packed[side]);
      for (int i = 0; i < size; i++) {
        packed[side][i].store(false, std::memory_order_relaxed);
      }
    }
  }

  // Create the atomic block id, allocate it using Allocator so that
  // we get the alignment ensuring that it sits alone in its exclusives
  // reservation granule.
  std::atomic<int>* atomic_block_id;
  allocator->Allocate(1, &atomic_block_id);

  // Create task objects.
  TrMulTask* tasks;
  allocator->Allocate(thread_count, &tasks);

  atomic_block_id->store(thread_count);

  for (int i = 0; i < thread_count; i++) {
    new (tasks + i) TrMulTask(params, block_map, atomic_block_id, i, packed,
                              &context->per_thread_states[i]->tuning_resolver,
                              &context->per_thread_states[i]->allocator, trace);
  }

  // Do the computation.
  TraceRecordExecute(trace);
  TraceStartRecordingBlockAndThreadFields(block_map, thread_count, trace);

  context->workers_pool.Execute(thread_count, tasks);

  // Finish up.
  for (int i = 0; i < thread_count; i++) {
    tasks[i].~TrMulTask();
  }

  TraceRecordEnd(trace);

  allocator->FreeAll();
}

}  // namespace ruy
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	TELNET サーバー・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "ethernet_server.hpp"
#include "common/fixed_fifo.hpp"

#define TELNETS_DEBUG

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  telnet_server class テンプレート
		@param[in]	SEND_SIZE	送信、一時バッファサイズ
		@param[in]	RECV_SIZE	受信、一時バッファサイズ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t SEND_SIZE, uint32_t RECV_SIZE>
	class telnet_server {

	private:
		// デバッグ以外で出力を無効にする
#ifdef TELNETS_DEBUG
		typedef utils::format debug_format;
#else
		typedef utils::null_format debug_format;
#endif

		ethernet&		eth_;
		ethernet_server	telnet_;

		enum class task : uint8_t {
			none,
			begin,
			wait,
			main_loop,
			disconnect_delay,
			disconnect,
		};
		task		task_;

		char		server_name_[32];
		uint32_t	count_;
		uint32_t	disconnect_loop_;

		typedef utils::fixed_fifo<char, SEND_SIZE> SEND_FIFO;
		typedef utils::fixed_fifo<char, RECV_SIZE> RECV_FIFO;

		SEND_FIFO	send_;
		RECV_FIFO	recv_;

		void write_()
		{
			char tmp[256];
			uint16_t l = 0;
			while(send_.length() > 0) {
				auto ch = send_.get();
				tmp[l] = ch;
				++l;
				if(l >= sizeof(tmp)) {
					telnet_.write(tmp, l);
					l = 0;
				}
			}
			if(l > 0) {
				telnet_.write(tmp, l);
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		telnet_server(ethernet& e) : eth_(e), telnet_(e), task_(task::none),
			server_name_{ 0 }, count_(0), disconnect_loop_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  スタート
			@param[in]	server_name	サーバー名
		*/
		//-----------------------------------------------------------------//
		void start(const char* server_name)
		{
			std::strncpy(server_name_, server_name, sizeof(server_name_) - 1);

			count_ = 0;
			disconnect_loop_ = 0;

			task_ = task::begin;

			debug_format("TELNET Server: SEND_BUFF: %d, RECV_BUFF: %d\n") % SEND_SIZE % RECV_SIZE;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
			@param[in]	cycle	サービス・サイクル（通常１００Ｈｚ）
			@param[in]	port	TELNET ポート番号（通常２３番）
		*/
		//-----------------------------------------------------------------//
		void service(uint32_t cycle, uint16_t port = 23)
		{
			switch(task_) {
			case task::none:
				break;

			case task::begin:
				telnet_.begin(port);
				debug_format("Start TELNET Server: '%s' port(%d), fd(%d)\n")
					% eth_.get_local_ip().c_str()
					% static_cast<int>(telnet_.get_port()) % telnet_.get_cepid();
				task_ = task::wait;
				break;

			case task::wait:
				if(telnet_.connected()) {
					debug_format("TELNET Server: New connected, from: %s\n") % telnet_.get_from_ip().c_str();
					++count_;
					task_ = task::main_loop;
				}
				break;

			case task::main_loop:
				if(telnet_.connected()) {
					if(telnet_.available() > 0) {  // リードデータがあるか？
						char tmp[RECV_SIZE];
						int len = telnet_.read(tmp, sizeof(tmp));
//						recv_.length()
					}
					write_();
				} else {
					task_ = task::disconnect_delay;
					disconnect_loop_ = 10;
				}
				break;

			case task::disconnect_delay:
				if(disconnect_loop_ > 0) {
					--disconnect_loop_;
				} else {
					task_ = task::disconnect;
				}
				break;

			case task::disconnect:
			default:
				telnet_.stop();
				debug_format("TELNET Server: disconnected\n");
				task_ = task::begin;
				break;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  出力
			@param[in]	text	出力文字列
		*/
		//-----------------------------------------------------------------//
		void putch(char ch)
		{
			if(ch == '\n') {
				putch('\r');
			}
			if(task_ == task::main_loop) {
				if((send_.size() - send_.length()) <= 2) {
					write_();
				}
				send_.put(ch);
//				if(ch == '\r') {
//				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  出力
			@param[in]	text	出力文字列
		*/
		//-----------------------------------------------------------------//
		void puts(const char* text)
		{
			if(text == nullptr) return;

			if(task_ == task::main_loop) {
				char ch;
				while((ch = *text++) != 0) {
					putch(ch);
				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  入力文字数取得
			@return 入力文字数
		*/
		//-----------------------------------------------------------------//
		uint32_t length() const
		{
			return 0;
		}
	};
}

<commit_msg>update API<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	TELNET サーバー・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "ethernet_server.hpp"
#include "common/fixed_fifo.hpp"

#define TELNETS_DEBUG

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  telnet_server class テンプレート
		@param[in]	SEND_SIZE	送信、一時バッファサイズ
		@param[in]	RECV_SIZE	受信、一時バッファサイズ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t SEND_SIZE, uint32_t RECV_SIZE>
	class telnet_server {

	private:
		// デバッグ以外で出力を無効にする
#ifdef TELNETS_DEBUG
		typedef utils::format debug_format;
#else
		typedef utils::null_format debug_format;
#endif

		ethernet&		eth_;
		ethernet_server	telnet_;

		enum class task : uint8_t {
			none,
			begin,
			wait,
			main_loop,
			disconnect_delay,
			disconnect,
		};
		task		task_;

		char		server_name_[32];
		char		user_[32];
		char		pass_[32];
		uint32_t	count_;
		uint32_t	disconnect_loop_;
		uint32_t	recv_lost_;

		typedef utils::fixed_fifo<char, SEND_SIZE> SEND_FIFO;
		typedef utils::fixed_fifo<char, RECV_SIZE> RECV_FIFO;

		SEND_FIFO	send_;
		RECV_FIFO	recv_;

		void write_()
		{
			char tmp[256];
			uint16_t l = 0;
			while(send_.length() > 0) {
				auto ch = send_.get();
				tmp[l] = ch;
				++l;
				if(l >= sizeof(tmp)) {
					telnet_.write(tmp, l);
					l = 0;
				}
			}
			if(l > 0) {
				telnet_.write(tmp, l);
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		telnet_server(ethernet& e) : eth_(e), telnet_(e), task_(task::none),
			server_name_{ 0 }, user_{ 0 }, pass_{ 0 },
			count_(0), disconnect_loop_(0), recv_lost_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  スタート
			@param[in]	server_name	サーバー名
			@param[in]	user		ユーザー名
			@param[in]	pass		パスワード
		*/
		//-----------------------------------------------------------------//
		void start(const char* server_name, const char* user = nullptr, const char* pass = nullptr)
		{
			std::strncpy(server_name_, server_name, sizeof(server_name_) - 1);
			if(user != nullptr) std::strncpy(user_, user, sizeof(user_) - 1);
			if(pass != nullptr) std::strncpy(pass_, pass, sizeof(pass_) - 1);

			count_ = 0;
			disconnect_loop_ = 0;
			recv_lost_ = 0;

			task_ = task::begin;

			debug_format("TELNET Server: SEND_BUFF: %d, RECV_BUFF: %d\n") % SEND_SIZE % RECV_SIZE;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
			@param[in]	cycle	サービス・サイクル（通常１００Ｈｚ）
			@param[in]	port	TELNET ポート番号（通常２３番）
		*/
		//-----------------------------------------------------------------//
		void service(uint32_t cycle, uint16_t port = 23)
		{
			switch(task_) {
			case task::none:
				break;

			case task::begin:
				telnet_.begin(port);
				debug_format("Start TELNET Server: '%s' port(%d), fd(%d)\n")
					% eth_.get_local_ip().c_str()
					% static_cast<int>(telnet_.get_port()) % telnet_.get_cepid();
				task_ = task::wait;
				break;

			case task::wait:
				if(telnet_.connected()) {
					debug_format("TELNET Server: New connected, from: %s\n") % telnet_.get_from_ip().c_str();
					++count_;
					task_ = task::main_loop;
				}
				break;

			case task::main_loop:
				if(telnet_.connected()) {
					if(telnet_.available() > 0) {  // リードデータがあるか？
						char tmp[256];
						int len = telnet_.read(tmp, sizeof(tmp));
						if(len > 0) {
							int l = 0;
							while((recv_.size() - recv_.length()) > 2) {
								recv_.put(tmp[l]);
								++l;
								if(l >= len) break;
							}
							recv_lost_ += len - l;
						}
					}
					write_();
				} else {
					task_ = task::disconnect_delay;
					disconnect_loop_ = 10;
				}
				break;

			case task::disconnect_delay:
				if(disconnect_loop_ > 0) {
					--disconnect_loop_;
				} else {
					task_ = task::disconnect;
				}
				break;

			case task::disconnect:
			default:
				telnet_.stop();
				debug_format("TELNET Server: disconnected\n");
				task_ = task::begin;
				break;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  出力
			@param[in]	text	出力文字列
		*/
		//-----------------------------------------------------------------//
		void putch(char ch)
		{
			if(ch == '\n') {
				putch('\r');
			}
			if(task_ == task::main_loop) {
				if((send_.size() - send_.length()) <= 2) {
					write_();
				}
				send_.put(ch);
//				if(ch == '\r') {
//					flush_();
//				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  出力
			@param[in]	text	出力文字列
		*/
		//-----------------------------------------------------------------//
		void puts(const char* text)
		{
			if(text == nullptr) return;

			if(task_ == task::main_loop) {
				char ch;
				while((ch = *text++) != 0) {
					putch(ch);
				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  入力文字数取得
			@return 入力文字数
		*/
		//-----------------------------------------------------------------//
		uint32_t length() const
		{
			return recv_.length();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  入力文字取得
			@return 入力文字（入力文字が無い場合「０」が返る）
		*/
		//-----------------------------------------------------------------//
		char getch() const
		{
			if(recv_.length() > 0) {
				return recv_.get();
			} else {
				return 0;
			}
		}
	};
}

<|endoftext|>


<commit_before>/*-------------brownian.cpp---------------------------------------------------//
*
*              What Color is BROWNian Motion?
*
* Purpose: This will be a simple Brownian motion simulation. I will throw the
*          results into vbots and get out some 3-d motion and such.
*
*          I will then do some Doppler shift stuff to see how the color changes
*          based on the velocity of the initial particles (assuming they are
*          emitting light and are moving relatively fast).
*
*   State: Currently adding in the hard_sphere collisions. Woo!
*
*   Notes: I should massacre the vbots code and stick it into this by imbedding
*          python into c++ code. This is somewhat documented online. This would
*          mean that I could generate a series of png files rather than output
*          files in the end, saving a good bit or writing time and space.
*
*   ERROR: For some reason, the particles are not moving every timestep...
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>

using namespace std;

/*----------------------------------------------------------------------------//
* STRUCTURES AND FUNCTIONS
*-----------------------------------------------------------------------------*/

struct part{
    double radius, mass, x, y, z, vx, vy, vz;             // Particle parameters
};

struct vox_cube{
    double x, y, z, intensity;
};

vector<part> simulate(double cube_length, vector<part> particles, int max_time,
                      double timestep);
vector<vox_cube> doppler(vector<part> motion_path);
vector<part> fill_box(int pnum, double cube_length, double max_vel, double r1,
                      double r2, double mass_1, double mass_2);
vector <part> hard_sphere(part part_1, part part_2, double timestep);

/*----------------------------------------------------------------------------//
* MAIN
*-----------------------------------------------------------------------------*/

int main(){

    vector<part> particles = fill_box(400, 40, 1, 1, 5, 0.5, 0.5);
    vector<part> motion_path = simulate(40, particles, 10, 1);

    for (int i = 0; i < motion_path.size(); i++){
        cout << motion_path[i].x << endl;
    }
}

/*----------------------------------------------------------------------------//
* SUBROUTINES
*-----------------------------------------------------------------------------*/

// Function to fill the box with randomly positioned initial particles. Note
// that I should be using random velocities too.
vector<part> fill_box(int pnum, double cube_length, double max_vel, double r1,
                      double r2, double mass_1, double mass_2){

    srand(time(0));
    vector<part> particles;
    part particle;

    // Let's go ahead and set the large particle in the middle
    particle.x = rand() % 10000 * 0.0001 * cube_length;
    particle.y = rand() % 10000 * 0.0001 * cube_length;
    particle.z = rand() % 10000 * 0.0001 * cube_length;
    particle.vx = rand() % 10000 * 0.0001 * max_vel;
    particle.vy = rand() % 10000 * 0.0001 * max_vel;
    particle.vz = rand() % 10000 * 0.0001 * max_vel;
    particle.radius = r2;
    particle.mass = mass_2;

    particles.push_back(particle);

    // Random number generator
    for (int i= 0; i <= pnum; i++){

        particle.x = rand() % 10000 * 0.0001 * cube_length;
            while (particle.x > (particles[0].x - r2) &&
                   particle.x < (particles[0].x + r2)){
                particle.x = rand() % 10000 * 0.0001 * cube_length;
                cout << "check " << i + 1 << endl;
            }

        particle.y = rand() % 10000 * 0.0001 * cube_length;
            while (particle.y > particles[0].y - r2 &&
                   particle.y < particles[0].y + r2){
                particle.y = rand() % 10000 * 0.0001 * cube_length;
            }

        particle.z = rand() % 10000 * 0.0001 * cube_length;
            while (particle.z > particles[0].z - r2 &&
                   particle.z < particles[0].z + r2){
                particle.z = rand() % 10000 * 0.0001 * cube_length;
            }

        particle.vx = rand() % 10000 * 0.0001 * max_vel;
        particle.vy = rand() % 10000 * 0.0001 * max_vel;
        particle.vz = rand() % 10000 * 0.0001 * max_vel;
        particle.radius = r1;
        particle.mass = mass_2;

        particles.push_back(particle);

    }

    for (int i = 0; i < particles.size(); i++){
        cout << i << '\t' << particles[i].x << endl;
    }

    return particles;
}

// This should deal with the interactions of the partiocles.
vector<part> simulate(double box_length, vector<part> particles, int max_time,
                      double timestep){

    // We will certainly have to do a hard sphere collision if any two particles
    // become sufficiently close to each other. We should go ahead and add in
    // a vector of parts...
    vector<part> collision_out, motion_path;
    part particle;

    particle.x = 0;
    particle.y = 0;
    particle.z = 0;
    particle.vx = 0;
    particle.vy = 0;
    particle.vz = 0;
    particle.radius = 0;
    particle.mass = 0;

    collision_out.push_back(particle);
    collision_out.push_back(particle);

    cout << "testing..." << endl;

    // So let's start by moving all the particles forward a single timestep
    for (int i = 0; i < max_time; i++){
        for (int ii = 0; ii < particles.size(); ii++){
            particles[ii].x = particles[ii].vx * timestep;
            if (particles[ii].x > box_length){
                particles[ii].x -= box_length;
            }

            if (particles[ii].x < 0){
                particles[ii].x += box_length;
            }

            particles[ii].y = particles[ii].vy * timestep;
            if (particles[ii].y > box_length){
                particles[ii].y -= box_length;
            }

            if (particles[ii].y < 0){
                particles[ii].y += box_length;
            }

            particles[ii].z = particles[ii].vz * timestep;
            if (particles[ii].z > box_length){
                particles[ii].z -= box_length;
            }

            if (particles[ii].z < 0){
                particles[ii].z += box_length;
            }

            // I really don't like all these nested loops...
            for (int iii = 0; iii < particles.size(); iii++){
                if (particles[ii].x > (particles[iii].x -
                                       particles[iii].radius) &&
                    particles[ii].y > (particles[iii].y -
                                       particles[iii].radius) &&
                    particles[ii].z > (particles[iii].z -
                                       particles[iii].radius) &&
                    particles[ii].x < (particles[iii].x +
                                       particles[iii].radius) &&
                    particles[ii].y < (particles[iii].y +
                                       particles[iii].radius) &&
                    particles[ii].z < (particles[iii].z +
                                       particles[iii].radius)){

                    collision_out = hard_sphere(particles[ii], particles[iii],
                                                timestep);

                    // Now, I might have mixed these guys up. Oops.
                    particles[ii] = collision_out[0];
                    particles[iii] = collision_out[1];
                }
            }

        }

    // Now we need to keep track of the motion path of the large particle. Each
    // element is a timestep
    motion_path.push_back(particles[0]);
    }

return motion_path;
}

// I may need to perform a "hard sphere collision" if the smaller particle is
// within the radius of the larger particle. I think I'll assume that the radius
// of the smaller particle is sufficiently small that I don't have to worry
// about it. I will also assume that the larger particle's radius will fluctuate
// by an amount that varies with the timestep such that it will "catch" all the
// particles after they have already pierced the shell.
vector<part> hard_sphere(part part_1, part part_2, double timestep){

    // Creating the solutions vector
    vector<part> collision_out;

    vector <part> soln;

    part particle;

    particle.x = 0;
    particle.y = 0;
    particle.z = 0;
    particle.vx = 0;
    particle.vy = 0;
    particle.vz = 0;
    particle.radius = 0;
    particle.mass = 0;

    soln.push_back(particle);
    soln.push_back(particle);

    // This is a time-driven simulation, we will need to define a global
    // variable to ultimately find the final velocity.

    double del_vx = part_2.vx - part_1.vx;
    double del_vy = part_2.vy - part_1.vy;
    double del_vz = part_2.vz - part_1.vz;
    double del_x = part_2.x - part_1.x;
    double del_y = part_2.y - part_1.y;
    double del_z = part_2.z - part_1.z;
    double sigma = part_1.radius + part_2.radius;

    double J = (2 * part_1.mass * part_2.mass *
               ((del_vx * del_x) + (del_vy * del_y) + (del_vz * del_z)) /
               (sigma * (part_1.mass + part_2.mass)));

    // Now we need to perform the collision

    soln[0].vx = part_1.vx + (J * del_x) / (sigma * part_1.mass);
    soln[0].vy = part_1.vy + (J * del_y) / (sigma * part_1.mass);
    soln[0].vz = part_1.vz + (J * del_z) / (sigma * part_1.mass);
    soln[1].vx = part_2.vx + (J * del_x) / (sigma * part_2.mass);
    soln[1].vy = part_2.vy + (J * del_y) / (sigma * part_2.mass);
    soln[1].vz = part_2.vz + (J * del_z) / (sigma * part_2.mass);

    soln[0].mass = part_1.mass;
    soln[0].radius = part_1.radius;
    soln[1].mass = part_2.mass;
    soln[1].radius = part_2.radius;

    soln[0].x = part_1.x + (soln[0].vx * timestep);
    soln[0].y = part_1.y + (soln[0].vy * timestep);
    soln[0].z = part_1.z + (soln[0].vz * timestep);
    soln[1].x = part_2.x + (soln[1].vx * timestep);
    soln[1].y = part_2.y + (soln[1].vy * timestep);
    soln[1].z = part_2.z + (soln[1].vz * timestep);

    // Now, it could be that the particle shoots off the side of the box.
    // Let's fix that.

    for (int q = 0; q <= 1; q++){

        while (soln[q].x > 40){
            soln[q].x -= 40;
        }

        while (soln[q].x < 0){
            soln[q].x += 40;
        }

        while (soln[q].y > 40){
            soln[q].y -= 40;
        }

        while (soln[q].y < 0){
            soln[q].y += 40;
        }

        if (soln[q].z > 40){
            soln[q].z -= 40;
        }

        if (soln[q].z < 0){
            soln[q].z += 40;
        }

    }

    return soln;
}

// The doppler shift stuff will return a 64 X 64 X 64 grid of voxels to use.
// This will have to be written to a file to be used by vbots.
vector<vox_cube> doppler(vector<part> motion_path){
}
<commit_msg>added a few notes for the future once I add in visualization scripts.<commit_after>/*-------------brownian.cpp---------------------------------------------------//
*
*              What Color is BROWNian Motion?
*
* Purpose: This will be a simple Brownian motion simulation. I will throw the
*          results into vbots and get out some 3-d motion and such.
*
*          I will then do some Doppler shift stuff to see how the color changes
*          based on the velocity of the initial particles (assuming they are
*          emitting light and are moving relatively fast).
*
*   State: Currently adding in the hard_sphere collisions. Woo!
*
*   Notes: I should massacre the vbots code and stick it into this by imbedding
*          python into c++ code. This is somewhat documented online. This would
*          mean that I could generate a series of png files rather than output
*          files in the end, saving a good bit or writing time and space.
*
*          When compiling with vbots support (for later), uncomment the
*          following line:
*              #include <Python.h>
*          And add the following flag when compiling:
*              -I/usr/include/python3.4m
*          If the code still does not work, use this command to find flags:
*              python3.4-config --cflags
*          Note that this will have to work with blender nicely...
*          TEST!!!
*
*   ERROR: For some reason, the particles are not moving every timestep...
*          I think this is the expected result when no collision occurs.
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
//#include <Python.h>

using namespace std;

/*----------------------------------------------------------------------------//
* STRUCTURES AND FUNCTIONS
*-----------------------------------------------------------------------------*/

struct part{
    double radius, mass, x, y, z, vx, vy, vz;             // Particle parameters
};

struct vox_cube{
    double x, y, z, intensity;
};

vector<part> simulate(double cube_length, vector<part> particles, int max_time,
                      double timestep);
vector<vox_cube> doppler(vector<part> motion_path);
vector<part> fill_box(int pnum, double cube_length, double max_vel, double r1,
                      double r2, double mass_1, double mass_2);
vector <part> hard_sphere(part part_1, part part_2, double timestep);

/*----------------------------------------------------------------------------//
* MAIN
*-----------------------------------------------------------------------------*/

int main(){

    vector<part> particles = fill_box(400, 40, 1, 1, 5, 0.5, 0.5);
    vector<part> motion_path = simulate(40, particles, 10, 1);

    for (int i = 0; i < motion_path.size(); i++){
        cout << motion_path[i].x << endl;
    }
}

/*----------------------------------------------------------------------------//
* SUBROUTINES
*-----------------------------------------------------------------------------*/

// Function to fill the box with randomly positioned initial particles. Note
// that I should be using random velocities too.
vector<part> fill_box(int pnum, double cube_length, double max_vel, double r1,
                      double r2, double mass_1, double mass_2){

    srand(time(0));
    vector<part> particles;
    part particle;

    // Let's go ahead and set the large particle in the middle
    particle.x = rand() % 10000 * 0.0001 * cube_length;
    particle.y = rand() % 10000 * 0.0001 * cube_length;
    particle.z = rand() % 10000 * 0.0001 * cube_length;
    particle.vx = rand() % 10000 * 0.0001 * max_vel;
    particle.vy = rand() % 10000 * 0.0001 * max_vel;
    particle.vz = rand() % 10000 * 0.0001 * max_vel;
    particle.radius = r2;
    particle.mass = mass_2;

    particles.push_back(particle);

    // Random number generator
    for (int i= 0; i <= pnum; i++){

        particle.x = rand() % 10000 * 0.0001 * cube_length;
            while (particle.x > (particles[0].x - r2) &&
                   particle.x < (particles[0].x + r2)){
                particle.x = rand() % 10000 * 0.0001 * cube_length;
                cout << "check " << i + 1 << endl;
            }

        particle.y = rand() % 10000 * 0.0001 * cube_length;
            while (particle.y > particles[0].y - r2 &&
                   particle.y < particles[0].y + r2){
                particle.y = rand() % 10000 * 0.0001 * cube_length;
            }

        particle.z = rand() % 10000 * 0.0001 * cube_length;
            while (particle.z > particles[0].z - r2 &&
                   particle.z < particles[0].z + r2){
                particle.z = rand() % 10000 * 0.0001 * cube_length;
            }

        particle.vx = rand() % 10000 * 0.0001 * max_vel;
        particle.vy = rand() % 10000 * 0.0001 * max_vel;
        particle.vz = rand() % 10000 * 0.0001 * max_vel;
        particle.radius = r1;
        particle.mass = mass_2;

        particles.push_back(particle);

    }

    for (int i = 0; i < particles.size(); i++){
        cout << i << '\t' << particles[i].x << endl;
    }

    return particles;
}

// This should deal with the interactions of the partiocles.
vector<part> simulate(double box_length, vector<part> particles, int max_time,
                      double timestep){

    // We will certainly have to do a hard sphere collision if any two particles
    // become sufficiently close to each other. We should go ahead and add in
    // a vector of parts...
    vector<part> collision_out, motion_path;
    part particle;

    particle.x = 0;
    particle.y = 0;
    particle.z = 0;
    particle.vx = 0;
    particle.vy = 0;
    particle.vz = 0;
    particle.radius = 0;
    particle.mass = 0;

    collision_out.push_back(particle);
    collision_out.push_back(particle);

    cout << "testing..." << endl;

    // So let's start by moving all the particles forward a single timestep
    for (int i = 0; i < max_time; i++){
        for (int ii = 0; ii < particles.size(); ii++){
            particles[ii].x = particles[ii].vx * timestep;
            if (particles[ii].x > box_length){
                particles[ii].x -= box_length;
            }

            if (particles[ii].x < 0){
                particles[ii].x += box_length;
            }

            particles[ii].y = particles[ii].vy * timestep;
            if (particles[ii].y > box_length){
                particles[ii].y -= box_length;
            }

            if (particles[ii].y < 0){
                particles[ii].y += box_length;
            }

            particles[ii].z = particles[ii].vz * timestep;
            if (particles[ii].z > box_length){
                particles[ii].z -= box_length;
            }

            if (particles[ii].z < 0){
                particles[ii].z += box_length;
            }

            // I really don't like all these nested loops...
            for (int iii = 0; iii < particles.size(); iii++){
                if (particles[ii].x > (particles[iii].x -
                                       particles[iii].radius) &&
                    particles[ii].y > (particles[iii].y -
                                       particles[iii].radius) &&
                    particles[ii].z > (particles[iii].z -
                                       particles[iii].radius) &&
                    particles[ii].x < (particles[iii].x +
                                       particles[iii].radius) &&
                    particles[ii].y < (particles[iii].y +
                                       particles[iii].radius) &&
                    particles[ii].z < (particles[iii].z +
                                       particles[iii].radius)){

                    collision_out = hard_sphere(particles[ii], particles[iii],
                                                timestep);

                    // Now, I might have mixed these guys up. Oops.
                    particles[ii] = collision_out[0];
                    particles[iii] = collision_out[1];
                }
            }

        }

    // Now we need to keep track of the motion path of the large particle. Each
    // element is a timestep
    motion_path.push_back(particles[0]);
    }

return motion_path;
}

// I may need to perform a "hard sphere collision" if the smaller particle is
// within the radius of the larger particle. I think I'll assume that the radius
// of the smaller particle is sufficiently small that I don't have to worry
// about it. I will also assume that the larger particle's radius will fluctuate
// by an amount that varies with the timestep such that it will "catch" all the
// particles after they have already pierced the shell.
vector<part> hard_sphere(part part_1, part part_2, double timestep){

    // Creating the solutions vector
    vector<part> collision_out;

    vector <part> soln;

    part particle;

    particle.x = 0;
    particle.y = 0;
    particle.z = 0;
    particle.vx = 0;
    particle.vy = 0;
    particle.vz = 0;
    particle.radius = 0;
    particle.mass = 0;

    soln.push_back(particle);
    soln.push_back(particle);

    // This is a time-driven simulation, we will need to define a global
    // variable to ultimately find the final velocity.

    double del_vx = part_2.vx - part_1.vx;
    double del_vy = part_2.vy - part_1.vy;
    double del_vz = part_2.vz - part_1.vz;
    double del_x = part_2.x - part_1.x;
    double del_y = part_2.y - part_1.y;
    double del_z = part_2.z - part_1.z;
    double sigma = part_1.radius + part_2.radius;

    double J = (2 * part_1.mass * part_2.mass *
               ((del_vx * del_x) + (del_vy * del_y) + (del_vz * del_z)) /
               (sigma * (part_1.mass + part_2.mass)));

    // Now we need to perform the collision

    soln[0].vx = part_1.vx + (J * del_x) / (sigma * part_1.mass);
    soln[0].vy = part_1.vy + (J * del_y) / (sigma * part_1.mass);
    soln[0].vz = part_1.vz + (J * del_z) / (sigma * part_1.mass);
    soln[1].vx = part_2.vx + (J * del_x) / (sigma * part_2.mass);
    soln[1].vy = part_2.vy + (J * del_y) / (sigma * part_2.mass);
    soln[1].vz = part_2.vz + (J * del_z) / (sigma * part_2.mass);

    soln[0].mass = part_1.mass;
    soln[0].radius = part_1.radius;
    soln[1].mass = part_2.mass;
    soln[1].radius = part_2.radius;

    soln[0].x = part_1.x + (soln[0].vx * timestep);
    soln[0].y = part_1.y + (soln[0].vy * timestep);
    soln[0].z = part_1.z + (soln[0].vz * timestep);
    soln[1].x = part_2.x + (soln[1].vx * timestep);
    soln[1].y = part_2.y + (soln[1].vy * timestep);
    soln[1].z = part_2.z + (soln[1].vz * timestep);

    // Now, it could be that the particle shoots off the side of the box.
    // Let's fix that.

    for (int q = 0; q <= 1; q++){

        while (soln[q].x > 40){
            soln[q].x -= 40;
        }

        while (soln[q].x < 0){
            soln[q].x += 40;
        }

        while (soln[q].y > 40){
            soln[q].y -= 40;
        }

        while (soln[q].y < 0){
            soln[q].y += 40;
        }

        if (soln[q].z > 40){
            soln[q].z -= 40;
        }

        if (soln[q].z < 0){
            soln[q].z += 40;
        }

    }

    return soln;
}

// The doppler shift stuff will return a 64 X 64 X 64 grid of voxels to use.
// This will have to be written to a file to be used by vbots.
vector<vox_cube> doppler(vector<part> motion_path){
}
<|endoftext|>


<commit_before>//===-- LiveIntervalUnion.cpp - Live interval union data structure --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// LiveIntervalUnion represents a coalesced set of live intervals. This may be
// used during coalescing to represent a congruence class, or during register
// allocation to model liveness of a physical register.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "regalloc"
#include "LiveIntervalUnion.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;

// Merge a LiveInterval's segments. Guarantee no overlaps.
void LiveIntervalUnion::unify(LiveInterval &lvr) {
  // Add this live virtual register to the union
  LiveVirtRegs::iterator pos = std::upper_bound(lvrs_.begin(), lvrs_.end(),
                                                &lvr, less_ptr<LiveInterval>());
  assert(pos == lvrs_.end() || *pos != &lvr && "duplicate LVR insertion");
  lvrs_.insert(pos, &lvr);
  // Insert each of the virtual register's live segments into the map
  SegmentIter segPos = segments_.begin();
  for (LiveInterval::iterator lvrI = lvr.begin(), lvrEnd = lvr.end();
       lvrI != lvrEnd; ++lvrI ) {
    LiveSegment segment(lvrI->start, lvrI->end, lvr);
    segPos = segments_.insert(segPos, segment);
    assert(*segPos == segment && "need equal val for equal key");
  }
}

namespace {

// Keep LVRs sorted for fast membership test and extraction.
struct LessReg
  : public std::binary_function<LiveInterval*, LiveInterval*, bool> {
  bool operator()(const LiveInterval *left, const LiveInterval *right) const {
    return left->reg < right->reg;
  }
};

// Low-level helper to find the first segment in the range [segI,segEnd) that
// intersects with a live virtual register segment, or segI.start >= lvr.end
//
// This logic is tied to the underlying LiveSegments data structure. For now, we
// use a binary search within the vector to find the nearest starting position,
// then reverse iterate to find the first overlap.
//
// Upon entry we have segI.start < lvrSeg.end
// seg   |--...
//        \   .
// lvr ...-|
//
// After binary search, we have segI.start >= lvrSeg.start:
// seg   |--...
//      /
// lvr |--...
//
// Assuming intervals are disjoint, if an intersection exists, it must be the
// segment found or immediately behind it. We continue reverse iterating to
// return the first overlap.
//
// FIXME: support extract(), handle tombstones of extracted lvrs.
typedef LiveIntervalUnion::SegmentIter SegmentIter;
SegmentIter upperBound(SegmentIter segBegin,
                       SegmentIter segEnd,
                       const LiveRange &lvrSeg) {
  assert(lvrSeg.end > segBegin->start && "segment iterator precondition");
  // get the next LIU segment such that setg.start is not less than
  // lvrSeg.start
  SegmentIter segI = std::upper_bound(segBegin, segEnd, lvrSeg.start);
  while (segI != segBegin) {
    --segI;
    if (lvrSeg.start >= segI->end)
      return ++segI;
  }
  return segI;
}
} // end anonymous namespace

// Private interface accessed by Query.
//
// Find a pair of segments that intersect, one in the live virtual register
// (LiveInterval), and the other in this LiveIntervalUnion. The caller (Query)
// is responsible for advancing the LiveIntervalUnion segments to find a
// "notable" intersection, which requires query-specific logic.
//
// This design assumes only a fast mechanism for intersecting a single live
// virtual register segment with a set of LiveIntervalUnion segments.  This may
// be ok since most LVRs have very few segments.  If we had a data
// structure that optimizd MxN intersection of segments, then we would bypass
// the loop that advances within the LiveInterval.
//
// If no intersection exists, set lvrI = lvrEnd, and set segI to the first
// segment whose start point is greater than LiveInterval's end point.
//
// Assumes that segments are sorted by start position in both
// LiveInterval and LiveSegments.
void LiveIntervalUnion::Query::findIntersection(InterferenceResult &ir) const {
  LiveInterval::iterator lvrEnd = lvr_.end();
  SegmentIter liuEnd = liu_.end();
  while (ir.liuSegI_ != liuEnd) {
    // Slowly advance the live virtual reg iterator until we surpass the next
    // segment in this union. If this is ever used for coalescing of fixed
    // registers and we have a LiveInterval with thousands of segments, then use
    // upper bound instead.
    while (ir.lvrSegI_ != lvrEnd && ir.lvrSegI_->end <= ir.liuSegI_->start)
      ++ir.lvrSegI_;
    if (ir.lvrSegI_ == lvrEnd)
      break;
    // lvrSegI_ may have advanced far beyond liuSegI_,
    // do a fast intersection test to "catch up"
    ir.liuSegI_ = upperBound(ir.liuSegI_, liuEnd, *ir.lvrSegI_);
    // Check if no liuSegI_ exists with lvrSegI_->start < liuSegI_.end
    if (ir.liuSegI_ == liuEnd)
      break;
    if (ir.liuSegI_->start < ir.lvrSegI_->end) {
      assert(overlap(*ir.lvrSegI_, *ir.liuSegI_) && "upperBound postcondition");
      break;
    }
  }
  if (ir.liuSegI_ == liuEnd)
    ir.lvrSegI_ = lvrEnd;
}

// Find the first intersection, and cache interference info
// (retain segment iterators into both lvr_ and liu_).
LiveIntervalUnion::InterferenceResult
LiveIntervalUnion::Query::firstInterference() {
  if (firstInterference_ != LiveIntervalUnion::InterferenceResult()) {
    return firstInterference_;
  }
  firstInterference_ = InterferenceResult(lvr_.begin(), liu_.begin());
  findIntersection(firstInterference_);
  return firstInterference_;
}

// Treat the result as an iterator and advance to the next interfering pair
// of segments. This is a plain iterator with no filter.
bool LiveIntervalUnion::Query::nextInterference(InterferenceResult &ir) const {
  assert(isInterference(ir) && "iteration past end of interferences");
  // Advance either the lvr or liu segment to ensure that we visit all unique
  // overlapping pairs.
  if (ir.lvrSegI_->end < ir.liuSegI_->end) {
    if (++ir.lvrSegI_ == lvr_.end())
      return false;
  }
  else {
    if (++ir.liuSegI_ == liu_.end()) {
      ir.lvrSegI_ = lvr_.end();
      return false;
    }
  }
  if (overlap(*ir.lvrSegI_, *ir.liuSegI_))
    return true;
  // find the next intersection
  findIntersection(ir);
  return isInterference(ir);
}
<commit_msg>Fix a likely bug in an assertion by adding parentheses around '||'. This bug was found by a GCC warning. ;]<commit_after>//===-- LiveIntervalUnion.cpp - Live interval union data structure --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// LiveIntervalUnion represents a coalesced set of live intervals. This may be
// used during coalescing to represent a congruence class, or during register
// allocation to model liveness of a physical register.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "regalloc"
#include "LiveIntervalUnion.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;

// Merge a LiveInterval's segments. Guarantee no overlaps.
void LiveIntervalUnion::unify(LiveInterval &lvr) {
  // Add this live virtual register to the union
  LiveVirtRegs::iterator pos = std::upper_bound(lvrs_.begin(), lvrs_.end(),
                                                &lvr, less_ptr<LiveInterval>());
  assert((pos == lvrs_.end() || *pos != &lvr) && "duplicate LVR insertion");
  lvrs_.insert(pos, &lvr);
  // Insert each of the virtual register's live segments into the map
  SegmentIter segPos = segments_.begin();
  for (LiveInterval::iterator lvrI = lvr.begin(), lvrEnd = lvr.end();
       lvrI != lvrEnd; ++lvrI ) {
    LiveSegment segment(lvrI->start, lvrI->end, lvr);
    segPos = segments_.insert(segPos, segment);
    assert(*segPos == segment && "need equal val for equal key");
  }
}

namespace {

// Keep LVRs sorted for fast membership test and extraction.
struct LessReg
  : public std::binary_function<LiveInterval*, LiveInterval*, bool> {
  bool operator()(const LiveInterval *left, const LiveInterval *right) const {
    return left->reg < right->reg;
  }
};

// Low-level helper to find the first segment in the range [segI,segEnd) that
// intersects with a live virtual register segment, or segI.start >= lvr.end
//
// This logic is tied to the underlying LiveSegments data structure. For now, we
// use a binary search within the vector to find the nearest starting position,
// then reverse iterate to find the first overlap.
//
// Upon entry we have segI.start < lvrSeg.end
// seg   |--...
//        \   .
// lvr ...-|
//
// After binary search, we have segI.start >= lvrSeg.start:
// seg   |--...
//      /
// lvr |--...
//
// Assuming intervals are disjoint, if an intersection exists, it must be the
// segment found or immediately behind it. We continue reverse iterating to
// return the first overlap.
//
// FIXME: support extract(), handle tombstones of extracted lvrs.
typedef LiveIntervalUnion::SegmentIter SegmentIter;
SegmentIter upperBound(SegmentIter segBegin,
                       SegmentIter segEnd,
                       const LiveRange &lvrSeg) {
  assert(lvrSeg.end > segBegin->start && "segment iterator precondition");
  // get the next LIU segment such that setg.start is not less than
  // lvrSeg.start
  SegmentIter segI = std::upper_bound(segBegin, segEnd, lvrSeg.start);
  while (segI != segBegin) {
    --segI;
    if (lvrSeg.start >= segI->end)
      return ++segI;
  }
  return segI;
}
} // end anonymous namespace

// Private interface accessed by Query.
//
// Find a pair of segments that intersect, one in the live virtual register
// (LiveInterval), and the other in this LiveIntervalUnion. The caller (Query)
// is responsible for advancing the LiveIntervalUnion segments to find a
// "notable" intersection, which requires query-specific logic.
//
// This design assumes only a fast mechanism for intersecting a single live
// virtual register segment with a set of LiveIntervalUnion segments.  This may
// be ok since most LVRs have very few segments.  If we had a data
// structure that optimizd MxN intersection of segments, then we would bypass
// the loop that advances within the LiveInterval.
//
// If no intersection exists, set lvrI = lvrEnd, and set segI to the first
// segment whose start point is greater than LiveInterval's end point.
//
// Assumes that segments are sorted by start position in both
// LiveInterval and LiveSegments.
void LiveIntervalUnion::Query::findIntersection(InterferenceResult &ir) const {
  LiveInterval::iterator lvrEnd = lvr_.end();
  SegmentIter liuEnd = liu_.end();
  while (ir.liuSegI_ != liuEnd) {
    // Slowly advance the live virtual reg iterator until we surpass the next
    // segment in this union. If this is ever used for coalescing of fixed
    // registers and we have a LiveInterval with thousands of segments, then use
    // upper bound instead.
    while (ir.lvrSegI_ != lvrEnd && ir.lvrSegI_->end <= ir.liuSegI_->start)
      ++ir.lvrSegI_;
    if (ir.lvrSegI_ == lvrEnd)
      break;
    // lvrSegI_ may have advanced far beyond liuSegI_,
    // do a fast intersection test to "catch up"
    ir.liuSegI_ = upperBound(ir.liuSegI_, liuEnd, *ir.lvrSegI_);
    // Check if no liuSegI_ exists with lvrSegI_->start < liuSegI_.end
    if (ir.liuSegI_ == liuEnd)
      break;
    if (ir.liuSegI_->start < ir.lvrSegI_->end) {
      assert(overlap(*ir.lvrSegI_, *ir.liuSegI_) && "upperBound postcondition");
      break;
    }
  }
  if (ir.liuSegI_ == liuEnd)
    ir.lvrSegI_ = lvrEnd;
}

// Find the first intersection, and cache interference info
// (retain segment iterators into both lvr_ and liu_).
LiveIntervalUnion::InterferenceResult
LiveIntervalUnion::Query::firstInterference() {
  if (firstInterference_ != LiveIntervalUnion::InterferenceResult()) {
    return firstInterference_;
  }
  firstInterference_ = InterferenceResult(lvr_.begin(), liu_.begin());
  findIntersection(firstInterference_);
  return firstInterference_;
}

// Treat the result as an iterator and advance to the next interfering pair
// of segments. This is a plain iterator with no filter.
bool LiveIntervalUnion::Query::nextInterference(InterferenceResult &ir) const {
  assert(isInterference(ir) && "iteration past end of interferences");
  // Advance either the lvr or liu segment to ensure that we visit all unique
  // overlapping pairs.
  if (ir.lvrSegI_->end < ir.liuSegI_->end) {
    if (++ir.lvrSegI_ == lvr_.end())
      return false;
  }
  else {
    if (++ir.liuSegI_ == liu_.end()) {
      ir.lvrSegI_ = lvr_.end();
      return false;
    }
  }
  if (overlap(*ir.lvrSegI_, *ir.liuSegI_))
    return true;
  // find the next intersection
  findIntersection(ir);
  return isInterference(ir);
}
<|endoftext|>


<commit_before>//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "DWARFDebugFrame.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"

using namespace llvm;
using namespace dwarf;

class llvm::FrameEntry {
public:
  enum FrameKind {FK_CIE, FK_FDE};
  FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length)
    : Kind(K), Data(D), Offset(Offset), Length(Length) {}

  virtual ~FrameEntry() {
  }

  FrameKind getKind() const { return Kind; }

  virtual void dumpHeader(raw_ostream &OS) const = 0;

protected:
  const FrameKind Kind;

  /// \brief The data stream holding the section from which the entry was
  /// parsed.
  DataExtractor Data;

  /// \brief Offset of this entry in the section.
  uint64_t Offset;

  /// \brief Entry length as specified in DWARF.
  uint64_t Length;
};

class CIE : public FrameEntry {
public:
  // CIEs (and FDEs) are simply container classes, so the only sensible way to
  // create them is by providing the full parsed contents in the constructor.
  CIE(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version,
      SmallString<8> Augmentation, uint64_t CodeAlignmentFactor,
      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
   : FrameEntry(FK_CIE, D, Offset, Length), Version(Version),
     Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor),
     DataAlignmentFactor(DataAlignmentFactor),
     ReturnAddressRegister(ReturnAddressRegister) {}

  ~CIE() {
  }

  void dumpHeader(raw_ostream &OS) const {
    OS << format("%08x %08x %08x CIE", Offset, Length, DW_CIE_ID) << "\n";
    OS << format("  Version:               %d\n", Version);
    OS << "  Augmentation:          \"" << Augmentation << "\"\n";
    OS << format("  Code alignment factor: %u\n", CodeAlignmentFactor);
    OS << format("  Data alignment factor: %d\n", DataAlignmentFactor);
    OS << format("  Return address column: %d\n", ReturnAddressRegister);
    OS << "\n";
  }

  static bool classof(const FrameEntry *FE) {
    return FE->getKind() == FK_CIE;
  }

private:
  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
  uint8_t Version;
  SmallString<8> Augmentation;
  uint64_t CodeAlignmentFactor;
  int64_t DataAlignmentFactor;
  uint64_t ReturnAddressRegister;
};

class FDE : public FrameEntry {
public:
  // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
  // an offset to the CIE (provided by parsing the FDE header). The CIE itself
  // is obtained lazily once it's actually required.
  FDE(DataExtractor D, uint64_t Offset, uint64_t Length,
      int64_t LinkedCIEOffset, uint64_t InitialLocation, uint64_t AddressRange)
   : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset),
     InitialLocation(InitialLocation), AddressRange(AddressRange),
     LinkedCIE(NULL) {}

  ~FDE() {
  }

  void dumpHeader(raw_ostream &OS) const {
    OS << format("%08x %08x %08x FDE ", Offset, Length, LinkedCIEOffset);
    OS << format("cie=%08x pc=%08x...%08x\n",
                 LinkedCIEOffset, InitialLocation,
                 InitialLocation + AddressRange);
    OS << "\n";
  }

  static bool classof(const FrameEntry *FE) {
    return FE->getKind() == FK_FDE;
  }
private:

  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
  uint64_t LinkedCIEOffset;
  uint64_t InitialLocation;
  uint64_t AddressRange;
  CIE *LinkedCIE;
};

DWARFDebugFrame::DWARFDebugFrame() {
}

DWARFDebugFrame::~DWARFDebugFrame() {
  for (EntryVector::iterator I = Entries.begin(), E = Entries.end();
       I != E; ++I) {
    delete *I;
  }
}

static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
                                              uint32_t Offset, int Length) {
  errs() << "DUMP: ";
  for (int i = 0; i < Length; ++i) {
    uint8_t c = Data.getU8(&Offset);
    errs().write_hex(c); errs() << " ";
  }
  errs() << "\n";
}

void DWARFDebugFrame::parse(DataExtractor Data) {
  uint32_t Offset = 0;

  while (Data.isValidOffset(Offset)) {
    uint32_t StartOffset = Offset;

    bool IsDWARF64 = false;
    uint64_t Length = Data.getU32(&Offset);
    uint64_t Id;

    if (Length == UINT32_MAX) {
      // DWARF-64 is distinguished by the first 32 bits of the initial length
      // field being 0xffffffff. Then, the next 64 bits are the actual entry
      // length.
      IsDWARF64 = true;
      Length = Data.getU64(&Offset);
    }

    // At this point, Offset points to the next field after Length.
    // Length is the structure size excluding itself. Compute an offset one
    // past the end of the structure (needed to know how many instructions to
    // read).
    // TODO: For honest DWARF64 support, DataExtractor will have to treat
    //       offset_ptr as uint64_t*
    uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);

    // The Id field's size depends on the DWARF format
    Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4);
    bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID);

    if (IsCIE) {
      // Note: this is specifically DWARFv3 CIE header structure. It was
      // changed in DWARFv4.
      uint8_t Version = Data.getU8(&Offset);
      const char *Augmentation = Data.getCStr(&Offset);
      uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
      int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
      uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);

      CIE *NewCIE = new CIE(Data, StartOffset, Length, Version,
                            StringRef(Augmentation), CodeAlignmentFactor,
                            DataAlignmentFactor, ReturnAddressRegister);
      Entries.push_back(NewCIE);
    } else {
      // FDE
      uint64_t CIEPointer = Id;
      uint64_t InitialLocation = Data.getAddress(&Offset);
      uint64_t AddressRange = Data.getAddress(&Offset);

      FDE *NewFDE = new FDE(Data, StartOffset, Length, CIEPointer,
                            InitialLocation, AddressRange);
      Entries.push_back(NewFDE);
    }

    Offset = EndStructureOffset;
  }
}

void DWARFDebugFrame::dump(raw_ostream &OS) const {
  OS << "\n";
  for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end();
       I != E; ++I) {
    (*I)->dumpHeader(OS);
  }
}

<commit_msg>Failing builds because a private class member is not being used after initialization is one of the reasons I consider -werror to be shoddy.<commit_after>//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "DWARFDebugFrame.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"

using namespace llvm;
using namespace dwarf;

class llvm::FrameEntry {
public:
  enum FrameKind {FK_CIE, FK_FDE};
  FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length)
    : Kind(K), Data(D), Offset(Offset), Length(Length) {}

  virtual ~FrameEntry() {
  }

  FrameKind getKind() const { return Kind; }

  virtual void dumpHeader(raw_ostream &OS) const = 0;

protected:
  const FrameKind Kind;

  /// \brief The data stream holding the section from which the entry was
  /// parsed.
  DataExtractor Data;

  /// \brief Offset of this entry in the section.
  uint64_t Offset;

  /// \brief Entry length as specified in DWARF.
  uint64_t Length;
};

class CIE : public FrameEntry {
public:
  // CIEs (and FDEs) are simply container classes, so the only sensible way to
  // create them is by providing the full parsed contents in the constructor.
  CIE(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version,
      SmallString<8> Augmentation, uint64_t CodeAlignmentFactor,
      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
   : FrameEntry(FK_CIE, D, Offset, Length), Version(Version),
     Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor),
     DataAlignmentFactor(DataAlignmentFactor),
     ReturnAddressRegister(ReturnAddressRegister) {}

  ~CIE() {
  }

  void dumpHeader(raw_ostream &OS) const {
    OS << format("%08x %08x %08x CIE", Offset, Length, DW_CIE_ID) << "\n";
    OS << format("  Version:               %d\n", Version);
    OS << "  Augmentation:          \"" << Augmentation << "\"\n";
    OS << format("  Code alignment factor: %u\n", CodeAlignmentFactor);
    OS << format("  Data alignment factor: %d\n", DataAlignmentFactor);
    OS << format("  Return address column: %d\n", ReturnAddressRegister);
    OS << "\n";
  }

  static bool classof(const FrameEntry *FE) {
    return FE->getKind() == FK_CIE;
  }

private:
  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
  uint8_t Version;
  SmallString<8> Augmentation;
  uint64_t CodeAlignmentFactor;
  int64_t DataAlignmentFactor;
  uint64_t ReturnAddressRegister;
};

class FDE : public FrameEntry {
public:
  // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
  // an offset to the CIE (provided by parsing the FDE header). The CIE itself
  // is obtained lazily once it's actually required.
  FDE(DataExtractor D, uint64_t Offset, uint64_t Length,
      int64_t LinkedCIEOffset, uint64_t InitialLocation, uint64_t AddressRange)
   : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset),
     InitialLocation(InitialLocation), AddressRange(AddressRange),
     LinkedCIE(NULL) {}

  ~FDE() {
  }

  void dumpHeader(raw_ostream &OS) const {
    OS << format("%08x %08x %08x FDE ", Offset, Length, LinkedCIEOffset);
    OS << format("cie=%08x pc=%08x...%08x\n",
                 LinkedCIEOffset, InitialLocation,
                 InitialLocation + AddressRange);
    OS << "\n";
    if (LinkedCIE) {
      OS << format("%p\n", LinkedCIE);
    }
  }

  static bool classof(const FrameEntry *FE) {
    return FE->getKind() == FK_FDE;
  }
private:

  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
  uint64_t LinkedCIEOffset;
  uint64_t InitialLocation;
  uint64_t AddressRange;
  CIE *LinkedCIE;
};

DWARFDebugFrame::DWARFDebugFrame() {
}

DWARFDebugFrame::~DWARFDebugFrame() {
  for (EntryVector::iterator I = Entries.begin(), E = Entries.end();
       I != E; ++I) {
    delete *I;
  }
}

static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
                                              uint32_t Offset, int Length) {
  errs() << "DUMP: ";
  for (int i = 0; i < Length; ++i) {
    uint8_t c = Data.getU8(&Offset);
    errs().write_hex(c); errs() << " ";
  }
  errs() << "\n";
}

void DWARFDebugFrame::parse(DataExtractor Data) {
  uint32_t Offset = 0;

  while (Data.isValidOffset(Offset)) {
    uint32_t StartOffset = Offset;

    bool IsDWARF64 = false;
    uint64_t Length = Data.getU32(&Offset);
    uint64_t Id;

    if (Length == UINT32_MAX) {
      // DWARF-64 is distinguished by the first 32 bits of the initial length
      // field being 0xffffffff. Then, the next 64 bits are the actual entry
      // length.
      IsDWARF64 = true;
      Length = Data.getU64(&Offset);
    }

    // At this point, Offset points to the next field after Length.
    // Length is the structure size excluding itself. Compute an offset one
    // past the end of the structure (needed to know how many instructions to
    // read).
    // TODO: For honest DWARF64 support, DataExtractor will have to treat
    //       offset_ptr as uint64_t*
    uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);

    // The Id field's size depends on the DWARF format
    Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4);
    bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID);

    if (IsCIE) {
      // Note: this is specifically DWARFv3 CIE header structure. It was
      // changed in DWARFv4.
      uint8_t Version = Data.getU8(&Offset);
      const char *Augmentation = Data.getCStr(&Offset);
      uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
      int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
      uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);

      CIE *NewCIE = new CIE(Data, StartOffset, Length, Version,
                            StringRef(Augmentation), CodeAlignmentFactor,
                            DataAlignmentFactor, ReturnAddressRegister);
      Entries.push_back(NewCIE);
    } else {
      // FDE
      uint64_t CIEPointer = Id;
      uint64_t InitialLocation = Data.getAddress(&Offset);
      uint64_t AddressRange = Data.getAddress(&Offset);

      FDE *NewFDE = new FDE(Data, StartOffset, Length, CIEPointer,
                            InitialLocation, AddressRange);
      Entries.push_back(NewFDE);
    }

    Offset = EndStructureOffset;
  }
}

void DWARFDebugFrame::dump(raw_ostream &OS) const {
  OS << "\n";
  for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end();
       I != E; ++I) {
    (*I)->dumpHeader(OS);
  }
}

<|endoftext|>


<commit_before>//===--- OpenBSD.cpp - OpenBSD ToolChain Implementations --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "OpenBSD.h"
#include "Arch/Mips.h"
#include "Arch/Sparc.h"
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"

using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
                                      const InputInfo &Output,
                                      const InputInfoList &Inputs,
                                      const ArgList &Args,
                                      const char *LinkingOutput) const {
  claimNoWarnArgs(Args);
  ArgStringList CmdArgs;

  switch (getToolChain().getArch()) {
  case llvm::Triple::x86:
    // When building 32-bit code on OpenBSD/amd64, we have to explicitly
    // instruct as in the base system to assemble 32-bit code.
    CmdArgs.push_back("--32");
    break;

  case llvm::Triple::ppc:
    CmdArgs.push_back("-mppc");
    CmdArgs.push_back("-many");
    break;

  case llvm::Triple::sparc:
  case llvm::Triple::sparcel: {
    CmdArgs.push_back("-32");
    std::string CPU = getCPUName(Args, getToolChain().getTriple());
    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
    AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
    break;
  }

  case llvm::Triple::sparcv9: {
    CmdArgs.push_back("-64");
    std::string CPU = getCPUName(Args, getToolChain().getTriple());
    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
    AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
    break;
  }

  case llvm::Triple::mips64:
  case llvm::Triple::mips64el: {
    StringRef CPUName;
    StringRef ABIName;
    mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);

    CmdArgs.push_back("-mabi");
    CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());

    if (getToolChain().getTriple().isLittleEndian())
      CmdArgs.push_back("-EL");
    else
      CmdArgs.push_back("-EB");

    AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
    break;
  }

  default:
    break;
  }

  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);

  CmdArgs.push_back("-o");
  CmdArgs.push_back(Output.getFilename());

  for (const auto &II : Inputs)
    CmdArgs.push_back(II.getFilename());

  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}

void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
                                   const InputInfo &Output,
                                   const InputInfoList &Inputs,
                                   const ArgList &Args,
                                   const char *LinkingOutput) const {
  const toolchains::OpenBSD &ToolChain =
      static_cast<const toolchains::OpenBSD &>(getToolChain());
  const Driver &D = getToolChain().getDriver();
  ArgStringList CmdArgs;

  // Silence warning for "clang -g foo.o -o foo"
  Args.ClaimAllArgs(options::OPT_g_Group);
  // and "clang -emit-llvm foo.o -o foo"
  Args.ClaimAllArgs(options::OPT_emit_llvm);
  // and for "clang -w foo.o -o foo". Other warning options are already
  // handled somewhere else.
  Args.ClaimAllArgs(options::OPT_w);

  if (ToolChain.getArch() == llvm::Triple::mips64)
    CmdArgs.push_back("-EB");
  else if (ToolChain.getArch() == llvm::Triple::mips64el)
    CmdArgs.push_back("-EL");

  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
    CmdArgs.push_back("-e");
    CmdArgs.push_back("__start");
  }

  CmdArgs.push_back("--eh-frame-hdr");
  if (Args.hasArg(options::OPT_static)) {
    CmdArgs.push_back("-Bstatic");
  } else {
    if (Args.hasArg(options::OPT_rdynamic))
      CmdArgs.push_back("-export-dynamic");
    CmdArgs.push_back("-Bdynamic");
    if (Args.hasArg(options::OPT_shared)) {
      CmdArgs.push_back("-shared");
    } else {
      CmdArgs.push_back("-dynamic-linker");
      CmdArgs.push_back("/usr/libexec/ld.so");
    }
  }

  if (Args.hasArg(options::OPT_pie))
    CmdArgs.push_back("-pie");
  if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg))
    CmdArgs.push_back("-nopie");

  if (Output.isFilename()) {
    CmdArgs.push_back("-o");
    CmdArgs.push_back(Output.getFilename());
  } else {
    assert(Output.isNothing() && "Invalid output.");
  }

  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
    const char *crt0 = nullptr;
    const char *crtbegin = nullptr;
    if (!Args.hasArg(options::OPT_shared)) {
      if (Args.hasArg(options::OPT_pg))
        crt0 = "gcrt0.o";
      else if (Args.hasArg(options::OPT_static) &&
               !Args.hasArg(options::OPT_nopie))
        crt0 = "rcrt0.o";
      else
        crt0 = "crt0.o";
      crtbegin = "crtbegin.o";
    } else {
      crtbegin = "crtbeginS.o";
    }

    if (crt0)
      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0)));
    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
  }

  Args.AddAllArgs(CmdArgs, options::OPT_L);
  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
  Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e,
                            options::OPT_s, options::OPT_t,
                            options::OPT_Z_Flag, options::OPT_r});

  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);

  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
    if (D.CCCIsCXX()) {
      if (ToolChain.ShouldLinkCXXStdlib(Args))
        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
      if (Args.hasArg(options::OPT_pg))
        CmdArgs.push_back("-lm_p");
      else
        CmdArgs.push_back("-lm");
    }
    if (NeedsSanitizerDeps) {
      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
      linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
    }
    if (NeedsXRayDeps) {
      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
      linkXRayRuntimeDeps(ToolChain, CmdArgs);
    }
    // FIXME: For some reason GCC passes -lgcc before adding
    // the default system libraries. Just mimic this for now.
    CmdArgs.push_back("-lcompiler_rt");

    if (Args.hasArg(options::OPT_pthread)) {
      if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
        CmdArgs.push_back("-lpthread_p");
      else
        CmdArgs.push_back("-lpthread");
    }

    if (!Args.hasArg(options::OPT_shared)) {
      if (Args.hasArg(options::OPT_pg))
        CmdArgs.push_back("-lc_p");
      else
        CmdArgs.push_back("-lc");
    }

    CmdArgs.push_back("-lcompiler_rt");
  }

  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
    const char *crtend = nullptr;
    if (!Args.hasArg(options::OPT_shared))
      crtend = "crtend.o";
    else
      crtend = "crtendS.o";

    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
  }

  const char *Exec = Args.MakeArgString(
      !NeedsSanitizerDeps ? ToolChain.GetLinkerPath()
                          : ToolChain.GetProgramPath("ld.lld"));
  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}

SanitizerMask OpenBSD::getSupportedSanitizers() const {
  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;

  // For future use, only UBsan at the moment
  SanitizerMask Res = ToolChain::getSupportedSanitizers();

  if (IsX86 || IsX86_64) {
    Res |= SanitizerKind::Vptr;
    Res |= SanitizerKind::Fuzzer;
    Res |= SanitizerKind::FuzzerNoLink;
  }

  return Res;
}

/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.

OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple,
                 const ArgList &Args)
    : Generic_ELF(D, Triple, Args) {
  getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
}

void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
                                  ArgStringList &CmdArgs) const {
  bool Profiling = Args.hasArg(options::OPT_pg);

  CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
  CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
}

Tool *OpenBSD::buildAssembler() const {
  return new tools::openbsd::Assembler(*this);
}

Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
<commit_msg>Remove sanitizer context workaround no longer necessary<commit_after>//===--- OpenBSD.cpp - OpenBSD ToolChain Implementations --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "OpenBSD.h"
#include "Arch/Mips.h"
#include "Arch/Sparc.h"
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"

using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
                                      const InputInfo &Output,
                                      const InputInfoList &Inputs,
                                      const ArgList &Args,
                                      const char *LinkingOutput) const {
  claimNoWarnArgs(Args);
  ArgStringList CmdArgs;

  switch (getToolChain().getArch()) {
  case llvm::Triple::x86:
    // When building 32-bit code on OpenBSD/amd64, we have to explicitly
    // instruct as in the base system to assemble 32-bit code.
    CmdArgs.push_back("--32");
    break;

  case llvm::Triple::ppc:
    CmdArgs.push_back("-mppc");
    CmdArgs.push_back("-many");
    break;

  case llvm::Triple::sparc:
  case llvm::Triple::sparcel: {
    CmdArgs.push_back("-32");
    std::string CPU = getCPUName(Args, getToolChain().getTriple());
    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
    AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
    break;
  }

  case llvm::Triple::sparcv9: {
    CmdArgs.push_back("-64");
    std::string CPU = getCPUName(Args, getToolChain().getTriple());
    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
    AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
    break;
  }

  case llvm::Triple::mips64:
  case llvm::Triple::mips64el: {
    StringRef CPUName;
    StringRef ABIName;
    mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);

    CmdArgs.push_back("-mabi");
    CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());

    if (getToolChain().getTriple().isLittleEndian())
      CmdArgs.push_back("-EL");
    else
      CmdArgs.push_back("-EB");

    AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
    break;
  }

  default:
    break;
  }

  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);

  CmdArgs.push_back("-o");
  CmdArgs.push_back(Output.getFilename());

  for (const auto &II : Inputs)
    CmdArgs.push_back(II.getFilename());

  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}

void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
                                   const InputInfo &Output,
                                   const InputInfoList &Inputs,
                                   const ArgList &Args,
                                   const char *LinkingOutput) const {
  const toolchains::OpenBSD &ToolChain =
      static_cast<const toolchains::OpenBSD &>(getToolChain());
  const Driver &D = getToolChain().getDriver();
  ArgStringList CmdArgs;

  // Silence warning for "clang -g foo.o -o foo"
  Args.ClaimAllArgs(options::OPT_g_Group);
  // and "clang -emit-llvm foo.o -o foo"
  Args.ClaimAllArgs(options::OPT_emit_llvm);
  // and for "clang -w foo.o -o foo". Other warning options are already
  // handled somewhere else.
  Args.ClaimAllArgs(options::OPT_w);

  if (ToolChain.getArch() == llvm::Triple::mips64)
    CmdArgs.push_back("-EB");
  else if (ToolChain.getArch() == llvm::Triple::mips64el)
    CmdArgs.push_back("-EL");

  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
    CmdArgs.push_back("-e");
    CmdArgs.push_back("__start");
  }

  CmdArgs.push_back("--eh-frame-hdr");
  if (Args.hasArg(options::OPT_static)) {
    CmdArgs.push_back("-Bstatic");
  } else {
    if (Args.hasArg(options::OPT_rdynamic))
      CmdArgs.push_back("-export-dynamic");
    CmdArgs.push_back("-Bdynamic");
    if (Args.hasArg(options::OPT_shared)) {
      CmdArgs.push_back("-shared");
    } else {
      CmdArgs.push_back("-dynamic-linker");
      CmdArgs.push_back("/usr/libexec/ld.so");
    }
  }

  if (Args.hasArg(options::OPT_pie))
    CmdArgs.push_back("-pie");
  if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg))
    CmdArgs.push_back("-nopie");

  if (Output.isFilename()) {
    CmdArgs.push_back("-o");
    CmdArgs.push_back(Output.getFilename());
  } else {
    assert(Output.isNothing() && "Invalid output.");
  }

  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
    const char *crt0 = nullptr;
    const char *crtbegin = nullptr;
    if (!Args.hasArg(options::OPT_shared)) {
      if (Args.hasArg(options::OPT_pg))
        crt0 = "gcrt0.o";
      else if (Args.hasArg(options::OPT_static) &&
               !Args.hasArg(options::OPT_nopie))
        crt0 = "rcrt0.o";
      else
        crt0 = "crt0.o";
      crtbegin = "crtbegin.o";
    } else {
      crtbegin = "crtbeginS.o";
    }

    if (crt0)
      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0)));
    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
  }

  Args.AddAllArgs(CmdArgs, options::OPT_L);
  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
  Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e,
                            options::OPT_s, options::OPT_t,
                            options::OPT_Z_Flag, options::OPT_r});

  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);

  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
    if (D.CCCIsCXX()) {
      if (ToolChain.ShouldLinkCXXStdlib(Args))
        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
      if (Args.hasArg(options::OPT_pg))
        CmdArgs.push_back("-lm_p");
      else
        CmdArgs.push_back("-lm");
    }
    if (NeedsSanitizerDeps) {
      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
      linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
    }
    if (NeedsXRayDeps) {
      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
      linkXRayRuntimeDeps(ToolChain, CmdArgs);
    }
    // FIXME: For some reason GCC passes -lgcc before adding
    // the default system libraries. Just mimic this for now.
    CmdArgs.push_back("-lcompiler_rt");

    if (Args.hasArg(options::OPT_pthread)) {
      if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
        CmdArgs.push_back("-lpthread_p");
      else
        CmdArgs.push_back("-lpthread");
    }

    if (!Args.hasArg(options::OPT_shared)) {
      if (Args.hasArg(options::OPT_pg))
        CmdArgs.push_back("-lc_p");
      else
        CmdArgs.push_back("-lc");
    }

    CmdArgs.push_back("-lcompiler_rt");
  }

  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
    const char *crtend = nullptr;
    if (!Args.hasArg(options::OPT_shared))
      crtend = "crtend.o";
    else
      crtend = "crtendS.o";

    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
  }

  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}

SanitizerMask OpenBSD::getSupportedSanitizers() const {
  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;

  // For future use, only UBsan at the moment
  SanitizerMask Res = ToolChain::getSupportedSanitizers();

  if (IsX86 || IsX86_64) {
    Res |= SanitizerKind::Vptr;
    Res |= SanitizerKind::Fuzzer;
    Res |= SanitizerKind::FuzzerNoLink;
  }

  return Res;
}

/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.

OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple,
                 const ArgList &Args)
    : Generic_ELF(D, Triple, Args) {
  getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
}

void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
                                  ArgStringList &CmdArgs) const {
  bool Profiling = Args.hasArg(options::OPT_pg);

  CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
  CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
}

Tool *OpenBSD::buildAssembler() const {
  return new tools::openbsd::Assembler(*this);
}

Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
<|endoftext|>