<commit_before>#include "Event.h"
#include "script/ScriptClassParser.h"
#include "scene/managers/SceneStackManager.h"
#include "scene/sprites/ScriptableSpriteActor.h"
#include "widgets/Widget.h"
#include "widgets/Layouters/StackWidget.h"

using namespace MX;

class ReturnEvent : public Event
{
public:
	ReturnEvent(const std::string& objectName) : Event(objectName)
	{
		load_property_child(_value, "Value");
	}

	void Do() override
	{
		if (!Context<EventInfo>::isCurrent())
			return;

		auto &info = Context<EventInfo>::current();
		info.returnValue = _value;
	}

protected:
	int _value = 0;
};

class IfEvent : public Event
{
public:
	IfEvent(const std::string& objectName) : Event(objectName)
	{
		load_property(_condition, "Condition");
		load_property_children(_thenEvents, "Then");
		load_property(_elseEvents, "Else");
	}

	void Do() override
	{
		float value = *_condition;

		if (value)
			_thenEvents.Do();
		else
			_elseEvents.Do();
	}

protected:
	Scriptable::Value::pointer _condition;
	MX::EventHolder   _thenEvents;
	MX::EventHolder   _elseEvents;
};

class DoEvent : public Event
{
public:
	DoEvent(const std::string& objectName) : Event(objectName)
	{
		load_property_child(_do, "Do");
	}

	void Do() override
	{
		float value = *_do;
	}
protected:
	Scriptable::Value::pointer _do;
};

class OnRunEvent : public Event
{
public:

	OnRunEvent(const std::string& objectName) : Event(objectName)
	{
		load_property_children(onRun, "Commands");
	}

	void Do() override
	{
		auto &actor = Context<ScriptableSpriteActor>::current();
		actor.script.onRun += onRun;
	}
protected:
	CommandSignal onRun;
};

class StackWidgetPopEvent : public Event
{
public:
	using Event::Event;

	void Do() override
	{
		auto &widget = Context<MX::Widgets::Widget>::current();
		auto stack = MX::Widgets::StackWidget::stack_of(&widget);
		if (stack)
			stack->PopWidget();
	}

};

class SpriteSceneStackManagerPopEvent : public Event
{
public:
	using Event::Event;

	void Do() override
	{
		auto &sprite = ScriptableSpriteActor::current();
		SpriteSceneStackManager::PopOnManagerOf(&sprite);
	}

};

class CreateSpriteAtSprite : public Event
{
public:
    CreateSpriteAtSprite(const std::string& objectName) : Event(objectName)
    {
        load_property_child(_actor, "Sprite");
        load_property(_rotateToCurrent, "RotateToCurrent");
    }

    void Do()
    {
        if (!ScriptableSpriteActor::isCurrent())
            return;

        if (!_actor)
            return;
        auto actor = _actor->cloneSprite();

        actor->geometry.position = ScriptableSpriteActor::current().geometry.position;

        if (_rotateToCurrent)
            actor->geometry.angle = ScriptableSpriteActor::current().geometry.angle;

        ScriptableSpriteActor::current().sprite_scene().AddActor(actor);
    }

protected:
    std::shared_ptr<MX::ScriptableSpriteActor> _actor;
    bool _rotateToCurrent = false;
};

class SoundEffectEvent : public Event
{
public:
    SoundEffectEvent(const std::string& objectName) : Event(objectName)
    {
        load_property_child(_sound, "Sound");
    }

    void Do()
    {
        if (_sound)
            _sound->sound()->Play();
    }

protected:
    std::shared_ptr<MX::ScriptSoundClass> _sound;
};

void EventInit::Init()
{
	ScriptClassParser::AddCreator(L"Event.Return", new DefaultClassCreatorContructor<ReturnEvent>());
	ScriptClassParser::AddCreator(L"Event.If", new DefaultClassCreatorContructor<IfEvent>());
	ScriptClassParser::AddCreator(L"Event.Do", new DefaultClassCreatorContructor<DoEvent>());
	ScriptClassParser::AddCreator(L"Event.OnRun", new DefaultClassCreatorContructor<OnRunEvent>());

	ScriptClassParser::AddCreator(L"Event.StackWidget.Pop", new DefaultClassCreatorContructor<StackWidgetPopEvent>());

	ScriptClassParser::AddCreator(L"Event.Scene.StackManager.Pop", new DefaultClassCreatorContructor<SpriteSceneStackManagerPopEvent>());
    ScriptClassParser::AddCreator(L"Event.Sprite.CreateSprite", new DefaultClassCreatorContructor<CreateSpriteAtSprite>());

    ScriptClassParser::AddCreator(L"Event.PlaySound", new DefaultClassCreatorContructor<SoundEffectEvent>());
}
<commit_msg>Update.<commit_after>#include "Event.h"
#include "script/ScriptClassParser.h"
#include "scene/managers/SceneStackManager.h"
#include "scene/sprites/ScriptableSpriteActor.h"
#include "widgets/Widget.h"
#include "widgets/Layouters/StackWidget.h"

using namespace MX;

class ReturnEvent : public Event
{
public:
	ReturnEvent(const std::string& objectName) : Event(objectName)
	{
		load_property_child(_value, "Value");
	}

	void Do() override
	{
		if (!Context<EventInfo>::isCurrent())
			return;

		auto &info = Context<EventInfo>::current();
		info.returnValue = _value;
	}

protected:
	int _value = 0;
};

class IfEvent : public Event
{
public:
	IfEvent(const std::string& objectName) : Event(objectName)
	{
		load_property(_condition, "Condition");
		load_property_children(_thenEvents, "Then");
		load_property(_elseEvents, "Else");
	}

	void Do() override
	{
		float value = *_condition;

		if (value)
			_thenEvents.Do();
		else
			_elseEvents.Do();
	}

protected:
	Scriptable::Value::pointer _condition;
	MX::EventHolder   _thenEvents;
	MX::EventHolder   _elseEvents;
};

class DelayEvent : public Event
{
public:
	DelayEvent(const std::string& objectName) : Event(objectName)
	{
		load_property(_time, "Time");
		load_property_children(_events, "Events");
	}

	void Do() override
	{
		FunctorsQueue::current().planWeakFunctor(_time, [&]() { _events.Do(); }, shared_from_this());
	}

protected:
	float _time = 1.0f;
	MX::EventHolder   _events;
};
MXREGISTER_CLASS_DEFAULT(L"Event.CompositeDelay", DelayEvent)

class DoEvent : public Event
{
public:
	DoEvent(const std::string& objectName) : Event(objectName)
	{
		load_property_child(_do, "Do");
	}

	void Do() override
	{
		float value = *_do;
	}
protected:
	Scriptable::Value::pointer _do;
};

class OnRunEvent : public Event
{
public:

	OnRunEvent(const std::string& objectName) : Event(objectName)
	{
		load_property_children(onRun, "Commands");
	}

	void Do() override
	{
		auto &actor = Context<ScriptableSpriteActor>::current();
		actor.script.onRun += onRun;
	}
protected:
	CommandSignal onRun;
};

class StackWidgetPopEvent : public Event
{
public:
	using Event::Event;

	void Do() override
	{
		auto &widget = Context<MX::Widgets::Widget>::current();
		auto stack = MX::Widgets::StackWidget::stack_of(&widget);
		if (stack)
			stack->PopWidget();
	}

};

class SpriteSceneStackManagerPopEvent : public Event
{
public:
	using Event::Event;

	void Do() override
	{
		auto &sprite = ScriptableSpriteActor::current();
		SpriteSceneStackManager::PopOnManagerOf(&sprite);
	}

};

class CreateSpriteAtSprite : public Event
{
public:
    CreateSpriteAtSprite(const std::string& objectName) : Event(objectName)
    {
        load_property_child(_actor, "Sprite");
        load_property(_rotateToCurrent, "RotateToCurrent");
    }

    void Do()
    {
        if (!ScriptableSpriteActor::isCurrent())
            return;

        if (!_actor)
            return;
        auto actor = _actor->cloneSprite();

        actor->geometry.position = ScriptableSpriteActor::current().geometry.position;

        if (_rotateToCurrent)
            actor->geometry.angle = ScriptableSpriteActor::current().geometry.angle;

        ScriptableSpriteActor::current().sprite_scene().AddActor(actor);
    }

protected:
    std::shared_ptr<MX::ScriptableSpriteActor> _actor;
    bool _rotateToCurrent = false;
};

class SoundEffectEvent : public Event
{
public:
    SoundEffectEvent(const std::string& objectName) : Event(objectName)
    {
        load_property_child(_sound, "Sound");
    }

    void Do()
    {
        if (_sound)
            _sound->sound()->Play();
    }

protected:
    std::shared_ptr<MX::ScriptSoundClass> _sound;
};

void EventInit::Init()
{
	ScriptClassParser::AddCreator(L"Event.Return", new DefaultClassCreatorContructor<ReturnEvent>());
	ScriptClassParser::AddCreator(L"Event.If", new DefaultClassCreatorContructor<IfEvent>());
	ScriptClassParser::AddCreator(L"Event.Do", new DefaultClassCreatorContructor<DoEvent>());
	ScriptClassParser::AddCreator(L"Event.OnRun", new DefaultClassCreatorContructor<OnRunEvent>());

	ScriptClassParser::AddCreator(L"Event.StackWidget.Pop", new DefaultClassCreatorContructor<StackWidgetPopEvent>());

	ScriptClassParser::AddCreator(L"Event.Scene.StackManager.Pop", new DefaultClassCreatorContructor<SpriteSceneStackManagerPopEvent>());
    ScriptClassParser::AddCreator(L"Event.Sprite.CreateSprite", new DefaultClassCreatorContructor<CreateSpriteAtSprite>());

    ScriptClassParser::AddCreator(L"Event.PlaySound", new DefaultClassCreatorContructor<SoundEffectEvent>());
}
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. 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 <memory>
#include <vector>

#include "tensorflow/compiler/xla/service/gpu/ir_emitter_nested.h"

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "tensorflow/compiler/xla/service/gpu/hlo_to_ir_bindings.h"
#include "tensorflow/compiler/xla/service/gpu/ir_emitter_context.h"
#include "tensorflow/compiler/xla/service/hlo_computation.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/service/llvm_ir/llvm_util.h"
#include "tensorflow/compiler/xla/service/llvm_ir/tuple_ops.h"
#include "tensorflow/compiler/xla/service/name_uniquer.h"
#include "tensorflow/core/lib/core/status.h"

namespace xla {
namespace gpu {

IrEmitterNested::IrEmitterNested(const HloModuleConfig& hlo_module_config,
                                 const HloComputation& nested_computation,
                                 IrEmitterContext* ir_emitter_context)
    : IrEmitter(hlo_module_config, ir_emitter_context, /*is_nested=*/true),
      nested_computation_(nested_computation) {}

StatusOr<std::unique_ptr<IrEmitterNested>> IrEmitterNested::Create(
    const HloModuleConfig& hlo_module_config,
    const HloComputation& nested_computation,
    IrEmitterContext* ir_emitter_context) {
  std::unique_ptr<IrEmitterNested> emitter(new IrEmitterNested(
      hlo_module_config, nested_computation, ir_emitter_context));
  TF_RETURN_IF_ERROR(emitter->EmitConstants(nested_computation));
  return emitter;
}

// Nested function serves the same purpose on GPU as a thread-local function on
// a CPU.
Status IrEmitterNested::CodegenNestedComputation() {
  std::vector<const HloInstruction*> io_hlos;
  std::vector<llvm::Type*> argument_types;
  std::vector<int64_t> argument_dereferenceable_bytes;
  const auto params = nested_computation_.parameter_instructions();
  const auto n = params.size();
  io_hlos.reserve(n);
  argument_types.reserve(n);
  argument_dereferenceable_bytes.reserve(n);
  for (const HloInstruction* param : params) {
    io_hlos.push_back(param);
    const Shape& param_shape = param->shape();
    argument_types.push_back(
        llvm_ir::ShapeToIrType(param_shape, module_)->getPointerTo());
    int64_t param_size =
        llvm_ir::ByteSizeOf(param_shape, module_->getDataLayout());
    argument_dereferenceable_bytes.push_back(param_size);
  }

  const HloInstruction* root = nested_computation_.root_instruction();
  {
    const Shape& root_shape = root->shape();
    argument_types.push_back(
        llvm_ir::ShapeToIrType(root_shape, module_)->getPointerTo());
    int64_t root_size = llvm_ir::ByteSizeOf(
        root_shape, ir_emitter_context_->llvm_module()->getDataLayout());
    argument_dereferenceable_bytes.push_back(root_size);
  }

  llvm::FunctionType* function_type =
      llvm::FunctionType::get(b_.getVoidTy(), argument_types, false);
  llvm::Function* function = llvm::Function::Create(
      function_type,                       // The function type.
      llvm::GlobalValue::InternalLinkage,  // The linkage type.
      ir_emitter_context_->name_uniquer()->GetUniqueName(
          llvm_ir::SanitizeFunctionName(
              nested_computation_.name())),  // The name of the function.
      ir_emitter_context_->llvm_module());   // The parent LLVM module.
  for (size_t arg_no = 0; arg_no < argument_dereferenceable_bytes.size();
       ++arg_no) {
    int64_t arg_size = argument_dereferenceable_bytes[arg_no];
    if (arg_size > 0) {
      function->addDereferenceableParamAttr(arg_no, arg_size);
    }
  }

  // TODO(b/65380986): Investigate if adding fast math flags for generated
  // kernels makes sense.

  llvm::BasicBlock* entry_bb =
      llvm::BasicBlock::Create(function->getContext(), "entry", function);
  // Emit a "return void" at entry_bb's end, and sets the insert point before
  // that return instruction.
  llvm::ReturnInst* ret_instr =
      llvm::ReturnInst::Create(function->getContext(), entry_bb);
  b_.SetInsertPoint(ret_instr);

  std::vector<const HloInstruction*> non_io_hlos;
  non_io_hlos.push_back(root);
  for (const auto* hlo : nested_computation_.instructions()) {
    if (hlo->opcode() != HloOpcode::kParameter &&
        hlo != nested_computation_.root_instruction()) {
      non_io_hlos.push_back(hlo);
    }
  }
  bindings_.EmitBasePointersForHlos(io_hlos, non_io_hlos);

  TF_RETURN_IF_ERROR(nested_computation_.root_instruction()->Accept(this));
  b_.SetInsertPoint(ret_instr);

  // Function epilogue: copy the output value back.
  {
    // TODO(cheshire) Duplication vs. EmitThreadLocalFunctionEpilogue
    const HloInstruction* root_instruction =
        nested_computation_.root_instruction();
    llvm::Value* root_value = bindings_.GetBasePointer(*root_instruction);
    const Shape& return_shape = root_instruction->shape();

    // Last argument is the out parameter.
    llvm::Argument* out_parameter = std::prev(function->arg_end(), 1);

    if (ShapeUtil::IsScalar(return_shape)) {
      llvm::Value* ret_value = Load(root_value, "load_ret_value");
      Store(ret_value,
            BitCast(out_parameter, root_value->getType(), "bitcast_ret_value"));
    } else {
      CHECK(return_shape.IsTuple());
      llvm::Type* tuple_type = llvm_ir::ShapeToIrType(return_shape, module_);
      llvm::Type* tuple_type_ptr = tuple_type->getPointerTo();
      llvm::Value* tuple_ptr = BitCast(out_parameter, tuple_type_ptr);

      for (int i = 0; i < return_shape.tuple_shapes_size(); i++) {
        const Shape& element_shape = return_shape.tuple_shapes(i);
        llvm::Value* destination =
            llvm_ir::EmitGetTupleElement(element_shape,
                                         /*index=*/i,
                                         /*alignment=*/1, tuple_ptr, &b_);
        llvm::Value* source =
            llvm_ir::EmitGetTupleElement(element_shape,
                                         /*index=*/i,
                                         /*alignment=*/1, root_value, &b_);
        Store(Load(source), destination);
      }
    }
  }
  b_.SetInsertPoint(ret_instr);
  emitted_function_ = function;
  return Status::OK();
}

Status IrEmitterNested::HandleParameter(HloInstruction* parameter) {
  return Status::OK();
}

Status IrEmitterNested::EmitTargetElementLoop(
    const HloInstruction& hlo,
    const llvm_ir::ElementGenerator& element_generator) {
  // For MOF we give the loop emitter an array for every output it should
  // generate.
  if (hlo.shape().IsTuple()) {
    std::vector<llvm_ir::IrArray> target_arrays =
        ConstructIrArrayForOutputs(hlo);
    TF_RETURN_IF_ERROR(
        llvm_ir::LoopEmitter(element_generator, target_arrays, &b_).EmitLoop());
    llvm_ir::EmitTuple(GetIrArray(hlo, hlo), target_arrays, &b_);
    return Status::OK();
  }
  return llvm_ir::LoopEmitter(element_generator, GetIrArray(hlo, hlo), &b_)
      .EmitLoop();
}

}  // namespace gpu
}  // namespace xla
<commit_msg>[tensorflow/compiler/xla/service/gpu/ir_emitter_nested.cc] Add calls to `reserve()` before populating vectors<commit_after>/* Copyright 2017 The TensorFlow Authors. 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 <memory>
#include <vector>

#include "tensorflow/compiler/xla/service/gpu/ir_emitter_nested.h"

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "tensorflow/compiler/xla/service/gpu/hlo_to_ir_bindings.h"
#include "tensorflow/compiler/xla/service/gpu/ir_emitter_context.h"
#include "tensorflow/compiler/xla/service/hlo_computation.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/service/llvm_ir/llvm_util.h"
#include "tensorflow/compiler/xla/service/llvm_ir/tuple_ops.h"
#include "tensorflow/compiler/xla/service/name_uniquer.h"
#include "tensorflow/core/lib/core/status.h"

namespace xla {
namespace gpu {

IrEmitterNested::IrEmitterNested(const HloModuleConfig& hlo_module_config,
                                 const HloComputation& nested_computation,
                                 IrEmitterContext* ir_emitter_context)
    : IrEmitter(hlo_module_config, ir_emitter_context, /*is_nested=*/true),
      nested_computation_(nested_computation) {}

StatusOr<std::unique_ptr<IrEmitterNested>> IrEmitterNested::Create(
    const HloModuleConfig& hlo_module_config,
    const HloComputation& nested_computation,
    IrEmitterContext* ir_emitter_context) {
  std::unique_ptr<IrEmitterNested> emitter(new IrEmitterNested(
      hlo_module_config, nested_computation, ir_emitter_context));
  TF_RETURN_IF_ERROR(emitter->EmitConstants(nested_computation));
  return emitter;
}

// Nested function serves the same purpose on GPU as a thread-local function on
// a CPU.
Status IrEmitterNested::CodegenNestedComputation() {
  std::vector<const HloInstruction*> io_hlos;
  std::vector<llvm::Type*> argument_types;
  std::vector<int64_t> argument_dereferenceable_bytes;
  const auto params = nested_computation_.parameter_instructions();
  const auto n = params.size() + 1;
  io_hlos.reserve(n - 1);
  argument_types.reserve(n);
  argument_dereferenceable_bytes.reserve(n);
  for (const HloInstruction* param : params) {
    io_hlos.push_back(param);
    const Shape& param_shape = param->shape();
    argument_types.push_back(
        llvm_ir::ShapeToIrType(param_shape, module_)->getPointerTo());
    int64_t param_size =
        llvm_ir::ByteSizeOf(param_shape, module_->getDataLayout());
    argument_dereferenceable_bytes.push_back(param_size);
  }

  const HloInstruction* root = nested_computation_.root_instruction();
  {
    const Shape& root_shape = root->shape();
    argument_types.push_back(
        llvm_ir::ShapeToIrType(root_shape, module_)->getPointerTo());
    int64_t root_size = llvm_ir::ByteSizeOf(
        root_shape, ir_emitter_context_->llvm_module()->getDataLayout());
    argument_dereferenceable_bytes.push_back(root_size);
  }

  llvm::FunctionType* function_type =
      llvm::FunctionType::get(b_.getVoidTy(), argument_types, false);
  llvm::Function* function = llvm::Function::Create(
      function_type,                       // The function type.
      llvm::GlobalValue::InternalLinkage,  // The linkage type.
      ir_emitter_context_->name_uniquer()->GetUniqueName(
          llvm_ir::SanitizeFunctionName(
              nested_computation_.name())),  // The name of the function.
      ir_emitter_context_->llvm_module());   // The parent LLVM module.
  for (size_t arg_no = 0; arg_no < argument_dereferenceable_bytes.size();
       ++arg_no) {
    int64_t arg_size = argument_dereferenceable_bytes[arg_no];
    if (arg_size > 0) {
      function->addDereferenceableParamAttr(arg_no, arg_size);
    }
  }

  // TODO(b/65380986): Investigate if adding fast math flags for generated
  // kernels makes sense.

  llvm::BasicBlock* entry_bb =
      llvm::BasicBlock::Create(function->getContext(), "entry", function);
  // Emit a "return void" at entry_bb's end, and sets the insert point before
  // that return instruction.
  llvm::ReturnInst* ret_instr =
      llvm::ReturnInst::Create(function->getContext(), entry_bb);
  b_.SetInsertPoint(ret_instr);

  std::vector<const HloInstruction*> non_io_hlos;
  non_io_hlos.push_back(root);
  for (const auto* hlo : nested_computation_.instructions()) {
    if (hlo->opcode() != HloOpcode::kParameter &&
        hlo != nested_computation_.root_instruction()) {
      non_io_hlos.push_back(hlo);
    }
  }
  bindings_.EmitBasePointersForHlos(io_hlos, non_io_hlos);

  TF_RETURN_IF_ERROR(nested_computation_.root_instruction()->Accept(this));
  b_.SetInsertPoint(ret_instr);

  // Function epilogue: copy the output value back.
  {
    // TODO(cheshire) Duplication vs. EmitThreadLocalFunctionEpilogue
    const HloInstruction* root_instruction =
        nested_computation_.root_instruction();
    llvm::Value* root_value = bindings_.GetBasePointer(*root_instruction);
    const Shape& return_shape = root_instruction->shape();

    // Last argument is the out parameter.
    llvm::Argument* out_parameter = std::prev(function->arg_end(), 1);

    if (ShapeUtil::IsScalar(return_shape)) {
      llvm::Value* ret_value = Load(root_value, "load_ret_value");
      Store(ret_value,
            BitCast(out_parameter, root_value->getType(), "bitcast_ret_value"));
    } else {
      CHECK(return_shape.IsTuple());
      llvm::Type* tuple_type = llvm_ir::ShapeToIrType(return_shape, module_);
      llvm::Type* tuple_type_ptr = tuple_type->getPointerTo();
      llvm::Value* tuple_ptr = BitCast(out_parameter, tuple_type_ptr);

      for (int i = 0; i < return_shape.tuple_shapes_size(); i++) {
        const Shape& element_shape = return_shape.tuple_shapes(i);
        llvm::Value* destination =
            llvm_ir::EmitGetTupleElement(element_shape,
                                         /*index=*/i,
                                         /*alignment=*/1, tuple_ptr, &b_);
        llvm::Value* source =
            llvm_ir::EmitGetTupleElement(element_shape,
                                         /*index=*/i,
                                         /*alignment=*/1, root_value, &b_);
        Store(Load(source), destination);
      }
    }
  }
  b_.SetInsertPoint(ret_instr);
  emitted_function_ = function;
  return Status::OK();
}

Status IrEmitterNested::HandleParameter(HloInstruction* parameter) {
  return Status::OK();
}

Status IrEmitterNested::EmitTargetElementLoop(
    const HloInstruction& hlo,
    const llvm_ir::ElementGenerator& element_generator) {
  // For MOF we give the loop emitter an array for every output it should
  // generate.
  if (hlo.shape().IsTuple()) {
    std::vector<llvm_ir::IrArray> target_arrays =
        ConstructIrArrayForOutputs(hlo);
    TF_RETURN_IF_ERROR(
        llvm_ir::LoopEmitter(element_generator, target_arrays, &b_).EmitLoop());
    llvm_ir::EmitTuple(GetIrArray(hlo, hlo), target_arrays, &b_);
    return Status::OK();
  }
  return llvm_ir::LoopEmitter(element_generator, GetIrArray(hlo, hlo), &b_)
      .EmitLoop();
}

}  // namespace gpu
}  // namespace xla
<|endoftext|>


<commit_before>#include "cls_zlog.h"

CLS_VER(1,0)
CLS_NAME(zlog)

static int log_entry_read(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::ReadEntry op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_read(): failed to decode input");
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_read(): failed to read header %d", ret);
    return ret;
  }

  ret = header.epoch_guard(op.epoch());
  if (ret < 0) {
    CLS_LOG(10, "log_entry_read(): failed epoch guard %d", ret);
    return ret;
  }

  cls_zlog::LogEntry entry(hctx, op.pos());
  ret = entry.init();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_read(): error reading entry %d", ret);
    return ret;
  }

  if (!entry.exists()) {
    CLS_LOG(10, "log_entry_read(): entry not found");
    return -ERANGE;
  }

  if (entry.invalid()) {
    CLS_LOG(10, "log_entry_read(): entry is invalidated");
    return -ENODATA;
  }

  ret = entry.read(out);
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_read(): cannot read entry %d", ret);
    return ret;
  }

  return 0;
}

static int log_entry_write(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::WriteEntry op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_write(): failed to decode input");
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_write(): failed to read header %d", ret);
    return ret;
  }

  ret = header.epoch_guard(op.epoch());
  if (ret < 0) {
    CLS_LOG(10, "log_entry_write(): failed epoch guard %d", ret);
    return ret;
  }

  cls_zlog::LogEntry entry(hctx, op.pos());
  ret = entry.init();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_write(): init failed %d", ret);
    return ret;
  }

  if (entry.exists()) {
    CLS_LOG(10, "log_entry_write(): entry exists");
    return -EROFS;
  }

  entry.set_data(op.data());
  ret = entry.write();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_write(): entry write failed %d", ret);
    return ret;
  }

  ret = header.update_max_pos(op.pos());
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_write(): header update failed %d", ret);
    return ret;
  }

  return 0;
}

static int log_entry_invalidate(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::InvalidateEntry op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_invalidate(): failed to decode input");
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_invalidate(): failed to read header %d", ret);
    return ret;
  }

  ret = header.epoch_guard(op.epoch());
  if (ret < 0) {
    CLS_LOG(10, "log_entry_invalidate(): failed epoch guard %d", ret);
    return ret;
  }

  cls_zlog::LogEntry entry(hctx, op.pos());
  ret = entry.init();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_invalidate(): init failed %d", ret);
    return ret;
  }

  if (entry.exists()) {
    if (entry.invalid()) {
      CLS_LOG(10, "log_entry_invalidate(): already invalidated");
      return 0;
    }
    if (!op.force()) {
      CLS_LOG(10, "log_entry_invalidate(): entry exists (non-forced)");
      return -EROFS;
    }
  }

  entry.invalidate();
  ret = entry.write();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_invalidate(): entry write failed %d", ret);
    return ret;
  }

  ret = header.update_max_pos(op.pos());
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_invalidate(): header update failed %d", ret);
    return ret;
  }

  return 0;
}

static int log_entry_seal(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::Seal op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_seal(): failed to decode input");
    return -EINVAL;
  }

  if (op.epoch() < 1) {
    CLS_ERR("ERROR: log_entry_seal(): invalid epoch %llu",
        op.epoch());
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0 && ret != -ENOENT) {
    CLS_ERR("ERROR: log_entry_seal(): failed to read header %d", ret);
    return ret;
  }

  if (ret == 0) {
    if (op.epoch() <= header.epoch()) {
      CLS_LOG(10, "log_entry_seal(): stale op epoch %llu <= %llu (hdr)",
          (unsigned long long)op.epoch(),
          (unsigned long long)header.epoch());
      return -ESPIPE;
    }
  } else if (ret != -ENOENT) {
    CLS_ERR("ERROR: unexpected return value %d", ret);
    return -EIO;
  }

  header.set_epoch(op.epoch());
  ret = header.save();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_seal(): write header failed %d", ret);
  }

  return 0;
}

static int log_entry_max_position(cls_method_context_t hctx,
    ceph::bufferlist *in, ceph::bufferlist *out)
{
  zlog_ceph_proto::ReadMaxPos op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_max_position(): failed to decode input");
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_max_position(): failed to load header %d", ret);
    return ret;
  }

  if (op.epoch() < 1) {
    CLS_ERR("ERROR: log_entry_max_position(): invalid epoch");
    return -EINVAL;
  } else if (op.epoch() != header.epoch()) {
    CLS_LOG(10, "log_entry_max_position(): op epoch %llu != %llu (hdr)",
        (unsigned long long)op.epoch(),
        (unsigned long long)header.epoch());
    return -ESPIPE;
  }

  zlog_ceph_proto::MaxPos reply;
  auto max_pos = header.max_pos();
  if (max_pos) {
    reply.set_pos(*max_pos);
  }

  encode(*out, reply);

  return 0;
}

static int view_init(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::HeadObjectHeader op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: view_init(): decoding input");
    return -EINVAL;
  }

  if (op.prefix().empty()) {
    CLS_ERR("ERROR: view_init(): zero-length prefix");
    return -EINVAL;
  }

  int ret = cls_cxx_stat(hctx, NULL, NULL);
  if (ret != -ENOENT) {
    if (ret >= 0)
      ret = -EEXIST;
    CLS_ERR("ERROR: view_init(): stat check ret %d", ret);
    return ret;
  }

  zlog_ceph_proto::HeadObjectHeader hdr;
  hdr.set_prefix(op.prefix());
  hdr.set_deleted(false);
  hdr.set_epoch(0);

  cls_zlog::HeadObject head(hctx, hdr);
  ret = head.finalize();
  if (ret < 0) {
    CLS_ERR("ERROR: view_init(): finalizing ret %d", ret);
    return ret;
  }

  return 0;
}

static int view_create(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::CreateView op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: view_create(): decoding input");
    return -EINVAL;
  }

  cls_zlog::HeadObject head(hctx);
  int ret = head.initialize();
  if (ret < 0) {
    CLS_ERR("ERROR: view_create(): initializing ret %d", ret);
    return ret;
  }

  ret = head.set_epoch(op.epoch());
  if (ret < 0) {
    CLS_ERR("ERROR: view_create(): epoch %llu hdr %llu",
        op.epoch(), head.epoch());
    return ret;
  }

  ret = head.write_view(op.data());
  if (ret < 0) {
    CLS_ERR("ERROR: view_create(): writing view ret %d", ret);
    return ret;
  }

  ret = head.finalize();
  if (ret < 0) {
    CLS_ERR("ERROR: view_create(): finalizing ret %d", ret);
    return ret;
  }

  return 0;
}

static int view_read(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::ReadView op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: view_read(): decoding input");
    return -EINVAL;
  }

  cls_zlog::HeadObject head(hctx);
  int ret = head.initialize();
  if (ret < 0) {
    CLS_ERR("ERROR: view_read(): initializing ret %d", ret);
    return ret;
  }

  uint64_t epoch = op.epoch();
  if (epoch < 1) {
    CLS_ERR("ERROR: view_read(): bad start epoch %llu", epoch);
    return -EINVAL;
  }

  // TODO: add a cap on the maximum number of views to return

  uint32_t count = 0;
  zlog_ceph_proto::Views views;
  while (epoch <= head.epoch() && count < op.max_views()) {
    ceph::bufferlist bl;
    ret = head.read_view(epoch, &bl);
    if (ret < 0) {
      CLS_ERR("ERROR: view_read(): reading view %llu ret %d",
          epoch, ret);
      return ret;
    }

    auto view = views.add_views();
    view->set_epoch(epoch);
    view->set_data(bl.c_str(), bl.length());

    epoch++;
    count++;
  }

  encode(*out, views);

  return 0;
}

void __cls_init()
{
  CLS_LOG(0, "loading cls_zlog");

  // log entry object methods
  cls_method_handle_t h_log_entry_read;
  cls_method_handle_t h_log_entry_write;
  cls_method_handle_t h_log_entry_invalidate;
  cls_method_handle_t h_log_entry_seal;
  cls_method_handle_t h_log_entry_max_position;

  // head object methods
  cls_method_handle_t h_view_init;
  cls_method_handle_t h_view_create;
  cls_method_handle_t h_view_read;

  cls_handle_t h_class;
  cls_register("zlog", &h_class);

  cls_register_cxx_method(h_class, "entry_read",
      CLS_METHOD_RD,
      log_entry_read, &h_log_entry_read);

  cls_register_cxx_method(h_class, "entry_write",
      CLS_METHOD_RD | CLS_METHOD_WR,
      log_entry_write, &h_log_entry_write);

  cls_register_cxx_method(h_class, "entry_invalidate",
      CLS_METHOD_RD | CLS_METHOD_WR,
      log_entry_invalidate, &h_log_entry_invalidate);

  cls_register_cxx_method(h_class, "entry_seal",
      CLS_METHOD_RD | CLS_METHOD_WR,
      log_entry_seal, &h_log_entry_seal);

  cls_register_cxx_method(h_class, "entry_max_position",
      CLS_METHOD_RD,
      log_entry_max_position, &h_log_entry_max_position);

  cls_register_cxx_method(h_class, "view_init",
      CLS_METHOD_RD | CLS_METHOD_WR,
      view_init, &h_view_init);

  cls_register_cxx_method(h_class, "view_create",
      CLS_METHOD_RD | CLS_METHOD_WR,
      view_create, &h_view_create);

  cls_register_cxx_method(h_class, "view_read",
      CLS_METHOD_RD,
      view_read, &h_view_read);
}
<commit_msg>be/ceph: return error on failure<commit_after>#include "cls_zlog.h"

CLS_VER(1,0)
CLS_NAME(zlog)

static int log_entry_read(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::ReadEntry op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_read(): failed to decode input");
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_read(): failed to read header %d", ret);
    return ret;
  }

  ret = header.epoch_guard(op.epoch());
  if (ret < 0) {
    CLS_LOG(10, "log_entry_read(): failed epoch guard %d", ret);
    return ret;
  }

  cls_zlog::LogEntry entry(hctx, op.pos());
  ret = entry.init();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_read(): error reading entry %d", ret);
    return ret;
  }

  if (!entry.exists()) {
    CLS_LOG(10, "log_entry_read(): entry not found");
    return -ERANGE;
  }

  if (entry.invalid()) {
    CLS_LOG(10, "log_entry_read(): entry is invalidated");
    return -ENODATA;
  }

  ret = entry.read(out);
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_read(): cannot read entry %d", ret);
    return ret;
  }

  return 0;
}

static int log_entry_write(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::WriteEntry op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_write(): failed to decode input");
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_write(): failed to read header %d", ret);
    return ret;
  }

  ret = header.epoch_guard(op.epoch());
  if (ret < 0) {
    CLS_LOG(10, "log_entry_write(): failed epoch guard %d", ret);
    return ret;
  }

  cls_zlog::LogEntry entry(hctx, op.pos());
  ret = entry.init();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_write(): init failed %d", ret);
    return ret;
  }

  if (entry.exists()) {
    CLS_LOG(10, "log_entry_write(): entry exists");
    return -EROFS;
  }

  entry.set_data(op.data());
  ret = entry.write();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_write(): entry write failed %d", ret);
    return ret;
  }

  ret = header.update_max_pos(op.pos());
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_write(): header update failed %d", ret);
    return ret;
  }

  return 0;
}

static int log_entry_invalidate(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::InvalidateEntry op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_invalidate(): failed to decode input");
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_invalidate(): failed to read header %d", ret);
    return ret;
  }

  ret = header.epoch_guard(op.epoch());
  if (ret < 0) {
    CLS_LOG(10, "log_entry_invalidate(): failed epoch guard %d", ret);
    return ret;
  }

  cls_zlog::LogEntry entry(hctx, op.pos());
  ret = entry.init();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_invalidate(): init failed %d", ret);
    return ret;
  }

  if (entry.exists()) {
    if (entry.invalid()) {
      CLS_LOG(10, "log_entry_invalidate(): already invalidated");
      return 0;
    }
    if (!op.force()) {
      CLS_LOG(10, "log_entry_invalidate(): entry exists (non-forced)");
      return -EROFS;
    }
  }

  entry.invalidate();
  ret = entry.write();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_invalidate(): entry write failed %d", ret);
    return ret;
  }

  ret = header.update_max_pos(op.pos());
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_invalidate(): header update failed %d", ret);
    return ret;
  }

  return 0;
}

static int log_entry_seal(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::Seal op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_seal(): failed to decode input");
    return -EINVAL;
  }

  if (op.epoch() < 1) {
    CLS_ERR("ERROR: log_entry_seal(): invalid epoch %llu",
        op.epoch());
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0 && ret != -ENOENT) {
    CLS_ERR("ERROR: log_entry_seal(): failed to read header %d", ret);
    return ret;
  }

  if (ret == 0) {
    if (op.epoch() <= header.epoch()) {
      CLS_LOG(10, "log_entry_seal(): stale op epoch %llu <= %llu (hdr)",
          (unsigned long long)op.epoch(),
          (unsigned long long)header.epoch());
      return -ESPIPE;
    }
  } else if (ret != -ENOENT) {
    CLS_ERR("ERROR: unexpected return value %d", ret);
    return -EIO;
  }

  header.set_epoch(op.epoch());
  ret = header.save();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_seal(): write header failed %d", ret);
    return ret;
  }

  return 0;
}

static int log_entry_max_position(cls_method_context_t hctx,
    ceph::bufferlist *in, ceph::bufferlist *out)
{
  zlog_ceph_proto::ReadMaxPos op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: log_entry_max_position(): failed to decode input");
    return -EINVAL;
  }

  cls_zlog::LogObjectHeader header(hctx);
  int ret = header.load();
  if (ret < 0) {
    CLS_ERR("ERROR: log_entry_max_position(): failed to load header %d", ret);
    return ret;
  }

  if (op.epoch() < 1) {
    CLS_ERR("ERROR: log_entry_max_position(): invalid epoch");
    return -EINVAL;
  } else if (op.epoch() != header.epoch()) {
    CLS_LOG(10, "log_entry_max_position(): op epoch %llu != %llu (hdr)",
        (unsigned long long)op.epoch(),
        (unsigned long long)header.epoch());
    return -ESPIPE;
  }

  zlog_ceph_proto::MaxPos reply;
  auto max_pos = header.max_pos();
  if (max_pos) {
    reply.set_pos(*max_pos);
  }

  encode(*out, reply);

  return 0;
}

static int view_init(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::HeadObjectHeader op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: view_init(): decoding input");
    return -EINVAL;
  }

  if (op.prefix().empty()) {
    CLS_ERR("ERROR: view_init(): zero-length prefix");
    return -EINVAL;
  }

  int ret = cls_cxx_stat(hctx, NULL, NULL);
  if (ret != -ENOENT) {
    if (ret >= 0)
      ret = -EEXIST;
    CLS_ERR("ERROR: view_init(): stat check ret %d", ret);
    return ret;
  }

  zlog_ceph_proto::HeadObjectHeader hdr;
  hdr.set_prefix(op.prefix());
  hdr.set_deleted(false);
  hdr.set_epoch(0);

  cls_zlog::HeadObject head(hctx, hdr);
  ret = head.finalize();
  if (ret < 0) {
    CLS_ERR("ERROR: view_init(): finalizing ret %d", ret);
    return ret;
  }

  return 0;
}

static int view_create(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::CreateView op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: view_create(): decoding input");
    return -EINVAL;
  }

  cls_zlog::HeadObject head(hctx);
  int ret = head.initialize();
  if (ret < 0) {
    CLS_ERR("ERROR: view_create(): initializing ret %d", ret);
    return ret;
  }

  ret = head.set_epoch(op.epoch());
  if (ret < 0) {
    CLS_ERR("ERROR: view_create(): epoch %llu hdr %llu",
        op.epoch(), head.epoch());
    return ret;
  }

  ret = head.write_view(op.data());
  if (ret < 0) {
    CLS_ERR("ERROR: view_create(): writing view ret %d", ret);
    return ret;
  }

  ret = head.finalize();
  if (ret < 0) {
    CLS_ERR("ERROR: view_create(): finalizing ret %d", ret);
    return ret;
  }

  return 0;
}

static int view_read(cls_method_context_t hctx, ceph::bufferlist *in,
    ceph::bufferlist *out)
{
  zlog_ceph_proto::ReadView op;
  if (!decode(*in, &op)) {
    CLS_ERR("ERROR: view_read(): decoding input");
    return -EINVAL;
  }

  cls_zlog::HeadObject head(hctx);
  int ret = head.initialize();
  if (ret < 0) {
    CLS_ERR("ERROR: view_read(): initializing ret %d", ret);
    return ret;
  }

  uint64_t epoch = op.epoch();
  if (epoch < 1) {
    CLS_ERR("ERROR: view_read(): bad start epoch %llu", epoch);
    return -EINVAL;
  }

  // TODO: add a cap on the maximum number of views to return

  uint32_t count = 0;
  zlog_ceph_proto::Views views;
  while (epoch <= head.epoch() && count < op.max_views()) {
    ceph::bufferlist bl;
    ret = head.read_view(epoch, &bl);
    if (ret < 0) {
      CLS_ERR("ERROR: view_read(): reading view %llu ret %d",
          epoch, ret);
      return ret;
    }

    auto view = views.add_views();
    view->set_epoch(epoch);
    view->set_data(bl.c_str(), bl.length());

    epoch++;
    count++;
  }

  encode(*out, views);

  return 0;
}

void __cls_init()
{
  CLS_LOG(0, "loading cls_zlog");

  // log entry object methods
  cls_method_handle_t h_log_entry_read;
  cls_method_handle_t h_log_entry_write;
  cls_method_handle_t h_log_entry_invalidate;
  cls_method_handle_t h_log_entry_seal;
  cls_method_handle_t h_log_entry_max_position;

  // head object methods
  cls_method_handle_t h_view_init;
  cls_method_handle_t h_view_create;
  cls_method_handle_t h_view_read;

  cls_handle_t h_class;
  cls_register("zlog", &h_class);

  cls_register_cxx_method(h_class, "entry_read",
      CLS_METHOD_RD,
      log_entry_read, &h_log_entry_read);

  cls_register_cxx_method(h_class, "entry_write",
      CLS_METHOD_RD | CLS_METHOD_WR,
      log_entry_write, &h_log_entry_write);

  cls_register_cxx_method(h_class, "entry_invalidate",
      CLS_METHOD_RD | CLS_METHOD_WR,
      log_entry_invalidate, &h_log_entry_invalidate);

  cls_register_cxx_method(h_class, "entry_seal",
      CLS_METHOD_RD | CLS_METHOD_WR,
      log_entry_seal, &h_log_entry_seal);

  cls_register_cxx_method(h_class, "entry_max_position",
      CLS_METHOD_RD,
      log_entry_max_position, &h_log_entry_max_position);

  cls_register_cxx_method(h_class, "view_init",
      CLS_METHOD_RD | CLS_METHOD_WR,
      view_init, &h_view_init);

  cls_register_cxx_method(h_class, "view_create",
      CLS_METHOD_RD | CLS_METHOD_WR,
      view_create, &h_view_create);

  cls_register_cxx_method(h_class, "view_read",
      CLS_METHOD_RD,
      view_read, &h_view_read);
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001-2009  The Bochs Project
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////

#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR

// Make code more tidy with a few macros.
#if BX_SUPPORT_X86_64==0
#define RSP ESP
#endif

void BX_CPP_AttrRegparmN(1) BX_CPU_C::BOUND_GwMa(bxInstruction_c *i)
{
  Bit16s op1_16 = BX_READ_16BIT_REG(i->nnn());

  Bit32u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));

  Bit16s bound_min = (Bit16s) read_virtual_word_32(i->seg(), eaddr);
  Bit16s bound_max = (Bit16s) read_virtual_word_32(i->seg(), eaddr+2);

  if (op1_16 < bound_min || op1_16 > bound_max) {
    BX_INFO(("BOUND_GdMa: fails bounds test"));
    exception(BX_BR_EXCEPTION, 0, 0);
  }
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::BOUND_GdMa(bxInstruction_c *i)
{
  Bit32s op1_32 = BX_READ_32BIT_REG(i->nnn());

  Bit32u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));

  Bit32s bound_min = (Bit32s) read_virtual_dword_32(i->seg(), eaddr);
  Bit32s bound_max = (Bit32s) read_virtual_dword_32(i->seg(), eaddr+4);

  if (op1_32 < bound_min || op1_32 > bound_max) {
    BX_INFO(("BOUND_GdMa: fails bounds test"));
    exception(BX_BR_EXCEPTION, 0, 0);
  }
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT1(bxInstruction_c *i)
{
#if BX_SUPPORT_VMX
  VMexit_Event(i, BX_PRIVILEGED_SOFTWARE_INTERRUPT, 1, 0, 0);
#endif

  // This is an undocumented instrucion (opcode 0xf1)
  // which is useful for an ICE system.

#if BX_DEBUGGER
  BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif

  RSP_SPECULATIVE;

  // interrupt is not RSP safe
  interrupt(1, BX_PRIVILEGED_SOFTWARE_INTERRUPT, 0, 0);

  RSP_COMMIT;

  BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
                      BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
                      EIP);
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT3(bxInstruction_c *i)
{
  // INT 3 is not IOPL sensitive

#if BX_SUPPORT_VMX
  VMexit_Event(i, BX_SOFTWARE_EXCEPTION, 3, 0, 0);
#endif

#if BX_DEBUGGER
  BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif

  RSP_SPECULATIVE;

  // interrupt is not RSP safe
  interrupt(3, BX_SOFTWARE_EXCEPTION, 0, 0);

  RSP_COMMIT;

  BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
                      BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
                      EIP);
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT_Ib(bxInstruction_c *i)
{
#if BX_DEBUGGER
  BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif

  Bit8u vector = i->Ib();

  RSP_SPECULATIVE;

  if (v8086_mode()) {
#if BX_CPU_LEVEL >= 5
    if (BX_CPU_THIS_PTR cr4.get_VME())
    {
      bx_address tr_base = BX_CPU_THIS_PTR tr.cache.u.segment.base;
      if (BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled < 103) {
        BX_ERROR(("INT_Ib(): TR.limit < 103 in VME"));
        exception(BX_GP_EXCEPTION, 0, 0);
      }

      Bit32u io_base = system_read_word(tr_base + 102), offset = io_base - 32 + (vector >> 3);
      if (offset > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
        BX_ERROR(("INT_Ib(): failed to fetch VME redirection bitmap"));
        exception(BX_GP_EXCEPTION, 0, 0);
      }

      Bit8u vme_redirection_bitmap = system_read_byte(tr_base + offset);
      if (!(vme_redirection_bitmap & (1 << (vector & 7))))
      {
        // redirect interrupt through virtual-mode idt
        v86_redirect_interrupt(vector);
        goto done;
      }
    }
#endif
    // interrupt is not redirected or VME is OFF
    if (BX_CPU_THIS_PTR get_IOPL() < 3)
    {
      BX_DEBUG(("INT_Ib(): Interrupt cannot be redirected, generate #GP(0)"));
      exception(BX_GP_EXCEPTION, 0, 0);
    }
  }

#if BX_SUPPORT_VMX
  VMexit_Event(i, BX_SOFTWARE_INTERRUPT, vector, 0, 0);
#endif

#ifdef SHOW_EXIT_STATUS
  if ((vector == 0x21) && (AH == 0x4c)) {
    BX_INFO(("INT 21/4C called AL=0x%02x, BX=0x%04x", (unsigned) AL, (unsigned) BX));
  }
#endif

  interrupt(vector, BX_SOFTWARE_INTERRUPT, 0, 0);

done:

  RSP_COMMIT;

  BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
                      BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
                      EIP);
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::INTO(bxInstruction_c *i)
{
  if (get_OF()) {

#if BX_SUPPORT_VMX
    VMexit_Event(i, BX_SOFTWARE_EXCEPTION, 4, 0, 0);
#endif

#if BX_DEBUGGER
    BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif

    RSP_SPECULATIVE;

    // interrupt is not RSP safe
    interrupt(4, BX_SOFTWARE_EXCEPTION, 0, 0);

    RSP_COMMIT;

    BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
                        BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
                        EIP);
  }
}
<commit_msg>INT1 should set EXT bit<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001-2009  The Bochs Project
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////

#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR

// Make code more tidy with a few macros.
#if BX_SUPPORT_X86_64==0
#define RSP ESP
#endif

void BX_CPP_AttrRegparmN(1) BX_CPU_C::BOUND_GwMa(bxInstruction_c *i)
{
  Bit16s op1_16 = BX_READ_16BIT_REG(i->nnn());

  Bit32u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));

  Bit16s bound_min = (Bit16s) read_virtual_word_32(i->seg(), eaddr);
  Bit16s bound_max = (Bit16s) read_virtual_word_32(i->seg(), eaddr+2);

  if (op1_16 < bound_min || op1_16 > bound_max) {
    BX_INFO(("BOUND_GdMa: fails bounds test"));
    exception(BX_BR_EXCEPTION, 0, 0);
  }
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::BOUND_GdMa(bxInstruction_c *i)
{
  Bit32s op1_32 = BX_READ_32BIT_REG(i->nnn());

  Bit32u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));

  Bit32s bound_min = (Bit32s) read_virtual_dword_32(i->seg(), eaddr);
  Bit32s bound_max = (Bit32s) read_virtual_dword_32(i->seg(), eaddr+4);

  if (op1_32 < bound_min || op1_32 > bound_max) {
    BX_INFO(("BOUND_GdMa: fails bounds test"));
    exception(BX_BR_EXCEPTION, 0, 0);
  }
}

// This is an undocumented instrucion (opcode 0xf1) which
// is useful for an ICE system
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT1(bxInstruction_c *i)
{
#if BX_SUPPORT_VMX
  VMexit_Event(i, BX_PRIVILEGED_SOFTWARE_INTERRUPT, 1, 0, 0);
#endif

#if BX_DEBUGGER
  BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif

  BX_CPU_THIS_PTR EXT = 1;

  RSP_SPECULATIVE;

  // interrupt is not RSP safe
  interrupt(1, BX_PRIVILEGED_SOFTWARE_INTERRUPT, 0, 0);

  RSP_COMMIT;

  BX_CPU_THIS_PTR EXT = 0;

  BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
                      BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
                      EIP);
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT3(bxInstruction_c *i)
{
  // INT 3 is not IOPL sensitive

#if BX_SUPPORT_VMX
  VMexit_Event(i, BX_SOFTWARE_EXCEPTION, 3, 0, 0);
#endif

#if BX_DEBUGGER
  BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif

  RSP_SPECULATIVE;

  // interrupt is not RSP safe
  interrupt(3, BX_SOFTWARE_EXCEPTION, 0, 0);

  RSP_COMMIT;

  BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
                      BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
                      EIP);
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT_Ib(bxInstruction_c *i)
{
#if BX_DEBUGGER
  BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif

  Bit8u vector = i->Ib();

  RSP_SPECULATIVE;

  if (v8086_mode()) {
#if BX_CPU_LEVEL >= 5
    if (BX_CPU_THIS_PTR cr4.get_VME())
    {
      bx_address tr_base = BX_CPU_THIS_PTR tr.cache.u.segment.base;
      if (BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled < 103) {
        BX_ERROR(("INT_Ib(): TR.limit < 103 in VME"));
        exception(BX_GP_EXCEPTION, 0, 0);
      }

      Bit32u io_base = system_read_word(tr_base + 102), offset = io_base - 32 + (vector >> 3);
      if (offset > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
        BX_ERROR(("INT_Ib(): failed to fetch VME redirection bitmap"));
        exception(BX_GP_EXCEPTION, 0, 0);
      }

      Bit8u vme_redirection_bitmap = system_read_byte(tr_base + offset);
      if (!(vme_redirection_bitmap & (1 << (vector & 7))))
      {
        // redirect interrupt through virtual-mode idt
        v86_redirect_interrupt(vector);
        goto done;
      }
    }
#endif
    // interrupt is not redirected or VME is OFF
    if (BX_CPU_THIS_PTR get_IOPL() < 3)
    {
      BX_DEBUG(("INT_Ib(): Interrupt cannot be redirected, generate #GP(0)"));
      exception(BX_GP_EXCEPTION, 0, 0);
    }
  }

#if BX_SUPPORT_VMX
  VMexit_Event(i, BX_SOFTWARE_INTERRUPT, vector, 0, 0);
#endif

#ifdef SHOW_EXIT_STATUS
  if ((vector == 0x21) && (AH == 0x4c)) {
    BX_INFO(("INT 21/4C called AL=0x%02x, BX=0x%04x", (unsigned) AL, (unsigned) BX));
  }
#endif

  interrupt(vector, BX_SOFTWARE_INTERRUPT, 0, 0);

done:

  RSP_COMMIT;

  BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
                      BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
                      EIP);
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::INTO(bxInstruction_c *i)
{
  if (get_OF()) {

#if BX_SUPPORT_VMX
    VMexit_Event(i, BX_SOFTWARE_EXCEPTION, 4, 0, 0);
#endif

#if BX_DEBUGGER
    BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif

    RSP_SPECULATIVE;

    // interrupt is not RSP safe
    interrupt(4, BX_SOFTWARE_EXCEPTION, 0, 0);

    RSP_COMMIT;

    BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
                        BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
                        EIP);
  }
}
<|endoftext|>


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

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "init.hh"
#include "message/messaging_service.hh"
#include "gms/failure_detector.hh"
#include "gms/gossiper.hh"
#include "service/storage_service.hh"
#include "to_string.hh"
#include "gms/inet_address.hh"

//
// NOTE: there functions are (temporarily)
// duplicated in cql_test_env.cc
// until proper shutdown is done.

void init_storage_service(distributed<database>& db) {
    service::init_storage_service(db).get();
    // #293 - do not stop anything
    //engine().at_exit([] { return service::deinit_storage_service(); });
}

void init_ms_fd_gossiper(sstring listen_address
                , uint16_t storage_port
                , uint16_t ssl_storage_port
                , sstring ms_encrypt_what
                , sstring ms_trust_store
                , sstring ms_cert
                , sstring ms_key
                , db::seed_provider_type seed_provider
                , sstring cluster_name
                , double phi)
{
    const gms::inet_address listen(listen_address);

    using encrypt_what = net::messaging_service::encrypt_what;
    using namespace seastar::tls;

    encrypt_what ew = encrypt_what::none;
    if (ms_encrypt_what == "all") {
        ew = encrypt_what::all;
    } else if (ms_encrypt_what == "dc") {
        ew = encrypt_what::dc;
    } else if (ms_encrypt_what == "rack") {
        ew = encrypt_what::rack;
    }

    future<> f = make_ready_future<>();
    ::shared_ptr<server_credentials> creds;

    if (ew != encrypt_what::none) {
        // note: credentials are immutable after this, and ok to share across shards
        creds = ::make_shared<server_credentials>(::make_shared<dh_params>(dh_params::level::MEDIUM));
        creds->set_x509_key_file(ms_cert, ms_key, x509_crt_format::PEM).get();
        ms_trust_store.empty() ? creds->set_system_trust().get() :
                                 creds->set_x509_trust_file(ms_trust_store, x509_crt_format::PEM).get();
    }

    // Init messaging_service
    net::get_messaging_service().start(listen, storage_port, ew, ssl_storage_port, creds).get();
    // #293 - do not stop anything
    //engine().at_exit([] { return net::get_messaging_service().stop(); });
    // Init failure_detector
    gms::get_failure_detector().start(std::move(phi)).get();
    // #293 - do not stop anything
    //engine().at_exit([]{ return gms::get_failure_detector().stop(); });
    // Init gossiper
    std::set<gms::inet_address> seeds;
    if (seed_provider.parameters.count("seeds") > 0) {
        size_t begin = 0;
        size_t next = 0;
        sstring seeds_str = seed_provider.parameters.find("seeds")->second;
        while (begin < seeds_str.length() && begin != (next=seeds_str.find(",",begin))) {
            auto seed = boost::trim_copy(seeds_str.substr(begin,next-begin));
            seeds.emplace(gms::inet_address(std::move(seed)));
            begin = next+1;
        }
    }
    if (seeds.empty()) {
        seeds.emplace(gms::inet_address("127.0.0.1"));
    }
    auto broadcast_address = utils::fb_utilities::get_broadcast_address();
    if (broadcast_address != listen_address && seeds.count(listen_address)) {
        print("Use broadcast_address instead of listen_address for seeds list: seeds=%s, listen_address=%s, broadcast_address=%s\n",
                to_string(seeds), listen_address, broadcast_address);
        throw std::runtime_error("Use broadcast_address for seeds list");
    }
    gms::get_gossiper().start().get();
    auto& gossiper = gms::get_local_gossiper();
    gossiper.set_seeds(seeds);
    // #293 - do not stop anything
    //engine().at_exit([]{ return gms::get_gossiper().stop(); });
    gms::get_gossiper().invoke_on_all([cluster_name](gms::gossiper& g) {
        g.set_cluster_name(cluster_name);
    });
}
<commit_msg>messaging_service: Change init to use per-shard tls credentials<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "init.hh"
#include "message/messaging_service.hh"
#include "gms/failure_detector.hh"
#include "gms/gossiper.hh"
#include "service/storage_service.hh"
#include "to_string.hh"
#include "gms/inet_address.hh"

//
// NOTE: there functions are (temporarily)
// duplicated in cql_test_env.cc
// until proper shutdown is done.

void init_storage_service(distributed<database>& db) {
    service::init_storage_service(db).get();
    // #293 - do not stop anything
    //engine().at_exit([] { return service::deinit_storage_service(); });
}

void init_ms_fd_gossiper(sstring listen_address
                , uint16_t storage_port
                , uint16_t ssl_storage_port
                , sstring ms_encrypt_what
                , sstring ms_trust_store
                , sstring ms_cert
                , sstring ms_key
                , db::seed_provider_type seed_provider
                , sstring cluster_name
                , double phi)
{
    const gms::inet_address listen(listen_address);

    using encrypt_what = net::messaging_service::encrypt_what;
    using namespace seastar::tls;

    encrypt_what ew = encrypt_what::none;
    if (ms_encrypt_what == "all") {
        ew = encrypt_what::all;
    } else if (ms_encrypt_what == "dc") {
        ew = encrypt_what::dc;
    } else if (ms_encrypt_what == "rack") {
        ew = encrypt_what::rack;
    }

    future<> f = make_ready_future<>();

    // While tls::server_credentials themselves are "shard-safe" once they are
    // fully initialized and "immutable", the ::shared_ptr holding them is not.
    // We need to pre-create credentials for each shard, so we can hand them out.
    // Because constructor is crap place to run future-calls...
    std::vector<server_credentials> per_cpu_creds;

    if (ew != encrypt_what::none) {
        dh_params dh(dh_params::level::MEDIUM);
        for (size_t i = 0; i < smp::count; ++i) {
            per_cpu_creds.emplace_back(dh);
            per_cpu_creds.back().set_x509_key_file(ms_cert, ms_key,
                            x509_crt_format::PEM).get();
            if (ms_trust_store.empty()) {
                per_cpu_creds.back().set_system_trust().get();
            } else {
                per_cpu_creds.back().set_x509_trust_file(ms_trust_store,
                                x509_crt_format::PEM).get();
            }
        }
    }

    struct creds_helper {
        std::vector<server_credentials> & creds;

        operator ::shared_ptr<server_credentials>() const {
            return creds.empty() ? nullptr : ::make_shared<server_credentials>(std::move(creds[engine().cpu_id()]));
        }
    };

    // Init messaging_service
    net::get_messaging_service().start(listen, storage_port, ew, ssl_storage_port, creds_helper{per_cpu_creds}).get();

    // #293 - do not stop anything
    //engine().at_exit([] { return net::get_messaging_service().stop(); });
    // Init failure_detector
    gms::get_failure_detector().start(std::move(phi)).get();
    // #293 - do not stop anything
    //engine().at_exit([]{ return gms::get_failure_detector().stop(); });
    // Init gossiper
    std::set<gms::inet_address> seeds;
    if (seed_provider.parameters.count("seeds") > 0) {
        size_t begin = 0;
        size_t next = 0;
        sstring seeds_str = seed_provider.parameters.find("seeds")->second;
        while (begin < seeds_str.length() && begin != (next=seeds_str.find(",",begin))) {
            auto seed = boost::trim_copy(seeds_str.substr(begin,next-begin));
            seeds.emplace(gms::inet_address(std::move(seed)));
            begin = next+1;
        }
    }
    if (seeds.empty()) {
        seeds.emplace(gms::inet_address("127.0.0.1"));
    }
    auto broadcast_address = utils::fb_utilities::get_broadcast_address();
    if (broadcast_address != listen_address && seeds.count(listen_address)) {
        print("Use broadcast_address instead of listen_address for seeds list: seeds=%s, listen_address=%s, broadcast_address=%s\n",
                to_string(seeds), listen_address, broadcast_address);
        throw std::runtime_error("Use broadcast_address for seeds list");
    }
    gms::get_gossiper().start().get();
    auto& gossiper = gms::get_local_gossiper();
    gossiper.set_seeds(seeds);
    // #293 - do not stop anything
    //engine().at_exit([]{ return gms::get_gossiper().stop(); });
    gms::get_gossiper().invoke_on_all([cluster_name](gms::gossiper& g) {
        g.set_cluster_name(cluster_name);
    });
}
<|endoftext|>


<commit_before>//===- CodeEmitterGen.cpp - Code Emitter Generator ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// CodeEmitterGen uses the descriptions of instructions and their fields to
// construct an automated code emitter: a function that, given a MachineInstr,
// returns the (currently, 32-bit unsigned) value of the instruction.
//
//===----------------------------------------------------------------------===//

#include "CodeEmitterGen.h"
#include "CodeGenTarget.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include <map>
using namespace llvm;

// FIXME: Somewhat hackish to use a command line option for this. There should
// be a CodeEmitter class in the Target.td that controls this sort of thing
// instead.
static cl::opt<bool>
MCEmitter("mc-emitter",
          cl::desc("Generate CodeEmitter for use with the MC library."),
          cl::init(false));

void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) {
  for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end();
       I != E; ++I) {
    Record *R = *I;
    if (R->getValueAsString("Namespace") == "TargetOpcode" ||
        R->getValueAsBit("isPseudo"))
      continue;

    BitsInit *BI = R->getValueAsBitsInit("Inst");

    unsigned numBits = BI->getNumBits();

    SmallVector<Init *, 16> NewBits(numBits);

    for (unsigned bit = 0, end = numBits / 2; bit != end; ++bit) {
      unsigned bitSwapIdx = numBits - bit - 1;
      Init *OrigBit = BI->getBit(bit);
      Init *BitSwap = BI->getBit(bitSwapIdx);
      NewBits[bit]        = BitSwap;
      NewBits[bitSwapIdx] = OrigBit;
    }
    if (numBits % 2) {
      unsigned middle = (numBits + 1) / 2;
      NewBits[middle] = BI->getBit(middle);
    }

    BitsInit *NewBI = BitsInit::get(NewBits);

    // Update the bits in reversed order so that emitInstrOpBits will get the
    // correct endianness.
    R->getValue("Inst")->setValue(NewBI);
  }
}

// If the VarBitInit at position 'bit' matches the specified variable then
// return the variable bit position.  Otherwise return -1.
int CodeEmitterGen::getVariableBit(const std::string &VarName,
                                   BitsInit *BI, int bit) {
  if (VarBitInit *VBI = dynamic_cast<VarBitInit*>(BI->getBit(bit))) {
    if (VarInit *VI = dynamic_cast<VarInit*>(VBI->getVariable()))
      if (VI->getName() == VarName)
        return VBI->getBitNum();
  } else if (VarInit *VI = dynamic_cast<VarInit*>(BI->getBit(bit))) {
    if (VI->getName() == VarName)
      return 0;
  }

  return -1;
}

void CodeEmitterGen::
AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
                        unsigned &NumberedOp,
                        std::string &Case, CodeGenTarget &Target) {
  CodeGenInstruction &CGI = Target.getInstruction(R);

  // Determine if VarName actually contributes to the Inst encoding.
  int bit = BI->getNumBits()-1;

  // Scan for a bit that this contributed to.
  for (; bit >= 0; ) {
    if (getVariableBit(VarName, BI, bit) != -1)
      break;

    --bit;
  }

  // If we found no bits, ignore this value, otherwise emit the call to get the
  // operand encoding.
  if (bit < 0) return;

  // If the operand matches by name, reference according to that
  // operand number. Non-matching operands are assumed to be in
  // order.
  unsigned OpIdx;
  if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
    // Get the machine operand number for the indicated operand.
    OpIdx = CGI.Operands[OpIdx].MIOperandNo;
    assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) &&
           "Explicitly used operand also marked as not emitted!");
  } else {
    /// If this operand is not supposed to be emitted by the
    /// generated emitter, skip it.
    while (CGI.Operands.isFlatOperandNotEmitted(NumberedOp))
      ++NumberedOp;
    OpIdx = NumberedOp++;
  }

  std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
  std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;

  // If the source operand has a custom encoder, use it. This will
  // get the encoding for all of the suboperands.
  if (!EncoderMethodName.empty()) {
    // A custom encoder has all of the information for the
    // sub-operands, if there are more than one, so only
    // query the encoder once per source operand.
    if (SO.second == 0) {
      Case += "      // op: " + VarName + "\n" +
              "      op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
      if (MCEmitter)
        Case += ", Fixups";
      Case += ");\n";
    }
  } else {
    Case += "      // op: " + VarName + "\n" +
      "      op = getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
    if (MCEmitter)
      Case += ", Fixups";
    Case += ");\n";
  }

  for (; bit >= 0; ) {
    int varBit = getVariableBit(VarName, BI, bit);

    // If this bit isn't from a variable, skip it.
    if (varBit == -1) {
      --bit;
      continue;
    }

    // Figure out the consecutive range of bits covered by this operand, in
    // order to generate better encoding code.
    int beginInstBit = bit;
    int beginVarBit = varBit;
    int N = 1;
    for (--bit; bit >= 0;) {
      varBit = getVariableBit(VarName, BI, bit);
      if (varBit == -1 || varBit != (beginVarBit - N)) break;
      ++N;
      --bit;
    }

    unsigned opMask = ~0U >> (32-N);
    int opShift = beginVarBit - N + 1;
    opMask <<= opShift;
    opShift = beginInstBit - beginVarBit;

    if (opShift > 0) {
      Case += "      Value |= (op & " + utostr(opMask) + "U) << " +
              itostr(opShift) + ";\n";
    } else if (opShift < 0) {
      Case += "      Value |= (op & " + utostr(opMask) + "U) >> " +
              itostr(-opShift) + ";\n";
    } else {
      Case += "      Value |= op & " + utostr(opMask) + "U;\n";
    }
  }
}

std::string CodeEmitterGen::getInstructionCase(Record *R,
                                               CodeGenTarget &Target) {
  std::string Case;

  BitsInit *BI = R->getValueAsBitsInit("Inst");
  const std::vector<RecordVal> &Vals = R->getValues();
  unsigned NumberedOp = 0;

  // Loop over all of the fields in the instruction, determining which are the
  // operands to the instruction.
  for (unsigned i = 0, e = Vals.size(); i != e; ++i) {
    // Ignore fixed fields in the record, we're looking for values like:
    //    bits<5> RST = { ?, ?, ?, ?, ? };
    if (Vals[i].getPrefix() || Vals[i].getValue()->isComplete())
      continue;

    AddCodeToMergeInOperand(R, BI, Vals[i].getName(), NumberedOp, Case, Target);
  }

  std::string PostEmitter = R->getValueAsString("PostEncoderMethod");
  if (!PostEmitter.empty())
    Case += "      Value = " + PostEmitter + "(MI, Value);\n";

  return Case;
}

void CodeEmitterGen::run(raw_ostream &o) {
  CodeGenTarget Target(Records);
  std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");

  // For little-endian instruction bit encodings, reverse the bit order
  if (Target.isLittleEndianEncoding()) reverseBits(Insts);

  EmitSourceFileHeader("Machine Code Emitter", o);

  const std::vector<const CodeGenInstruction*> &NumberedInstructions =
    Target.getInstructionsByEnumValue();

  // Emit function declaration
  o << "unsigned " << Target.getName();
  if (MCEmitter)
    o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
      << "    SmallVectorImpl<MCFixup> &Fixups) const {\n";
  else
    o << "CodeEmitter::getBinaryCodeForInstr(const MachineInstr &MI) const {\n";

  // Emit instruction base values
  o << "  static const unsigned InstBits[] = {\n";
  for (std::vector<const CodeGenInstruction*>::const_iterator
          IN = NumberedInstructions.begin(),
          EN = NumberedInstructions.end();
       IN != EN; ++IN) {
    const CodeGenInstruction *CGI = *IN;
    Record *R = CGI->TheDef;

    if (R->getValueAsString("Namespace") == "TargetOpcode" ||
        R->getValueAsBit("isPseudo")) {
      o << "    0U,\n";
      continue;
    }

    BitsInit *BI = R->getValueAsBitsInit("Inst");

    // Start by filling in fixed values.
    unsigned Value = 0;
    for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) {
      if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(e-i-1)))
        Value |= B->getValue() << (e-i-1);
    }
    o << "    " << Value << "U," << '\t' << "// " << R->getName() << "\n";
  }
  o << "    0U\n  };\n";

  // Map to accumulate all the cases.
  std::map<std::string, std::vector<std::string> > CaseMap;

  // Construct all cases statement for each opcode
  for (std::vector<Record*>::iterator IC = Insts.begin(), EC = Insts.end();
        IC != EC; ++IC) {
    Record *R = *IC;
    if (R->getValueAsString("Namespace") == "TargetOpcode" ||
        R->getValueAsBit("isPseudo"))
      continue;
    const std::string &InstName = R->getValueAsString("Namespace") + "::"
      + R->getName();
    std::string Case = getInstructionCase(R, Target);

    CaseMap[Case].push_back(InstName);
  }

  // Emit initial function code
  o << "  const unsigned opcode = MI.getOpcode();\n"
    << "  unsigned Value = InstBits[opcode];\n"
    << "  unsigned op = 0;\n"
    << "  (void)op;  // suppress warning\n"
    << "  switch (opcode) {\n";

  // Emit each case statement
  std::map<std::string, std::vector<std::string> >::iterator IE, EE;
  for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
    const std::string &Case = IE->first;
    std::vector<std::string> &InstList = IE->second;

    for (int i = 0, N = InstList.size(); i < N; i++) {
      if (i) o << "\n";
      o << "    case " << InstList[i]  << ":";
    }
    o << " {\n";
    o << Case;
    o << "      break;\n"
      << "    }\n";
  }

  // Default case: unhandled opcode
  o << "  default:\n"
    << "    std::string msg;\n"
    << "    raw_string_ostream Msg(msg);\n"
    << "    Msg << \"Not supported instr: \" << MI;\n"
    << "    report_fatal_error(Msg.str());\n"
    << "  }\n"
    << "  return Value;\n"
    << "}\n\n";
}
<commit_msg>Widen the instruction encoder that TblGen emits to a 64 bits, which should accomodate every target I can think of offhand.<commit_after>//===- CodeEmitterGen.cpp - Code Emitter Generator ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// CodeEmitterGen uses the descriptions of instructions and their fields to
// construct an automated code emitter: a function that, given a MachineInstr,
// returns the (currently, 32-bit unsigned) value of the instruction.
//
//===----------------------------------------------------------------------===//

#include "CodeEmitterGen.h"
#include "CodeGenTarget.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include <map>
using namespace llvm;

// FIXME: Somewhat hackish to use a command line option for this. There should
// be a CodeEmitter class in the Target.td that controls this sort of thing
// instead.
static cl::opt<bool>
MCEmitter("mc-emitter",
          cl::desc("Generate CodeEmitter for use with the MC library."),
          cl::init(false));

void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) {
  for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end();
       I != E; ++I) {
    Record *R = *I;
    if (R->getValueAsString("Namespace") == "TargetOpcode" ||
        R->getValueAsBit("isPseudo"))
      continue;

    BitsInit *BI = R->getValueAsBitsInit("Inst");

    unsigned numBits = BI->getNumBits();

    SmallVector<Init *, 16> NewBits(numBits);

    for (unsigned bit = 0, end = numBits / 2; bit != end; ++bit) {
      unsigned bitSwapIdx = numBits - bit - 1;
      Init *OrigBit = BI->getBit(bit);
      Init *BitSwap = BI->getBit(bitSwapIdx);
      NewBits[bit]        = BitSwap;
      NewBits[bitSwapIdx] = OrigBit;
    }
    if (numBits % 2) {
      unsigned middle = (numBits + 1) / 2;
      NewBits[middle] = BI->getBit(middle);
    }

    BitsInit *NewBI = BitsInit::get(NewBits);

    // Update the bits in reversed order so that emitInstrOpBits will get the
    // correct endianness.
    R->getValue("Inst")->setValue(NewBI);
  }
}

// If the VarBitInit at position 'bit' matches the specified variable then
// return the variable bit position.  Otherwise return -1.
int CodeEmitterGen::getVariableBit(const std::string &VarName,
                                   BitsInit *BI, int bit) {
  if (VarBitInit *VBI = dynamic_cast<VarBitInit*>(BI->getBit(bit))) {
    if (VarInit *VI = dynamic_cast<VarInit*>(VBI->getVariable()))
      if (VI->getName() == VarName)
        return VBI->getBitNum();
  } else if (VarInit *VI = dynamic_cast<VarInit*>(BI->getBit(bit))) {
    if (VI->getName() == VarName)
      return 0;
  }

  return -1;
}

void CodeEmitterGen::
AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
                        unsigned &NumberedOp,
                        std::string &Case, CodeGenTarget &Target) {
  CodeGenInstruction &CGI = Target.getInstruction(R);

  // Determine if VarName actually contributes to the Inst encoding.
  int bit = BI->getNumBits()-1;

  // Scan for a bit that this contributed to.
  for (; bit >= 0; ) {
    if (getVariableBit(VarName, BI, bit) != -1)
      break;

    --bit;
  }

  // If we found no bits, ignore this value, otherwise emit the call to get the
  // operand encoding.
  if (bit < 0) return;

  // If the operand matches by name, reference according to that
  // operand number. Non-matching operands are assumed to be in
  // order.
  unsigned OpIdx;
  if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
    // Get the machine operand number for the indicated operand.
    OpIdx = CGI.Operands[OpIdx].MIOperandNo;
    assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) &&
           "Explicitly used operand also marked as not emitted!");
  } else {
    /// If this operand is not supposed to be emitted by the
    /// generated emitter, skip it.
    while (CGI.Operands.isFlatOperandNotEmitted(NumberedOp))
      ++NumberedOp;
    OpIdx = NumberedOp++;
  }

  std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
  std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;

  // If the source operand has a custom encoder, use it. This will
  // get the encoding for all of the suboperands.
  if (!EncoderMethodName.empty()) {
    // A custom encoder has all of the information for the
    // sub-operands, if there are more than one, so only
    // query the encoder once per source operand.
    if (SO.second == 0) {
      Case += "      // op: " + VarName + "\n" +
              "      op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
      if (MCEmitter)
        Case += ", Fixups";
      Case += ");\n";
    }
  } else {
    Case += "      // op: " + VarName + "\n" +
      "      op = getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
    if (MCEmitter)
      Case += ", Fixups";
    Case += ");\n";
  }

  for (; bit >= 0; ) {
    int varBit = getVariableBit(VarName, BI, bit);

    // If this bit isn't from a variable, skip it.
    if (varBit == -1) {
      --bit;
      continue;
    }

    // Figure out the consecutive range of bits covered by this operand, in
    // order to generate better encoding code.
    int beginInstBit = bit;
    int beginVarBit = varBit;
    int N = 1;
    for (--bit; bit >= 0;) {
      varBit = getVariableBit(VarName, BI, bit);
      if (varBit == -1 || varBit != (beginVarBit - N)) break;
      ++N;
      --bit;
    }

    unsigned opMask = ~0U >> (32-N);
    int opShift = beginVarBit - N + 1;
    opMask <<= opShift;
    opShift = beginInstBit - beginVarBit;

    if (opShift > 0) {
      Case += "      Value |= (op & UINT64_C(" + utostr(opMask) + ")) << " +
              itostr(opShift) + ";\n";
    } else if (opShift < 0) {
      Case += "      Value |= (op & UINT64_C(" + utostr(opMask) + ")) >> " +
              itostr(-opShift) + ";\n";
    } else {
      Case += "      Value |= op & UINT64_C(" + utostr(opMask) + ");\n";
    }
  }
}

std::string CodeEmitterGen::getInstructionCase(Record *R,
                                               CodeGenTarget &Target) {
  std::string Case;

  BitsInit *BI = R->getValueAsBitsInit("Inst");
  const std::vector<RecordVal> &Vals = R->getValues();
  unsigned NumberedOp = 0;

  // Loop over all of the fields in the instruction, determining which are the
  // operands to the instruction.
  for (unsigned i = 0, e = Vals.size(); i != e; ++i) {
    // Ignore fixed fields in the record, we're looking for values like:
    //    bits<5> RST = { ?, ?, ?, ?, ? };
    if (Vals[i].getPrefix() || Vals[i].getValue()->isComplete())
      continue;

    AddCodeToMergeInOperand(R, BI, Vals[i].getName(), NumberedOp, Case, Target);
  }

  std::string PostEmitter = R->getValueAsString("PostEncoderMethod");
  if (!PostEmitter.empty())
    Case += "      Value = " + PostEmitter + "(MI, Value);\n";

  return Case;
}

void CodeEmitterGen::run(raw_ostream &o) {
  CodeGenTarget Target(Records);
  std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");

  // For little-endian instruction bit encodings, reverse the bit order
  if (Target.isLittleEndianEncoding()) reverseBits(Insts);

  EmitSourceFileHeader("Machine Code Emitter", o);

  const std::vector<const CodeGenInstruction*> &NumberedInstructions =
    Target.getInstructionsByEnumValue();

  // Emit function declaration
  o << "uint64_t " << Target.getName();
  if (MCEmitter)
    o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
      << "    SmallVectorImpl<MCFixup> &Fixups) const {\n";
  else
    o << "CodeEmitter::getBinaryCodeForInstr(const MachineInstr &MI) const {\n";

  // Emit instruction base values
  o << "  static const unsigned InstBits[] = {\n";
  for (std::vector<const CodeGenInstruction*>::const_iterator
          IN = NumberedInstructions.begin(),
          EN = NumberedInstructions.end();
       IN != EN; ++IN) {
    const CodeGenInstruction *CGI = *IN;
    Record *R = CGI->TheDef;

    if (R->getValueAsString("Namespace") == "TargetOpcode" ||
        R->getValueAsBit("isPseudo")) {
      o << "    UINT64_C(0),\n";
      continue;
    }

    BitsInit *BI = R->getValueAsBitsInit("Inst");

    // Start by filling in fixed values.
    unsigned Value = 0;
    for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) {
      if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(e-i-1)))
        Value |= B->getValue() << (e-i-1);
    }
    o << "    UINT64_C(" << Value << ")," << '\t' << "// " << R->getName() << "\n";
  }
  o << "    UINT64_C(0)\n  };\n";

  // Map to accumulate all the cases.
  std::map<std::string, std::vector<std::string> > CaseMap;

  // Construct all cases statement for each opcode
  for (std::vector<Record*>::iterator IC = Insts.begin(), EC = Insts.end();
        IC != EC; ++IC) {
    Record *R = *IC;
    if (R->getValueAsString("Namespace") == "TargetOpcode" ||
        R->getValueAsBit("isPseudo"))
      continue;
    const std::string &InstName = R->getValueAsString("Namespace") + "::"
      + R->getName();
    std::string Case = getInstructionCase(R, Target);

    CaseMap[Case].push_back(InstName);
  }

  // Emit initial function code
  o << "  const unsigned opcode = MI.getOpcode();\n"
    << "  unsigned Value = InstBits[opcode];\n"
    << "  unsigned op = 0;\n"
    << "  (void)op;  // suppress warning\n"
    << "  switch (opcode) {\n";

  // Emit each case statement
  std::map<std::string, std::vector<std::string> >::iterator IE, EE;
  for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
    const std::string &Case = IE->first;
    std::vector<std::string> &InstList = IE->second;

    for (int i = 0, N = InstList.size(); i < N; i++) {
      if (i) o << "\n";
      o << "    case " << InstList[i]  << ":";
    }
    o << " {\n";
    o << Case;
    o << "      break;\n"
      << "    }\n";
  }

  // Default case: unhandled opcode
  o << "  default:\n"
    << "    std::string msg;\n"
    << "    raw_string_ostream Msg(msg);\n"
    << "    Msg << \"Not supported instr: \" << MI;\n"
    << "    report_fatal_error(Msg.str());\n"
    << "  }\n"
    << "  return Value;\n"
    << "}\n\n";
}
<|endoftext|>