<commit_before>#ifndef AST_HPP
#define AST_HPP

#include <string>
#include <vector>
#include <memory>
#include <typeinfo>

#include "utils/util.hpp"
#include "utils/error.hpp"
#include "utils/typeInfo.hpp"
#include "token.hpp"

namespace llvm {
  class BasicBlock;
}

class ASTVisitor;
using ASTVisitorLink = PtrUtil<ASTVisitor>::Link;

/**
  \brief A node in an AST

  This is the abstract superclass for all the nodes in an AST.
*/
class ASTNode: public std::enable_shared_from_this<ASTNode> {
public:
  using Link = std::shared_ptr<ASTNode>;
  using WeakLink = std::weak_ptr<ASTNode>;
  using Children = std::vector<Link>;
protected:
  WeakLink parent = WeakLink(); ///< Parent in the tree
  Children children {}; ///< Branches/Leaves in the tree
  Trace trace = defaultTrace; ///< Where in the source was this found

  static inline void printIndent(uint level) {
    for (uint i = 0; i < level; i++) print("  ");
  }
public:
  ASTNode();
  virtual ~ASTNode();

  /**
    \brief Add a new child to this node.
  */
  virtual void addChild(Link child);

  /// Get list of children
  Children getChildren() const;
  /**
    \brief Get child at position
    \param pos which child. Suports negative positions that count from the end of the children
  */
  Link at(int64 pos) const;

  void setParent(WeakLink newParent);
  WeakLink getParent() const;

  void setTrace(Trace trace);
  Trace getTrace() const;

  /// Pretty printing for this node and all his children
  virtual void printTree(uint level) const;

  virtual bool operator==(const ASTNode& rhs) const;
  virtual bool operator!=(const ASTNode& rhs) const;

  virtual void visit(ASTVisitorLink visitor) = 0;
};

/**
  \brief All the types a BlockNode can be.
*/
enum BlockType {
  ROOT_BLOCK, ///< Only the root of the AST is this.
  CODE_BLOCK, ///< Default. Normal block do...end
  FUNCTION_BLOCK, ///< Same as CODE_BLOCK, except it is only used for functions
  IF_BLOCK ///< Used for else clauses. Can be do...else
};

/**
  \brief Represents a block of statements. Children are those statements.
*/
class BlockNode: public ASTNode {
private:
  BlockType type;
public:
  BlockNode(BlockType type);

  BlockType getType() const;

  void printTree(uint level) const override;

  bool operator==(const ASTNode& rhs) const override;
  bool operator!=(const ASTNode& rhs) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Represents a piece of an expression.

  The stored token only contains operators and terminals.
  If it has an operator, the children are the operands.
  If it has a terminal, it does not have children.
*/
class ExpressionNode: public ASTNode {
private:
  Token tok = Token(UNPROCESSED, defaultTrace);
public:
  ExpressionNode(Token token);

  /// Technically overrides ASTNode::at
  std::shared_ptr<ExpressionNode> at(int64 pos) const;
  /// Get stored Token
  Token getToken() const;

  void printTree(uint level) const override;

  bool operator==(const ASTNode& rhs) const override;
  bool operator!=(const ASTNode& rhs) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Utility class for managing smart pointers of ASTNode subclasses
*/
template<typename T, typename std::enable_if<std::is_base_of<ASTNode, T>::value>::type* = nullptr>
struct Node: public PtrUtil<T> {
  typedef typename PtrUtil<T>::Link Link;
  typedef typename PtrUtil<T>::WeakLink WeakLink;

  /// Create a shared ptr that holds a node
  template<typename... Args>
  static Link make(Args... args) {
    return std::make_shared<T>(args...);
  }

  /// Technically overrides PtrUtil<T>::isSameType
  static inline bool isSameType(ASTNode::Link node) {
    return typeid(T) == typeid(*node);
  }

  /// Technically overrides PtrUtil<T>::dynPtrCast
  static inline Link dynPtrCast(ASTNode::Link node) {
    return std::dynamic_pointer_cast<T>(node);
  }
};

/**
  \brief Stores an abstract syntax tree of a program.
*/
class AST {
private:
  /// Root of AST
  Node<BlockNode>::Link root;
public:
  AST(Node<BlockNode>::Link lk);
  /// Print the tree
  void print() const;
  /// Get root
  Node<BlockNode>::Link getRoot() const;

  bool operator==(const AST& rhs) const;
  bool operator!=(const AST& rhs) const;
};

#define GET_SIG(linkType, nameOf) Node<linkType>::Link get##nameOf() const;
#define SET_SIG(linkType, nameOf) void set##nameOf(std::shared_ptr<linkType> newNode);
#define GET_SET_SIGS(linkType, nameOf) \
GET_SIG(linkType, nameOf) \
SET_SIG(linkType, nameOf)

/**
  \brief ASTNode with fixed children count.
*/
class NoMoreChildrenNode: public ASTNode {
public:
  /**
    \param childrenCount does not have more than this many children
  */
  NoMoreChildrenNode(int childrenCount);

  /**
    \throws InternalError always throws, never use
  */
  void addChild(Link child) override;

  /// Utility to check if the childIndex'th child is not nullptr
  bool inline notNull(uint childIndex) const {
    return children[childIndex] != nullptr;
  }
};

/**
  \brief Stores metadata about a declaration.

  Can have one ExpressionNode child representing initialization. Check using hasInit.
*/
class DeclarationNode: public NoMoreChildrenNode {
private:
  std::string identifier;
  DefiniteTypeInfo info;
public:
  /**
    \param identifier name of declared variable
    \param typeList what types are allowed to be stored in this variable
  */
  DeclarationNode(std::string identifier, TypeList typeList);

  GET_SET_SIGS(ExpressionNode, Init)

  /// Get string identifier
  std::string getIdentifier() const;
  /// Get DefiniteTypeInfo
  DefiniteTypeInfo getTypeInfo() const;

  /// Has dynamic type
  bool isDynamic() const;
  /// Has initialization
  bool hasInit() const;

  void printTree(uint level) const override;

  bool operator==(const ASTNode& rhs) const override;
  bool operator!=(const ASTNode& rhs) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief If statement in AST form.

  Has 3 children:
    - Condition - ExpressionNode
    - SuccessBlock - BlockNode - if Condition is true, run this
    - FailiureBlock - BlockNode or BranchNode - if Condition if false, run this
*/
class BranchNode: public NoMoreChildrenNode {
public:
  BranchNode();

  GET_SET_SIGS(ExpressionNode, Condition)
  GET_SET_SIGS(BlockNode, SuccessBlock)
  GET_SIG(ASTNode, FailiureBlock)
  SET_SIG(BlockNode, FailiureBlock)
  SET_SIG(BranchNode, FailiureBlock)

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Represents a loop.

  Has 4 children:
    - Init - DeclarationNode
    - Condition - ExpressionNode
    - Update - ExpressionNode
    - Code - BlockNode
  Example on a for loop:
  for (Init, Condition, Update) Code
*/
class LoopNode: public NoMoreChildrenNode {
private:
  /// Used by the break statement
  llvm::BasicBlock* exitBlock;
public:
  LoopNode();

  GET_SET_SIGS(DeclarationNode, Init)
  GET_SET_SIGS(ExpressionNode, Condition)
  GET_SET_SIGS(ExpressionNode, Update)
  GET_SET_SIGS(BlockNode, Code)

  llvm::BasicBlock* getExitBlock() const;
  void setExitBlock(llvm::BasicBlock* bb);

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Return statement.

  Can have an ExpressionNode to be returned.
*/
class ReturnNode: public NoMoreChildrenNode {
public:
  ReturnNode();

  GET_SET_SIGS(ExpressionNode, Value)

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Break statement for exiting a loop.

  \todo maybe add loop labels so this can break a specific loop
*/
class BreakLoopNode: public NoMoreChildrenNode {
public:
  BreakLoopNode();

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Function definition.
*/
class FunctionNode: public NoMoreChildrenNode {
private:
  std::string ident;
  FunctionSignature sig;
public:
  FunctionNode(FunctionSignature sig);
  /// \param ident if empty, behaves just like FunctionNode(FunctionSignature)
  FunctionNode(std::string ident, FunctionSignature sig);

  GET_SET_SIGS(BlockNode, Code)

  std::string getIdentifier() const;
  const FunctionSignature& getSignature() const;
  bool isAnon() const;

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

#undef GET_SIG
#undef SET_SIG
#undef GET_SET_SIGS

/**
  \see VISITOR_VISIT_IMPL_FOR
*/
#define PURE_VIRTUAL_VISIT(nodeName) virtual void visit##nodeName(Node<nodeName##Node>::Link node) = 0;

/**
  \brief Abstract class for visiting nodes on an AST.
*/
class ASTVisitor {
public:
  PURE_VIRTUAL_VISIT(Block)
  PURE_VIRTUAL_VISIT(Expression)
  PURE_VIRTUAL_VISIT(Declaration)
  PURE_VIRTUAL_VISIT(Branch)
  PURE_VIRTUAL_VISIT(Loop)
  PURE_VIRTUAL_VISIT(Return)
  PURE_VIRTUAL_VISIT(BreakLoop)
  PURE_VIRTUAL_VISIT(Function)
};

#undef PURE_VIRTUAL_VISIT

#endif
<commit_msg>Reorder classes in header<commit_after>#ifndef AST_HPP
#define AST_HPP

#include <string>
#include <vector>
#include <memory>
#include <typeinfo>

#include "utils/util.hpp"
#include "utils/error.hpp"
#include "utils/typeInfo.hpp"
#include "token.hpp"

namespace llvm {
  class BasicBlock;
}

class ASTVisitor;
using ASTVisitorLink = PtrUtil<ASTVisitor>::Link;

/**
  \brief A node in an AST

  This is the abstract superclass for all the nodes in an AST.
*/
class ASTNode: public std::enable_shared_from_this<ASTNode> {
public:
  using Link = std::shared_ptr<ASTNode>;
  using WeakLink = std::weak_ptr<ASTNode>;
  using Children = std::vector<Link>;
protected:
  WeakLink parent = WeakLink(); ///< Parent in the tree
  Children children {}; ///< Branches/Leaves in the tree
  Trace trace = defaultTrace; ///< Where in the source was this found

  static inline void printIndent(uint level) {
    for (uint i = 0; i < level; i++) print("  ");
  }
public:
  ASTNode();
  virtual ~ASTNode();

  /**
    \brief Add a new child to this node.
  */
  virtual void addChild(Link child);

  /// Get list of children
  Children getChildren() const;
  /**
    \brief Get child at position
    \param pos which child. Suports negative positions that count from the end of the children
  */
  Link at(int64 pos) const;

  void setParent(WeakLink newParent);
  WeakLink getParent() const;

  void setTrace(Trace trace);
  Trace getTrace() const;

  /// Pretty printing for this node and all his children
  virtual void printTree(uint level) const;

  virtual bool operator==(const ASTNode& rhs) const;
  virtual bool operator!=(const ASTNode& rhs) const;

  virtual void visit(ASTVisitorLink visitor) = 0;
};

/**
  \brief Utility class for managing smart pointers of ASTNode subclasses
*/
template<typename T, typename std::enable_if<std::is_base_of<ASTNode, T>::value>::type* = nullptr>
struct Node: public PtrUtil<T> {
  typedef typename PtrUtil<T>::Link Link;
  typedef typename PtrUtil<T>::WeakLink WeakLink;

  /// Create a shared ptr that holds a node
  template<typename... Args>
  static Link make(Args... args) {
    return std::make_shared<T>(args...);
  }

  /// Technically overrides PtrUtil<T>::isSameType
  static inline bool isSameType(ASTNode::Link node) {
    return typeid(T) == typeid(*node);
  }

  /// Technically overrides PtrUtil<T>::dynPtrCast
  static inline Link dynPtrCast(ASTNode::Link node) {
    return std::dynamic_pointer_cast<T>(node);
  }
};

/**
  \brief All the types a BlockNode can be.
*/
enum BlockType {
  ROOT_BLOCK, ///< Only the root of the AST is this.
  CODE_BLOCK, ///< Default. Normal block do...end
  FUNCTION_BLOCK, ///< Same as CODE_BLOCK, except it is only used for functions
  IF_BLOCK ///< Used for else clauses. Can be do...else
};

/**
  \brief Represents a block of statements. Children are those statements.
*/
class BlockNode: public ASTNode {
private:
  BlockType type;
public:
  BlockNode(BlockType type);

  BlockType getType() const;

  void printTree(uint level) const override;

  bool operator==(const ASTNode& rhs) const override;
  bool operator!=(const ASTNode& rhs) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Represents a piece of an expression.

  The stored token only contains operators and terminals.
  If it has an operator, the children are the operands.
  If it has a terminal, it does not have children.
*/
class ExpressionNode: public ASTNode {
private:
  Token tok = Token(UNPROCESSED, defaultTrace);
public:
  ExpressionNode(Token token);

  /// Technically overrides ASTNode::at
  std::shared_ptr<ExpressionNode> at(int64 pos) const;
  /// Get stored Token
  Token getToken() const;

  void printTree(uint level) const override;

  bool operator==(const ASTNode& rhs) const override;
  bool operator!=(const ASTNode& rhs) const override;

  void visit(ASTVisitorLink visitor) override;
};

/// \see GET_FOR
#define GET_SIG(linkType, nameOf) Node<linkType>::Link get##nameOf() const;
/// \see SET_FOR
#define SET_SIG(linkType, nameOf) void set##nameOf(std::shared_ptr<linkType> newNode);
/// \see GET_SET_FOR
#define GET_SET_SIGS(linkType, nameOf) \
GET_SIG(linkType, nameOf); \
SET_SIG(linkType, nameOf);

/**
  \brief ASTNode with fixed children count.
*/
class NoMoreChildrenNode: public ASTNode {
public:
  /**
    \param childrenCount does not have more than this many children
  */
  NoMoreChildrenNode(int childrenCount);

  /**
    \throws InternalError always throws, never use
  */
  void addChild(Link child) override;

  /// Utility to check if the childIndex'th child is not nullptr
  bool inline notNull(uint childIndex) const {
    return children[childIndex] != nullptr;
  }
};

/**
  \brief Stores metadata about a declaration.

  Can have one ExpressionNode child representing initialization. Check using hasInit.
*/
class DeclarationNode: public NoMoreChildrenNode {
private:
  std::string identifier;
  DefiniteTypeInfo info;
public:
  /**
    \param identifier name of declared variable
    \param typeList what types are allowed to be stored in this variable
  */
  DeclarationNode(std::string identifier, TypeList typeList);

  GET_SET_SIGS(ExpressionNode, Init)

  /// Get string identifier
  std::string getIdentifier() const;
  /// Get DefiniteTypeInfo
  DefiniteTypeInfo getTypeInfo() const;

  /// Has dynamic type
  bool isDynamic() const;
  /// Has initialization
  bool hasInit() const;

  void printTree(uint level) const override;

  bool operator==(const ASTNode& rhs) const override;
  bool operator!=(const ASTNode& rhs) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief If statement in AST form.

  Has 3 children:
    - Condition - ExpressionNode
    - SuccessBlock - BlockNode - if Condition is true, run this
    - FailiureBlock - BlockNode or BranchNode - if Condition if false, run this
*/
class BranchNode: public NoMoreChildrenNode {
public:
  BranchNode();

  GET_SET_SIGS(ExpressionNode, Condition)
  GET_SET_SIGS(BlockNode, SuccessBlock)
  GET_SIG(ASTNode, FailiureBlock)
  SET_SIG(BlockNode, FailiureBlock)
  SET_SIG(BranchNode, FailiureBlock)

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Represents a loop.

  Has 4 children:
    - Init - DeclarationNode
    - Condition - ExpressionNode
    - Update - ExpressionNode
    - Code - BlockNode
  Example on a for loop:
  for (Init, Condition, Update) Code
*/
class LoopNode: public NoMoreChildrenNode {
private:
  /// Used by the break statement
  llvm::BasicBlock* exitBlock;
public:
  LoopNode();

  GET_SET_SIGS(DeclarationNode, Init)
  GET_SET_SIGS(ExpressionNode, Condition)
  GET_SET_SIGS(ExpressionNode, Update)
  GET_SET_SIGS(BlockNode, Code)

  llvm::BasicBlock* getExitBlock() const;
  void setExitBlock(llvm::BasicBlock* bb);

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Return statement.

  Can have an ExpressionNode to be returned.
*/
class ReturnNode: public NoMoreChildrenNode {
public:
  ReturnNode();

  GET_SET_SIGS(ExpressionNode, Value)

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Break statement for exiting a loop.

  \todo maybe add loop labels so this can break a specific loop
*/
class BreakLoopNode: public NoMoreChildrenNode {
public:
  BreakLoopNode();

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

/**
  \brief Function definition.
*/
class FunctionNode: public NoMoreChildrenNode {
private:
  std::string ident;
  FunctionSignature sig;
public:
  FunctionNode(FunctionSignature sig);
  /// \param ident if empty, behaves just like FunctionNode(FunctionSignature)
  FunctionNode(std::string ident, FunctionSignature sig);

  GET_SET_SIGS(BlockNode, Code)

  std::string getIdentifier() const;
  const FunctionSignature& getSignature() const;
  bool isAnon() const;

  void printTree(uint level) const override;

  void visit(ASTVisitorLink visitor) override;
};

#undef GET_SIG
#undef SET_SIG
#undef GET_SET_SIGS

/**
  \brief Stores an abstract syntax tree of a program.
*/
class AST {
private:
  /// Root of AST
  Node<BlockNode>::Link root;
public:
  AST(Node<BlockNode>::Link lk);
  /// Print the tree
  void print() const;
  /// Get root
  Node<BlockNode>::Link getRoot() const;

  bool operator==(const AST& rhs) const;
  bool operator!=(const AST& rhs) const;
};

/**
  \see VISITOR_VISIT_IMPL_FOR
*/
#define PURE_VIRTUAL_VISIT(nodeName) virtual void visit##nodeName(Node<nodeName##Node>::Link node) = 0;

/**
  \brief Abstract class for visiting nodes on an AST.
*/
class ASTVisitor {
public:
  PURE_VIRTUAL_VISIT(Block)
  PURE_VIRTUAL_VISIT(Expression)
  PURE_VIRTUAL_VISIT(Declaration)
  PURE_VIRTUAL_VISIT(Branch)
  PURE_VIRTUAL_VISIT(Loop)
  PURE_VIRTUAL_VISIT(Return)
  PURE_VIRTUAL_VISIT(BreakLoop)
  PURE_VIRTUAL_VISIT(Function)
};

#undef PURE_VIRTUAL_VISIT

#endif
<|endoftext|>


<commit_before>#include "TensorFlowEngine.hpp"

//#define TF_CPP_MIN_LOG_LEVEL 5
//#define TF_CPP_MIN_VLOG_LEVEL 5
// Windows hack for removing need for protobuf
#ifdef WIN32
#include <google/protobuf/stubs/logging.h>
#undef GOOGLE_LOG_IF
#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
  !(CONDITION) ? std::clog : std::cerr
// end hack
#endif

//#include <tensorflow/core/framework/step_stats.pb.h>
//#include <tensorflow/core/framework/tensor.h>
//#include <tensorflow/core/framework/types.pb.h>
//#include <tensorflow/core/lib/strings/stringprintf.h>
//#include <tensorflow/core/platform/env.h>
//#include <tensorflow/core/platform/mutex.h>
//#include <tensorflow/core/platform/types.h>
#include <tensorflow/core/public/session.h>
//#include <tensorflow/core/graph/default_device.h>
//#include <tensorflow/core/platform/init_main.h>
//#include <tensorflow/cc/framework/ops.h>
//#include <tensorflow/core/platform/logging.h>
#include <FAST/Utility.hpp>

#include <tensorflow/cc/saved_model/loader.h>
#include <tensorflow/cc/saved_model/loader_util.h>
#include <tensorflow/cc/saved_model/tag_constants.h>
#include <tensorflow/cc/saved_model/reader.h>

namespace fast {

class TensorFlowTensorWrapper {
    public:
        explicit TensorFlowTensorWrapper(tensorflow::Tensor&& inTensor) : tensor(inTensor) {};
        tensorflow::Tensor tensor;
};

void TensorFlowTensor::create(TensorFlowTensorWrapper* wrapper) {
    m_tensorflowTensor = wrapper;
    auto shape = m_tensorflowTensor->tensor.shape();
    TensorShape fastShape;
    for(int i = 0; i < shape.dims(); ++i)
        fastShape.addDimension(shape.dim_size(i));

    m_shape = fastShape;
    m_spacing = VectorXf::Ones(m_shape.getDimensions());
    mHostDataIsUpToDate = true;
    if(m_shape.getDimensions() >= 3) {
        const int width = m_shape[m_shape.getDimensions() - 2];
        const int height = m_shape[m_shape.getDimensions() - 3];
        mBoundingBox = DataBoundingBox(Vector3f(width, height, 1));
    }
    /*
    // Unnecessary copy..
    auto data = make_uninitialized_unique<float[]>(fastShape.getTotalSize());
    std::memcpy(data.get(), tensorflowTensor.flat<float>().data(), fastShape.getTotalSize()*sizeof(float));
    Tensor::create(std::move(data), fastShape);
     */
}

bool TensorFlowTensor::hasAnyData() {
    return true;
}

TensorFlowTensor::~TensorFlowTensor() {
    delete m_tensorflowTensor;
}

float* TensorFlowTensor::getHostDataPointer() {
    return m_tensorflowTensor->tensor.flat<float>().data();
}

static TensorShape getShape(const tensorflow::NodeDef& node) {
    TensorShape resultShape;
    if(node.attr().count("shape") > 0) {
        auto shape = node.attr().at("shape").shape();
        for(int i = 0; i < shape.dim_size(); i++) {
            resultShape.addDimension(shape.dim(i).size());
        }
    }
    return resultShape;
}

void TensorFlowEngine::run() {
	if(mInputNodes.empty())
		throw Exception("At least one output node has to be given to the NeuralNetwork before execution");
	if(mOutputNodes.empty())
		throw Exception("At least one output node has to be given to the NeuralNetwork before execution");

	// For each input, create a tensorflow tensor:
	std::vector <std::pair<std::string, tensorflow::Tensor>> input_tensors;
	for(auto inputNode : mInputNodes) {
		const std::string name = inputNode.first;
		if(!inputNode.second.data)
			throw Exception("Input node " + name + " has not received any data");
		auto shape = inputNode.second.data->getShape();
		if(shape.getUnknownDimensions() > 0)
		    throw Exception("Input shape must be fully known when executing NN");

		// Construct tensorflow tensor
        tensorflow::TensorShape tensorShape;
        for(auto i : shape.getAll()) {
            tensorShape.AddDim(i);
        }
        tensorflow::Tensor input_tensor(
                tensorflow::DT_FLOAT,
                tensorShape
        );

        // Give tensor data to tensorflow
        // TODO is the data here actually moved?
        TensorAccess::pointer access = inputNode.second.data->getAccess(ACCESS_READ);
        switch(shape.getDimensions()) {
            case 2:
                input_tensor.tensor<float, 2>() = std::move(access->getData<2>());
                break;
            case 3:
                input_tensor.tensor<float, 3>() = std::move(access->getData<3>());
                break;
            case 4:
                input_tensor.tensor<float, 4>() = std::move(access->getData<4>());
                break;
            case 5:
                input_tensor.tensor<float, 5>() = std::move(access->getData<5>());
                break;
			case 6:
				input_tensor.tensor<float, 6>() = std::move(access->getData<6>());
				break;
            default:
                throw Exception("Invalid tensor dimension size");
		}

		// Add tensorflow tensor to list of input tensors
		input_tensors.push_back(std::make_pair(name, input_tensor));
	}

    for(std::string name : mLearningPhaseTensors) {
        // Create a scalar tensor which tells the system we are NOT doing training
        tensorflow::Tensor input_tensor2(
                tensorflow::DT_BOOL,
                tensorflow::TensorShape() // Scalar
        );
        auto input_tensor_mapped2 = input_tensor2.tensor<bool, 0>();
        input_tensor_mapped2(0) = false;
        input_tensors.push_back(std::make_pair(name, input_tensor2));
    }

	std::vector<tensorflow::Tensor> output_tensors;

	reportInfo() << "Running network" << reportEnd();
	tensorflow::Status s;
	//mRuntimeManager->startRegularTimer("network_execution");
	std::vector<std::string> outputNames;
	for(auto node : mOutputNodes)
	    outputNames.push_back(node.first);
	s = mSession->Run(input_tensors, outputNames, {}, &output_tensors);
	//mRuntimeManager->stopRegularTimer("network_execution");

	if (!s.ok()) {
		throw Exception("Error during inference: " + s.ToString());
	}
	reportInfo() << "Finished executing network" << reportEnd();

    // Collect all output data as FAST tensors
    for(int j = 0; j < outputNames.size(); ++j) {
        const std::string outputName = outputNames[j];
        const NetworkNode node = mOutputNodes[outputName];
        auto tensor = TensorFlowTensor::New();
        tensor->create(new TensorFlowTensorWrapper(std::move(output_tensors[j])));
        mOutputNodes[outputName].data = tensor;
	}
	reportInfo() << "Finished parsing output" << reportEnd();
}

void TensorFlowEngine::load() {
    const auto networkFilename = getFilename();
    tensorflow::SessionOptions options;
    tensorflow::ConfigProto &config = options.config;
#ifndef WIN32
    // These lines cause linking issues on windows
    config.mutable_gpu_options()->set_allow_growth(true); // Set this so that tensorflow will not use up all GPU memory
    if (m_deviceType == InferenceDeviceType::CPU) {
        config.mutable_gpu_options()->set_visible_device_list("");
    } else if (m_deviceIndex >= 0) {
        config.mutable_gpu_options()->set_visible_device_list(std::to_string(m_deviceIndex));
    }
#endif
    /*
	tensorflow::GPUOptions* gpuOptions = config.mutable_gpu_options();
	gpuOptions->set_allow_growth(true);
	//gpuOptions->set_per_process_gpu_memory_fraction(0.5);
    */

	tensorflow::GraphDef tensorflow_graph;

	if(networkFilename.substr(networkFilename.size()-3) == ".pb" || tensorflow::MaybeSavedModelDirectory(networkFilename) == false) {
	    // Load a frozen protobuf file (.pb)
        if(!fileExists(networkFilename))
            throw Exception(networkFilename + " does not exist");
        reportInfo() << "Loading network file: " << networkFilename << reportEnd();
        tensorflow::Status s = ReadBinaryProto(tensorflow::Env::Default(), networkFilename, &tensorflow_graph);
        if (!s.ok()) {
            throw Exception("Could not read TensorFlow graph file " + networkFilename);
        }
        reportInfo() << "Creating session." << reportEnd();
        mSession.reset(tensorflow::NewSession(options));
        s = mSession->Create(tensorflow_graph);
        if (!s.ok()) {
            throw Exception("Could not create TensorFlow Graph: " + s.error_message());
        }
	} else {
	    // Load a model stored in the SavedModel format
        mSavedModelBundle = std::make_unique<tensorflow::SavedModelBundle>();
        tensorflow::RunOptions runOptions;
        auto s = tensorflow::LoadSavedModel(options, runOptions, networkFilename, {tensorflow::kSavedModelTagServe}, mSavedModelBundle.get());
        if(!s.ok()) {
            throw Exception("Could not read TensorFlow SavedModel from " + networkFilename);
        }
        tensorflow::MetaGraphDef metaGraphDef = mSavedModelBundle->meta_graph_def;
        mSession.reset(mSavedModelBundle->GetSession());
        tensorflow_graph = metaGraphDef.graph_def();
	}

	// Analyze nodes to find input node
	bool nodesSpecified = true;
    int inputCounter = 0;
	if(mInputNodes.size() == 0) {
		nodesSpecified = false;
	}

    for(int i = 0; i < tensorflow_graph.node_size(); ++i) {
		tensorflow::NodeDef node = tensorflow_graph.node(i);
		if(mInputNodes.count(node.name()) > 0) {
		}
		if(node.op() == "Placeholder") {
			if(node.name().find("keras_learning_phase") != std::string::npos) {
				//mLearningPhaseTensors.insert(node.name());
				mLearningPhaseTensors.push_back(node.name());
			} else {
				// Input node found:
				// Get its shape
				// Input nodes use the Op Placeholder
				reportInfo() << "Found input node: " << i << " with name " << node.name() << reportEnd();
				auto shape = getShape(node);
				reportInfo() << "Node has shape " << shape.toString() << reportEnd();
				if(mInputNodes.count(node.name()) == 0) {
					if(nodesSpecified) {
						throw Exception("Encountered unknown node " + node.name());
					}
					reportInfo() << "Node was not specified by user" << reportEnd();
					// If node has not been specified by user, we need to add it
					// and thus know its type (fast image or tensor)
					// It is assumed to be an image if input shape has at least 4 dimensions
					NodeType type = NodeType::TENSOR;
					if(shape.getDimensions() >= 4) {
						reportInfo() << "Assuming node is an image" << reportEnd();
						type = NodeType::IMAGE;
					} else if(shape.getDimensions() > 0) {
						reportInfo() << "Assuming node is a tensor" << reportEnd();
					} else {
						reportInfo() << "Node has dimension 0, skipping.." << reportEnd();
						continue;
					}
					addInputNode(inputCounter, node.name(), type, shape);
					++inputCounter;
				}
			}
		}
	}

    // If no output nodes, guess that last node is the output node
    if(mOutputNodes.empty()) {
        tensorflow::NodeDef node = tensorflow_graph.node(tensorflow_graph.node_size()-1);
        reportWarning() << "No output nodes were given to TensorFlow engine, FAST is guessing it is the last node with name " << node.name() << reportEnd();
        addOutputNode(0, node.name());
    }

	// Clear the proto to save memory space.
	tensorflow_graph.Clear();

	reportInfo() << "TensorFlow graph loaded from: " << networkFilename << reportEnd();

	setIsLoaded(true);
}

TensorFlowEngine::TensorFlowEngine() {

}

TensorFlowEngine::~TensorFlowEngine() {
	if(mSession) {
		mSession->Close();
	}
}

ImageOrdering TensorFlowEngine::getPreferredImageOrdering() const {
	return ImageOrdering::ChannelLast;
}

std::string TensorFlowEngine::getName() const {
    return "TensorFlow";
}

std::string TensorFlowEngine::getDefaultFileExtension() const {
    return "pb";
}

std::vector<InferenceDeviceInfo> TensorFlowEngine::getDeviceList() {
    std::vector<InferenceDeviceInfo> result;
    InferenceDeviceInfo cpu;
    cpu.type = InferenceDeviceType::CPU;
    cpu.index = 0;
    result.push_back(cpu);
#ifdef FAST_TENSORFLOW_BUILD_CUDA
    {
        // TODO how to query number of devices?
        InferenceDeviceInfo device;
        device.type = InferenceDeviceType::GPU;
        device.index = 0;
        result.push_back(device);
    }
#endif
#ifdef FAST_TENSORFLOW_BUILD_ROCM
    {
        // TODO ROCm how?
        InferenceDeviceInfo device;
        device.type = InferenceDeviceType::GPU;
        device.index = 0;
        result.push_back(device);
    }
#endif
    return result;
}

}
<commit_msg>Enabled allow_growth an other session options for Windows, which was excluded previously due to linking issues which have been resolved<commit_after>#include "TensorFlowEngine.hpp"

//#define TF_CPP_MIN_LOG_LEVEL 5
//#define TF_CPP_MIN_VLOG_LEVEL 5
// Windows hack for removing need for protobuf
#ifdef WIN32
#include <google/protobuf/stubs/logging.h>
#undef GOOGLE_LOG_IF
#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
  !(CONDITION) ? std::clog : std::cerr
// end hack
#endif

//#include <tensorflow/core/framework/step_stats.pb.h>
//#include <tensorflow/core/framework/tensor.h>
//#include <tensorflow/core/framework/types.pb.h>
//#include <tensorflow/core/lib/strings/stringprintf.h>
//#include <tensorflow/core/platform/env.h>
//#include <tensorflow/core/platform/mutex.h>
//#include <tensorflow/core/platform/types.h>
#include <tensorflow/core/public/session.h>
//#include <tensorflow/core/graph/default_device.h>
//#include <tensorflow/core/platform/init_main.h>
//#include <tensorflow/cc/framework/ops.h>
//#include <tensorflow/core/platform/logging.h>
#include <FAST/Utility.hpp>

#include <tensorflow/cc/saved_model/loader.h>
#include <tensorflow/cc/saved_model/loader_util.h>
#include <tensorflow/cc/saved_model/tag_constants.h>
#include <tensorflow/cc/saved_model/reader.h>

namespace fast {

class TensorFlowTensorWrapper {
    public:
        explicit TensorFlowTensorWrapper(tensorflow::Tensor&& inTensor) : tensor(inTensor) {};
        tensorflow::Tensor tensor;
};

void TensorFlowTensor::create(TensorFlowTensorWrapper* wrapper) {
    m_tensorflowTensor = wrapper;
    auto shape = m_tensorflowTensor->tensor.shape();
    TensorShape fastShape;
    for(int i = 0; i < shape.dims(); ++i)
        fastShape.addDimension(shape.dim_size(i));

    m_shape = fastShape;
    m_spacing = VectorXf::Ones(m_shape.getDimensions());
    mHostDataIsUpToDate = true;
    if(m_shape.getDimensions() >= 3) {
        const int width = m_shape[m_shape.getDimensions() - 2];
        const int height = m_shape[m_shape.getDimensions() - 3];
        mBoundingBox = DataBoundingBox(Vector3f(width, height, 1));
    }
    /*
    // Unnecessary copy..
    auto data = make_uninitialized_unique<float[]>(fastShape.getTotalSize());
    std::memcpy(data.get(), tensorflowTensor.flat<float>().data(), fastShape.getTotalSize()*sizeof(float));
    Tensor::create(std::move(data), fastShape);
     */
}

bool TensorFlowTensor::hasAnyData() {
    return true;
}

TensorFlowTensor::~TensorFlowTensor() {
    delete m_tensorflowTensor;
}

float* TensorFlowTensor::getHostDataPointer() {
    return m_tensorflowTensor->tensor.flat<float>().data();
}

static TensorShape getShape(const tensorflow::NodeDef& node) {
    TensorShape resultShape;
    if(node.attr().count("shape") > 0) {
        auto shape = node.attr().at("shape").shape();
        for(int i = 0; i < shape.dim_size(); i++) {
            resultShape.addDimension(shape.dim(i).size());
        }
    }
    return resultShape;
}

void TensorFlowEngine::run() {
	if(mInputNodes.empty())
		throw Exception("At least one output node has to be given to the NeuralNetwork before execution");
	if(mOutputNodes.empty())
		throw Exception("At least one output node has to be given to the NeuralNetwork before execution");

	// For each input, create a tensorflow tensor:
	std::vector <std::pair<std::string, tensorflow::Tensor>> input_tensors;
	for(auto inputNode : mInputNodes) {
		const std::string name = inputNode.first;
		if(!inputNode.second.data)
			throw Exception("Input node " + name + " has not received any data");
		auto shape = inputNode.second.data->getShape();
		if(shape.getUnknownDimensions() > 0)
		    throw Exception("Input shape must be fully known when executing NN");

		// Construct tensorflow tensor
        tensorflow::TensorShape tensorShape;
        for(auto i : shape.getAll()) {
            tensorShape.AddDim(i);
        }
        tensorflow::Tensor input_tensor(
                tensorflow::DT_FLOAT,
                tensorShape
        );

        // Give tensor data to tensorflow
        // TODO is the data here actually moved?
        TensorAccess::pointer access = inputNode.second.data->getAccess(ACCESS_READ);
        switch(shape.getDimensions()) {
            case 2:
                input_tensor.tensor<float, 2>() = std::move(access->getData<2>());
                break;
            case 3:
                input_tensor.tensor<float, 3>() = std::move(access->getData<3>());
                break;
            case 4:
                input_tensor.tensor<float, 4>() = std::move(access->getData<4>());
                break;
            case 5:
                input_tensor.tensor<float, 5>() = std::move(access->getData<5>());
                break;
			case 6:
				input_tensor.tensor<float, 6>() = std::move(access->getData<6>());
				break;
            default:
                throw Exception("Invalid tensor dimension size");
		}

		// Add tensorflow tensor to list of input tensors
		input_tensors.push_back(std::make_pair(name, input_tensor));
	}

    for(std::string name : mLearningPhaseTensors) {
        // Create a scalar tensor which tells the system we are NOT doing training
        tensorflow::Tensor input_tensor2(
                tensorflow::DT_BOOL,
                tensorflow::TensorShape() // Scalar
        );
        auto input_tensor_mapped2 = input_tensor2.tensor<bool, 0>();
        input_tensor_mapped2(0) = false;
        input_tensors.push_back(std::make_pair(name, input_tensor2));
    }

	std::vector<tensorflow::Tensor> output_tensors;

	reportInfo() << "Running network" << reportEnd();
	tensorflow::Status s;
	//mRuntimeManager->startRegularTimer("network_execution");
	std::vector<std::string> outputNames;
	for(auto node : mOutputNodes)
	    outputNames.push_back(node.first);
	s = mSession->Run(input_tensors, outputNames, {}, &output_tensors);
	//mRuntimeManager->stopRegularTimer("network_execution");

	if (!s.ok()) {
		throw Exception("Error during inference: " + s.ToString());
	}
	reportInfo() << "Finished executing network" << reportEnd();

    // Collect all output data as FAST tensors
    for(int j = 0; j < outputNames.size(); ++j) {
        const std::string outputName = outputNames[j];
        const NetworkNode node = mOutputNodes[outputName];
        auto tensor = TensorFlowTensor::New();
        tensor->create(new TensorFlowTensorWrapper(std::move(output_tensors[j])));
        mOutputNodes[outputName].data = tensor;
	}
	reportInfo() << "Finished parsing output" << reportEnd();
}

void TensorFlowEngine::load() {
    // Setup tensorflow session options
    tensorflow::SessionOptions options;
    tensorflow::ConfigProto &config = options.config;
    config.mutable_gpu_options()->set_allow_growth(true); // Set this so that tensorflow will not use up all GPU memory
    if (m_deviceType == InferenceDeviceType::CPU) {
        config.mutable_gpu_options()->set_visible_device_list(""); // Hide devices to force CPU execution
    } else if (m_deviceIndex >= 0) {
        config.mutable_gpu_options()->set_visible_device_list(std::to_string(m_deviceIndex)); // Use specific GPU
    }

	tensorflow::GraphDef tensorflow_graph;

    const auto networkFilename = getFilename();
	if(networkFilename.substr(networkFilename.size()-3) == ".pb" || tensorflow::MaybeSavedModelDirectory(networkFilename) == false) {
	    // Load a frozen protobuf file (.pb)
        if(!fileExists(networkFilename))
            throw Exception(networkFilename + " does not exist");
        reportInfo() << "Loading network file: " << networkFilename << reportEnd();
        tensorflow::Status s = ReadBinaryProto(tensorflow::Env::Default(), networkFilename, &tensorflow_graph);
        if (!s.ok()) {
            throw Exception("Could not read TensorFlow graph file " + networkFilename);
        }
        reportInfo() << "Creating session." << reportEnd();
        mSession.reset(tensorflow::NewSession(options));
        s = mSession->Create(tensorflow_graph);
        if (!s.ok()) {
            throw Exception("Could not create TensorFlow Graph: " + s.error_message());
        }
	} else {
	    // Load a model stored in the SavedModel format
        mSavedModelBundle = std::make_unique<tensorflow::SavedModelBundle>();
        tensorflow::RunOptions runOptions;
        auto s = tensorflow::LoadSavedModel(options, runOptions, networkFilename, {tensorflow::kSavedModelTagServe}, mSavedModelBundle.get());
        if(!s.ok()) {
            throw Exception("Could not read TensorFlow SavedModel from " + networkFilename);
        }
        tensorflow::MetaGraphDef metaGraphDef = mSavedModelBundle->meta_graph_def;
        mSession.reset(mSavedModelBundle->GetSession());
        tensorflow_graph = metaGraphDef.graph_def();
	}

	// Analyze nodes to find input node
	bool nodesSpecified = true;
    int inputCounter = 0;
	if(mInputNodes.size() == 0) {
		nodesSpecified = false;
	}

    for(int i = 0; i < tensorflow_graph.node_size(); ++i) {
		tensorflow::NodeDef node = tensorflow_graph.node(i);
		if(mInputNodes.count(node.name()) > 0) {
		}
		if(node.op() == "Placeholder") {
			if(node.name().find("keras_learning_phase") != std::string::npos) {
				//mLearningPhaseTensors.insert(node.name());
				mLearningPhaseTensors.push_back(node.name());
			} else {
				// Input node found:
				// Get its shape
				// Input nodes use the Op Placeholder
				reportInfo() << "Found input node: " << i << " with name " << node.name() << reportEnd();
				auto shape = getShape(node);
				reportInfo() << "Node has shape " << shape.toString() << reportEnd();
				if(mInputNodes.count(node.name()) == 0) {
					if(nodesSpecified) {
						throw Exception("Encountered unknown node " + node.name());
					}
					reportInfo() << "Node was not specified by user" << reportEnd();
					// If node has not been specified by user, we need to add it
					// and thus know its type (fast image or tensor)
					// It is assumed to be an image if input shape has at least 4 dimensions
					NodeType type = NodeType::TENSOR;
					if(shape.getDimensions() >= 4) {
						reportInfo() << "Assuming node is an image" << reportEnd();
						type = NodeType::IMAGE;
					} else if(shape.getDimensions() > 0) {
						reportInfo() << "Assuming node is a tensor" << reportEnd();
					} else {
						reportInfo() << "Node has dimension 0, skipping.." << reportEnd();
						continue;
					}
					addInputNode(inputCounter, node.name(), type, shape);
					++inputCounter;
				}
			}
		}
	}

    // If no output nodes, guess that last node is the output node
    if(mOutputNodes.empty()) {
        tensorflow::NodeDef node = tensorflow_graph.node(tensorflow_graph.node_size()-1);
        reportWarning() << "No output nodes were given to TensorFlow engine, FAST is guessing it is the last node with name " << node.name() << reportEnd();
        addOutputNode(0, node.name());
    }

	// Clear the proto to save memory space.
	tensorflow_graph.Clear();

	reportInfo() << "TensorFlow graph loaded from: " << networkFilename << reportEnd();

	setIsLoaded(true);
}

TensorFlowEngine::TensorFlowEngine() {

}

TensorFlowEngine::~TensorFlowEngine() {
	if(mSession) {
		mSession->Close();
	}
}

ImageOrdering TensorFlowEngine::getPreferredImageOrdering() const {
	return ImageOrdering::ChannelLast;
}

std::string TensorFlowEngine::getName() const {
    return "TensorFlow";
}

std::string TensorFlowEngine::getDefaultFileExtension() const {
    return "pb";
}

std::vector<InferenceDeviceInfo> TensorFlowEngine::getDeviceList() {
    std::vector<InferenceDeviceInfo> result;
    InferenceDeviceInfo cpu;
    cpu.type = InferenceDeviceType::CPU;
    cpu.index = 0;
    result.push_back(cpu);
#ifdef FAST_TENSORFLOW_BUILD_CUDA
    {
        // TODO how to query number of devices?
        InferenceDeviceInfo device;
        device.type = InferenceDeviceType::GPU;
        device.index = 0;
        result.push_back(device);
    }
#endif
#ifdef FAST_TENSORFLOW_BUILD_ROCM
    {
        // TODO ROCm how?
        InferenceDeviceInfo device;
        device.type = InferenceDeviceType::GPU;
        device.index = 0;
        result.push_back(device);
    }
#endif
    return result;
}

}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/nest/p10_chiplet_fabric_scominit.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p10_chiplet_fabric_scominit.C
/// @brief Apply fabric scom inits to prepare for xlink enablement
///
/// *HWP HW Maintainer: Jenny Huynh <jhuynh@us.ibm.com>
/// *HWP FW Maintainer: Ilya Smirnov <ismirno@us.ibm.com>
/// *HWP Consumed by: HB
///

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <p10_chiplet_fabric_scominit.H>
#include <p10_smp_link_firs.H>
#include <p10_fbc_utils.H>
#include <p10_fbc_no_hp_scom.H>
#include <p10_fbc_ptl_scom.H>
#include <p10_fbc_dlp_scom.H>

#include <p10_scom_proc.H>

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

fapi2::ReturnCode p10_chiplet_fabric_scominit(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const bool i_config_intranode,
    const bool i_config_internode)
{
    FAPI_DBG("Start");
    FAPI_DBG("  i_config_intranode: %d", i_config_intranode);
    FAPI_DBG("  i_config_internode: %d", i_config_internode);

    fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM;
    auto l_iohs_targets = i_target.getChildren<fapi2::TARGET_TYPE_IOHS>();
    char l_tgt_str[fapi2::MAX_ECMD_STRING_LEN];
    fapi2::ReturnCode l_rc;

    if (i_config_intranode)
    {
        // apply FBC non-hotplug scom initfile
        fapi2::toString(i_target, l_tgt_str, sizeof(l_tgt_str));
        FAPI_DBG("Invoking p10.fbc.no_hp.scom.initfile on target %s...", l_tgt_str);
        FAPI_EXEC_HWP(l_rc, p10_fbc_no_hp_scom, i_target, FAPI_SYSTEM);
        FAPI_TRY(l_rc, "Error from p10_fbc_no_hp_scom");

        // mask FIRs on proc/pauc scope if there are no valid links
        if(!l_iohs_targets.size())
        {
            auto l_iohs_present = i_target.getChildren<fapi2::TARGET_TYPE_IOHS>(fapi2::TARGET_STATE_PRESENT);

            for(auto l_iohs : l_iohs_present)
            {
                FAPI_TRY(p10_smp_link_firs(l_iohs, sublink_t::BOTH, action_t::INACTIVE),
                         "Error from p10_smp_link_firs when masking firs for all links");
            }
        }
    }

    for (auto l_iohs : l_iohs_targets)
    {
        fapi2::ATTR_PROC_FABRIC_LINK_ACTIVE_Type l_fabric_link_active;
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_LINK_ACTIVE, l_iohs, l_fabric_link_active),
                 "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_LINK_ACTIVE)");

        if(l_fabric_link_active == fapi2::ENUM_ATTR_PROC_FABRIC_LINK_ACTIVE_TRUE)
        {
            fapi2::ATTR_IOHS_DRAWER_INTERCONNECT_Type l_drawer_interconnect;
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IOHS_DRAWER_INTERCONNECT, l_iohs, l_drawer_interconnect),
                     "Error from FAPI_ATTR_GET (ATTR_IOHS_DRAWER_INTERCONNECT)");

            if((i_config_intranode && (l_drawer_interconnect == fapi2::ENUM_ATTR_IOHS_DRAWER_INTERCONNECT_FALSE)) ||
               (i_config_internode && (l_drawer_interconnect == fapi2::ENUM_ATTR_IOHS_DRAWER_INTERCONNECT_TRUE)))
            {
                auto l_pauc = l_iohs.getParent<fapi2::TARGET_TYPE_PAUC>();
                fapi2::ATTR_IOHS_LINK_TRAIN_Type l_link_train;
                sublink_t sublink_opt;

                // apply FBC TL scom initfile
                fapi2::toString(l_pauc, l_tgt_str, sizeof(l_tgt_str));
                FAPI_DBG("Invoking p10.fbc.ptl.scom.initfile on target %s...", l_tgt_str);
                FAPI_EXEC_HWP(l_rc, p10_fbc_ptl_scom, l_pauc, i_target, FAPI_SYSTEM);
                FAPI_TRY(l_rc, "Error from p10_fbc_ptl_scom");

                // apply FBC DL scom initfile
                fapi2::toString(l_iohs, l_tgt_str, sizeof(l_tgt_str));
                FAPI_DBG("Invoking p10.fbc.dlp.scom.initfile on target %s...", l_tgt_str);
                FAPI_EXEC_HWP(l_rc, p10_fbc_dlp_scom, l_iohs, i_target, FAPI_SYSTEM);
                FAPI_TRY(l_rc, "Error from p10_fbc_dlp_scom");

                FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IOHS_LINK_TRAIN, l_iohs, l_link_train),
                         "Error from FAPI_ATTR_GET (ATTR_IOHS_LINK_TRAIN)");

                switch(l_link_train)
                {
                    case fapi2::ENUM_ATTR_IOHS_LINK_TRAIN_BOTH:
                        sublink_opt = sublink_t::BOTH;
                        break;

                    case fapi2::ENUM_ATTR_IOHS_LINK_TRAIN_EVEN_ONLY:
                        sublink_opt = sublink_t::EVEN;
                        break;

                    case fapi2::ENUM_ATTR_IOHS_LINK_TRAIN_ODD_ONLY:
                        sublink_opt = sublink_t::ODD;
                        break;

                    default:
                        sublink_opt = sublink_t::NONE;
                        break;
                }

                // setup and unmask TL/DL FIRs
                FAPI_TRY(p10_smp_link_firs(l_iohs, sublink_opt, action_t::RUNTIME),
                         "Error from p10_smp_link_firs when configuring for runtime operations");
            }
        }
        else
        {
            // mask TL/DL FIRs for links that are not configured for smp operations
            if (i_config_intranode)
            {
                FAPI_TRY(p10_smp_link_firs(l_iohs, sublink_t::BOTH, action_t::INACTIVE),
                         "Error from p10_smp_link_firs when configuring both sublinks for inactive operations");
            }
        }
    }

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
<commit_msg>Mask all link firs before configuring link settings<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/nest/p10_chiplet_fabric_scominit.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p10_chiplet_fabric_scominit.C
/// @brief Apply fabric scom inits to prepare for xlink enablement
///
/// *HWP HW Maintainer: Jenny Huynh <jhuynh@us.ibm.com>
/// *HWP FW Maintainer: Ilya Smirnov <ismirno@us.ibm.com>
/// *HWP Consumed by: HB
///

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <p10_chiplet_fabric_scominit.H>
#include <p10_smp_link_firs.H>
#include <p10_fbc_utils.H>
#include <p10_fbc_no_hp_scom.H>
#include <p10_fbc_ptl_scom.H>
#include <p10_fbc_dlp_scom.H>

#include <p10_scom_proc.H>

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

fapi2::ReturnCode p10_chiplet_fabric_scominit(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const bool i_config_intranode,
    const bool i_config_internode)
{
    FAPI_DBG("Start");
    FAPI_DBG("  i_config_intranode: %d", i_config_intranode);
    FAPI_DBG("  i_config_internode: %d", i_config_internode);

    fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM;
    auto l_iohs_targets = i_target.getChildren<fapi2::TARGET_TYPE_IOHS>();
    char l_tgt_str[fapi2::MAX_ECMD_STRING_LEN];
    fapi2::ReturnCode l_rc;

    if (i_config_intranode)
    {
        // apply FBC non-hotplug scom initfile
        fapi2::toString(i_target, l_tgt_str, sizeof(l_tgt_str));
        FAPI_DBG("Invoking p10.fbc.no_hp.scom.initfile on target %s...", l_tgt_str);
        FAPI_EXEC_HWP(l_rc, p10_fbc_no_hp_scom, i_target, FAPI_SYSTEM);
        FAPI_TRY(l_rc, "Error from p10_fbc_no_hp_scom");

        // init all FIRs as inactive before applying configuration
        for(auto l_iohs : i_target.getChildren<fapi2::TARGET_TYPE_IOHS>(fapi2::TARGET_STATE_PRESENT))
        {
            FAPI_TRY(p10_smp_link_firs(l_iohs, sublink_t::BOTH, action_t::INACTIVE),
                     "Error from p10_smp_link_firs when masking firs for all links");
        }
    }

    for (auto l_iohs : l_iohs_targets)
    {
        fapi2::ATTR_PROC_FABRIC_LINK_ACTIVE_Type l_fabric_link_active;
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_LINK_ACTIVE, l_iohs, l_fabric_link_active),
                 "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_LINK_ACTIVE)");

        if(l_fabric_link_active == fapi2::ENUM_ATTR_PROC_FABRIC_LINK_ACTIVE_TRUE)
        {
            fapi2::ATTR_IOHS_DRAWER_INTERCONNECT_Type l_drawer_interconnect;
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IOHS_DRAWER_INTERCONNECT, l_iohs, l_drawer_interconnect),
                     "Error from FAPI_ATTR_GET (ATTR_IOHS_DRAWER_INTERCONNECT)");

            if((i_config_intranode && (l_drawer_interconnect == fapi2::ENUM_ATTR_IOHS_DRAWER_INTERCONNECT_FALSE)) ||
               (i_config_internode && (l_drawer_interconnect == fapi2::ENUM_ATTR_IOHS_DRAWER_INTERCONNECT_TRUE)))
            {
                auto l_pauc = l_iohs.getParent<fapi2::TARGET_TYPE_PAUC>();
                fapi2::ATTR_IOHS_LINK_TRAIN_Type l_link_train;
                sublink_t sublink_opt;

                // apply FBC TL scom initfile
                fapi2::toString(l_pauc, l_tgt_str, sizeof(l_tgt_str));
                FAPI_DBG("Invoking p10.fbc.ptl.scom.initfile on target %s...", l_tgt_str);
                FAPI_EXEC_HWP(l_rc, p10_fbc_ptl_scom, l_pauc, i_target, FAPI_SYSTEM);
                FAPI_TRY(l_rc, "Error from p10_fbc_ptl_scom");

                // apply FBC DL scom initfile
                fapi2::toString(l_iohs, l_tgt_str, sizeof(l_tgt_str));
                FAPI_DBG("Invoking p10.fbc.dlp.scom.initfile on target %s...", l_tgt_str);
                FAPI_EXEC_HWP(l_rc, p10_fbc_dlp_scom, l_iohs, i_target, FAPI_SYSTEM);
                FAPI_TRY(l_rc, "Error from p10_fbc_dlp_scom");

                FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IOHS_LINK_TRAIN, l_iohs, l_link_train),
                         "Error from FAPI_ATTR_GET (ATTR_IOHS_LINK_TRAIN)");

                switch(l_link_train)
                {
                    case fapi2::ENUM_ATTR_IOHS_LINK_TRAIN_BOTH:
                        sublink_opt = sublink_t::BOTH;
                        break;

                    case fapi2::ENUM_ATTR_IOHS_LINK_TRAIN_EVEN_ONLY:
                        sublink_opt = sublink_t::EVEN;
                        break;

                    case fapi2::ENUM_ATTR_IOHS_LINK_TRAIN_ODD_ONLY:
                        sublink_opt = sublink_t::ODD;
                        break;

                    default:
                        sublink_opt = sublink_t::NONE;
                        break;
                }

                // setup and unmask TL/DL FIRs
                FAPI_TRY(p10_smp_link_firs(l_iohs, sublink_opt, action_t::RUNTIME),
                         "Error from p10_smp_link_firs when configuring for runtime operations");
            }
        }
        else
        {
            // mask TL/DL FIRs for links that are not configured for smp operations
            if (i_config_intranode)
            {
                FAPI_TRY(p10_smp_link_firs(l_iohs, sublink_t::BOTH, action_t::INACTIVE),
                         "Error from p10_smp_link_firs when configuring both sublinks for inactive operations");
            }
        }
    }

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 BrewPi/Elco Jacobs.
 *
 * This file is part of BrewPi.
 *
 * BrewPi is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * BrewPi 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 BrewPi.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "temperatureFormats.h"
#include <string.h>
#include <Arduino.h> // uses constrain function from Arduino.h
#include <limits.h>
#include "TempControl.h"

// result can have maximum length of : sign + 3 digits integer part + point + 3 digits fraction part + '\0' = 9 bytes;
// only 1, 2 or 3 decimals allowed.
// returns pointer to the string
// fixed7_23 is used to prevent overflow
char * tempToString(char s[9], fixed23_9 rawValue, uint8_t numDecimals, uint8_t maxLength){
	if(rawValue == INT_MIN){
		strcpy_P(s, PSTR("null"));
		return s;
	}
	if(tempControl.cc.tempFormat == 'F'){
		rawValue = (rawValue * 9) / 5 + (32 << 9); // convert to Fahrenheit first
	}
	return fixedPointToString(s, rawValue, numDecimals, maxLength);
}

char * fixedPointToString(char s[9], fixed23_9 rawValue, uint8_t numDecimals, uint8_t maxLength){
	if(rawValue < 0l){
		s[0] = '-';
		rawValue = -rawValue;
	}
	else{
		s[0] = ' ';
	}

	int intPart = rawValue >> 9;
	uint16_t fracPart;
	if(numDecimals == 1){
		fracPart = ((rawValue & 0x01FF) * 10 + 256) >> 9; // add 256 for rounding
		if(fracPart >= 10){
			intPart++;
			fracPart = 0; // has already overflowed into integer part.
		}
		snprintf_P(&s[1], maxLength-1, PSTR("%d.%01d"), intPart, fracPart);
	}
	else if(numDecimals == 2){
		fracPart = ((rawValue  & 0x01FF) * 100 + 256) >> 9;
		if(fracPart >= 100){
			intPart++;
			fracPart = 0; // has already overflowed into integer part.
		}
		snprintf_P(&s[1], maxLength-1, PSTR("%d.%02d"), intPart, fracPart);
	}
	else{
		fracPart = ((rawValue  & 0x01FF) * 1000 + 256) >> 9;
		if(fracPart>=1000){
			intPart++;
			fracPart = 0; // has already overflowed into integer part.
		}
		snprintf_P(&s[1], maxLength-1, PSTR("%d.%03d"),  intPart, fracPart);
	}
	return s;
}

fixed7_9 stringToTemp(char * numberString){
	fixed23_9 rawTemp = stringToFixedPoint(numberString);

	if(tempControl.cc.tempFormat == 'F'){
		rawTemp = ((rawTemp - (32 << 9)) * 5) / 9; // convert to store as Celsius
	}

	return constrain(rawTemp, INT_MIN, INT_MAX);
}

fixed23_9 stringToFixedPoint(char * numberString){
	// receive new temperature as null terminated string: "19.20"
	fixed23_9 intPart = 0;
	fixed23_9 fracPart = 0;

	char * fractPtr = 0; //pointer to the point in the string
	char sign = 1;
	if(numberString[0] == '-'){
		numberString++;
		sign = -1; // by processing the sign here, we don't have to include strtol
	}

	// find the point in the string to split in the integer part and the fraction part
	fractPtr = strchrnul(numberString, '.'); // returns pointer to the point.

	intPart = strtoul(numberString, NULL, 10);
	if(fractPtr != 0){
		// decimal point was found
		char * fractEndPtr;
		fractPtr++; // add 1 to pointer to skip point
		fracPart = strtoul(fractPtr,&fractEndPtr, 10);
		uint8_t numDecimals = fractEndPtr - fractPtr;
		fracPart = fracPart << 9; // 9 bits for fraction part
		while(numDecimals > 0){
			fracPart = (fracPart + 5) / 10; // divide by 10 rounded
			numDecimals--;
		}
	}
	return sign * ((intPart<<9) +fracPart);
}

char * tempDiffToString(char s[9], fixed23_9 rawValue, uint8_t numDecimals, uint8_t maxLength){
	if(tempControl.cc.tempFormat == 'F'){
		rawValue = (rawValue * 9) / 5; // convert to Fahrenheit first
	}
	return fixedPointToString(s, rawValue, numDecimals, maxLength);
}

fixed7_9 stringToTempDiff(char * numberString){
	fixed23_9 rawTempDiff = stringToFixedPoint(numberString);

	if(tempControl.cc.tempFormat == 'F'){
		rawTempDiff = (rawTempDiff * 5) / 9; // convert to store as Celsius
	}

	return constrain(rawTempDiff, INT_MIN, INT_MAX);
}

int fixedToTenths(fixed23_9 temperature){
	if(tempControl.cc.tempFormat == 'F'){
		temperature = temperature*9/5 + 32*512; // Convert to Fahrenheit fixed point first
	}

	return (int) ((10 * temperature + 256) / 512); // return rounded result in tenth of degrees
}

fixed7_9 tenthsToFixed(int temperature){
	if(tempControl.cc.tempFormat == 'F'){
		return (( ( (fixed23_9) temperature - 320) * 512 * 5) / 9 + 5) / 10; // convert to Celsius and return rounded result in fixed point
	}
	else{
		return ((fixed23_9) temperature * 512 + 5) / 10; // return rounded result in fixed point
	}
}<commit_msg>Fix: negative temperatures where not processed correctly.<commit_after>/*
 * Copyright 2012 BrewPi/Elco Jacobs.
 *
 * This file is part of BrewPi.
 *
 * BrewPi is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * BrewPi 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 BrewPi.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "temperatureFormats.h"
#include <string.h>
#include <Arduino.h> // uses constrain function from Arduino.h
#include <limits.h>
#include "TempControl.h"

// result can have maximum length of : sign + 3 digits integer part + point + 3 digits fraction part + '\0' = 9 bytes;
// only 1, 2 or 3 decimals allowed.
// returns pointer to the string
// fixed7_23 is used to prevent overflow
char * tempToString(char s[9], fixed23_9 rawValue, uint8_t numDecimals, uint8_t maxLength){
	if(rawValue == INT_MIN){
		strcpy_P(s, PSTR("null"));
		return s;
	}
	if(tempControl.cc.tempFormat == 'F'){
		rawValue = (rawValue * 9) / 5 + (32 << 9); // convert to Fahrenheit first
	}
	return fixedPointToString(s, rawValue, numDecimals, maxLength);
}

char * fixedPointToString(char s[9], fixed23_9 rawValue, uint8_t numDecimals, uint8_t maxLength){
	if(rawValue < 0l){
		s[0] = '-';
		rawValue = -rawValue;
	}
	else{
		s[0] = ' ';
	}

	int intPart = rawValue >> 9;
	uint16_t fracPart;
	if(numDecimals == 1){
		fracPart = ((rawValue & 0x01FF) * 10 + 256) >> 9; // add 256 for rounding
		if(fracPart >= 10){
			intPart++;
			fracPart = 0; // has already overflowed into integer part.
		}
		snprintf_P(&s[1], maxLength-1, PSTR("%d.%01d"), intPart, fracPart);
	}
	else if(numDecimals == 2){
		fracPart = ((rawValue  & 0x01FF) * 100 + 256) >> 9;
		if(fracPart >= 100){
			intPart++;
			fracPart = 0; // has already overflowed into integer part.
		}
		snprintf_P(&s[1], maxLength-1, PSTR("%d.%02d"), intPart, fracPart);
	}
	else{
		fracPart = ((rawValue  & 0x01FF) * 1000 + 256) >> 9;
		if(fracPart>=1000){
			intPart++;
			fracPart = 0; // has already overflowed into integer part.
		}
		snprintf_P(&s[1], maxLength-1, PSTR("%d.%03d"),  intPart, fracPart);
	}
	return s;
}

fixed7_9 stringToTemp(char * numberString){
	fixed23_9 rawTemp = stringToFixedPoint(numberString);

	if(tempControl.cc.tempFormat == 'F'){
		rawTemp = ((rawTemp - (32 << 9)) * 5) / 9; // convert to store as Celsius
	}

	return constrain(rawTemp, INT_MIN, INT_MAX);
}

fixed23_9 stringToFixedPoint(char * numberString){
	// receive new temperature as null terminated string: "19.20"
	fixed23_9 intPart = 0;
	fixed23_9 fracPart = 0;

	char * fractPtr = 0; //pointer to the point in the string
	bool negative = 0;
	if(numberString[0] == '-'){
		numberString++;
		negative = true; // by processing the sign here, we don't have to include strtol
	}

	// find the point in the string to split in the integer part and the fraction part
	fractPtr = strchrnul(numberString, '.'); // returns pointer to the point.

	intPart = strtoul(numberString, NULL, 10);
	if(fractPtr != 0){
		// decimal point was found
		char * fractEndPtr;
		fractPtr++; // add 1 to pointer to skip point
		fracPart = strtoul(fractPtr,&fractEndPtr, 10);
		uint8_t numDecimals = fractEndPtr - fractPtr;
		fracPart = fracPart << 9; // 9 bits for fraction part
		while(numDecimals > 0){
			fracPart = (fracPart + 5) / 10; // divide by 10 rounded
			numDecimals--;
		}
	}
	fixed23_9 absVal = ((intPart<<9) +fracPart);
	return negative ? -absVal:absVal;
}

char * tempDiffToString(char s[9], fixed23_9 rawValue, uint8_t numDecimals, uint8_t maxLength){
	if(tempControl.cc.tempFormat == 'F'){
		rawValue = (rawValue * 9) / 5; // convert to Fahrenheit first
	}
	return fixedPointToString(s, rawValue, numDecimals, maxLength);
}

fixed7_9 stringToTempDiff(char * numberString){
	fixed23_9 rawTempDiff = stringToFixedPoint(numberString);

	if(tempControl.cc.tempFormat == 'F'){
		rawTempDiff = (rawTempDiff * 5) / 9; // convert to store as Celsius
	}

	return constrain(rawTempDiff, INT_MIN, INT_MAX);
}

int fixedToTenths(fixed23_9 temperature){
	if(tempControl.cc.tempFormat == 'F'){
		temperature = temperature*9/5 + 32*512; // Convert to Fahrenheit fixed point first
	}

	return (int) ((10 * temperature + 256) / 512); // return rounded result in tenth of degrees
}

fixed7_9 tenthsToFixed(int temperature){
	if(tempControl.cc.tempFormat == 'F'){
		return (( ( (fixed23_9) temperature - 320) * 512 * 5) / 9 + 5) / 10; // convert to Celsius and return rounded result in fixed point
	}
	else{
		return ((fixed23_9) temperature * 512 + 5) / 10; // return rounded result in fixed point
	}
}<|endoftext|>


<commit_before>// Copyright 2021 The IREE Authors
//
// Licensed 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 "iree/compiler/Dialect/HAL/Target/ROCM/ROCMTarget.h"

#include <mutex>

#include "iree/compiler/Codegen/Dialect/IREECodegenDialect.h"
#include "iree/compiler/Codegen/Passes.h"
#include "iree/compiler/Dialect/HAL/Target/TargetRegistry.h"
#include "iree/compiler/Utils/FlatbufferUtils.h"
#include "iree/schemas/rocm_executable_def_builder.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Support/LogicalResult.h"
#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
#include "mlir/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.h"
#include "mlir/Target/LLVMIR/Export.h"

static llvm::cl::opt<std::string> clROCMTargetChip(
    "iree-rocm-target-chip", llvm::cl::desc("ROCm target Chip"),
    llvm::cl::init("gfx908"));

static llvm::cl::opt<bool> clROCMLinkBC(
    "iree-rocm-link-bc",
    llvm::cl::desc("Whether to try Linking to AMD Bitcodes"),
    llvm::cl::init(false));

static llvm::cl::opt<std::string> clROCMBitcodeDir(
    "iree-rocm-bc-dir", llvm::cl::desc("Directory of ROCM Bitcode"),
    llvm::cl::init("/opt/rocm/amdgcn/bitcode"));

namespace mlir {
namespace iree_compiler {
namespace IREE {
namespace HAL {

static std::string translateModuleToISA(llvm::Module &module,
                                        llvm::TargetMachine &targetMachine) {
  std::string targetISA;
  {
    llvm::raw_string_ostream stream(targetISA);
    llvm::buffer_ostream pstream(stream);
    llvm::legacy::PassManager codegenPasses;
    targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr,
                                      llvm::CGFT_ObjectFile);
    codegenPasses.run(module);
  }
  return targetISA;
}

class ROCMTargetBackend final : public TargetBackend {
 public:
  std::string name() const override { return "rocm"; }

  void getDependentDialects(DialectRegistry &registry) const override {
    mlir::registerLLVMDialectTranslation(registry);
    mlir::registerROCDLDialectTranslation(registry);
    registry.insert<IREE::Codegen::IREECodegenDialect>();
  }

  IREE::HAL::DeviceTargetAttr getDefaultDeviceTarget(
      MLIRContext *context) const override {
    Builder b(context);
    SmallVector<NamedAttribute> configItems;
    configItems.emplace_back(b.getStringAttr("executable_targets"),
                             getExecutableTargets(context));

    auto configAttr = b.getDictionaryAttr(configItems);
    return IREE::HAL::DeviceTargetAttr::get(
        context, b.getStringAttr(deviceID()), configAttr);
  }

  void buildTranslationPassPipeline(OpPassManager &passManager) override {
    buildLLVMGPUTransformPassPipeline(passManager, true);
  }

  LogicalResult serializeExecutable(const SerializationOptions &options,
                                    IREE::HAL::ExecutableVariantOp variantOp,
                                    OpBuilder &executableBuilder) override {
    // Perform the translation in a separate context to avoid any
    // multi-threading issues.
    llvm::LLVMContext context;

    // We name our files after the executable name so that they are easy to
    // track both during compilation (logs/artifacts/etc), as outputs (final
    // intermediate code/binary files), and at runtime (loaded
    // libraries/symbols/etc).
    auto libraryName =
        variantOp->getParentOfType<IREE::HAL::ExecutableOp>().getName().str();

    ModuleOp innerModuleOp = variantOp.getInnerModule();

    // Remove all the functions that are not part of the ROCM kernel.
    // TODO: Find a better solution to handle this.
    auto illegalFuncOps =
        llvm::to_vector<4>(innerModuleOp.getOps<func::FuncOp>());
    for (auto funcOp : illegalFuncOps) {
      funcOp.erase();
    }

    auto llvmModule =
        mlir::translateModuleToLLVMIR(innerModuleOp, context, libraryName);
    if (!llvmModule) {
      return variantOp.emitError() << "failed to translate the MLIR LLVM "
                                      "dialect to the native llvm::Module";
    }

    // Collect all the entry point names.
    llvm::StringMap<IREE::HAL::ExecutableEntryPointOp> entryPointOps;
    for (auto op : variantOp.getOps<IREE::HAL::ExecutableEntryPointOp>()) {
      entryPointOps[op.sym_name()] = op;
    }
    std::vector<std::array<int32_t, 3>> workgroupSizes;
    for (auto func : innerModuleOp.getOps<LLVM::LLVMFuncOp>()) {
      int32_t flatWgSize = 1;
      auto *llvmFunc = llvmModule->getFunction(func.getName());
      if (llvmFunc->isDeclaration()) continue;
      std::array<int32_t, 3> workgroup_size;
      auto entryPointOp = entryPointOps[func.getName()];
      if (Optional<ArrayAttr> workgroupSizeAttr =
              entryPointOp.workgroup_size()) {
        for (auto it : llvm::enumerate(workgroupSizeAttr.getValue())) {
          workgroup_size[it.index()] = it.value().cast<IntegerAttr>().getInt();
          flatWgSize *= it.value().cast<IntegerAttr>().getInt();
        }
      } else {
        workgroup_size = {1, 1, 1};
      }
      workgroupSizes.push_back(workgroup_size);
      // For GPU kernels,
      // 1. Insert AMDGPU_KERNEL calling convention.
      // 2. Insert amdgpu-flat-workgroup-size(1, 256) attribute.
      // 3. Insert amdgpu-implicitarg-num-bytes=56 (which must be set on OpenCL
      // and HIP kernels per Clang)
      llvmFunc->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
      std::string wgSizeRange = std::string("1, ") + std::to_string(flatWgSize);
      llvmFunc->addFnAttr("amdgpu-flat-work-group-size", wgSizeRange);
    }

    std::unique_ptr<llvm::TargetMachine> targetMachine;
    {
      llvm::Triple triple("amdgcn--amdhsa-amdgiz");
      std::string targetChip = clROCMTargetChip;
      std::string error;
      const llvm::Target *target =
          llvm::TargetRegistry::lookupTarget("", triple, error);
      if (target == nullptr) {
        return variantOp.emitError() << "cannot initialize target triple";
      }
      targetMachine.reset(
          target->createTargetMachine(triple.str(), targetChip, {}, {}, {}));
      if (targetMachine == nullptr) {
        return variantOp.emitError() << "cannot initialize target machine";
      }
    }

    llvmModule->setDataLayout(targetMachine->createDataLayout());

    iree_compiler::FlatbufferBuilder builder;
    iree_ROCMExecutableDef_start_as_root(builder);

    // Link module to Device Library
    if (clROCMLinkBC) {
      LinkROCDLIfNecessary(llvmModule.get(), clROCMTargetChip,
                           clROCMBitcodeDir);
    }

    // Serialize hsaco kernel into the binary that we will embed in the
    // final flatbuffer.
    std::string targetISA = translateModuleToISA(*llvmModule, *targetMachine);
    std::string targetHSACO = createHsaco(targetISA, libraryName);
    if (!options.dumpBinariesPath.empty()) {
      dumpDataToPath(options.dumpBinariesPath, options.dumpBaseName,
                     variantOp.getName(), ".hsaco", targetHSACO);
    }

    auto hsacoRef = flatbuffers_uint8_vec_create(
        builder, reinterpret_cast<const uint8_t *>(targetHSACO.c_str()),
        targetHSACO.size());

    auto entryPointNames = llvm::to_vector<8>(llvm::map_range(
        variantOp.getBlock()
            .getOps<iree_compiler::IREE::HAL::ExecutableEntryPointOp>(),
        [&](auto op) { return op.getName(); }));
    auto entryPointsRef = builder.createStringVec(entryPointNames);

    iree_ROCMBlockSizeDef_vec_start(builder);
    auto blockSizes = workgroupSizes.begin();
    for (int i = 0, e = entryPointNames.size(); i < e; ++i) {
      iree_ROCMBlockSizeDef_vec_push_create(builder, (*blockSizes)[0],
                                            (*blockSizes)[1], (*blockSizes)[2]);
      ++blockSizes;
    }
    auto blockSizesRef = iree_ROCMBlockSizeDef_vec_end(builder);

    iree_ROCMExecutableDef_entry_points_add(builder, entryPointsRef);
    iree_ROCMExecutableDef_block_sizes_add(builder, blockSizesRef);
    iree_ROCMExecutableDef_hsaco_image_add(builder, hsacoRef);
    iree_ROCMExecutableDef_end_as_root(builder);

    // Add the binary data to the target executable.
    executableBuilder.create<iree_compiler::IREE::HAL::ExecutableBinaryOp>(
        variantOp.getLoc(), variantOp.sym_name(),
        variantOp.target().getFormat(),
        builder.getBufferAttr(executableBuilder.getContext()));

    return success();
  }

 private:
  ArrayAttr getExecutableTargets(MLIRContext *context) const {
    SmallVector<Attribute> targetAttrs;
    // If we had multiple target environments we would generate one target attr
    // per environment, with each setting its own environment attribute.
    targetAttrs.push_back(getExecutableTarget(context));
    return ArrayAttr::get(context, targetAttrs);
  }

  IREE::HAL::ExecutableTargetAttr getExecutableTarget(
      MLIRContext *context) const {
    Builder b(context);
    SmallVector<NamedAttribute> configItems;

    auto configAttr = b.getDictionaryAttr(configItems);
    return IREE::HAL::ExecutableTargetAttr::get(
        context, b.getStringAttr("rocm"), b.getStringAttr("rocm-hsaco-fb"),
        configAttr);
  }
};

void registerROCMTargetBackends() {
  // #hal.device.target<"rocm", ...
  // #hal.executable.target<"rocm", ...
  static iree_compiler::IREE::HAL::TargetBackendRegistration registration(
      "rocm", [=]() {
        LLVMInitializeAMDGPUTarget();
        LLVMInitializeAMDGPUTargetMC();
        LLVMInitializeAMDGPUTargetInfo();
        LLVMInitializeAMDGPUAsmPrinter();
        return std::make_shared<ROCMTargetBackend>();
      });
}

}  // namespace HAL
}  // namespace IREE
}  // namespace iree_compiler
}  // namespace mlir
<commit_msg>[ROCM] Add iree-hal-rocm-dump-isa flag (#9141)<commit_after>// Copyright 2021 The IREE Authors
//
// Licensed 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 "iree/compiler/Dialect/HAL/Target/ROCM/ROCMTarget.h"

#include <mutex>

#include "iree/compiler/Codegen/Dialect/IREECodegenDialect.h"
#include "iree/compiler/Codegen/Passes.h"
#include "iree/compiler/Dialect/HAL/Target/TargetRegistry.h"
#include "iree/compiler/Utils/FlatbufferUtils.h"
#include "iree/schemas/rocm_executable_def_builder.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Support/LogicalResult.h"
#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
#include "mlir/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.h"
#include "mlir/Target/LLVMIR/Export.h"

static llvm::cl::opt<std::string> clROCMTargetChip(
    "iree-rocm-target-chip", llvm::cl::desc("ROCm target Chip"),
    llvm::cl::init("gfx908"));

static llvm::cl::opt<bool> clROCMLinkBC(
    "iree-rocm-link-bc",
    llvm::cl::desc("Whether to try Linking to AMD Bitcodes"),
    llvm::cl::init(false));

static llvm::cl::opt<std::string> clROCMBitcodeDir(
    "iree-rocm-bc-dir", llvm::cl::desc("Directory of ROCM Bitcode"),
    llvm::cl::init("/opt/rocm/amdgcn/bitcode"));

namespace mlir {
namespace iree_compiler {
namespace IREE {
namespace HAL {

static std::string translateModuleToObj(llvm::Module &module,
                                        llvm::TargetMachine &targetMachine) {
  std::string targetObj;
  {
    llvm::raw_string_ostream stream(targetObj);
    llvm::buffer_ostream pstream(stream);
    llvm::legacy::PassManager codegenPasses;
    targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr,
                                      llvm::CGFT_ObjectFile);
    codegenPasses.run(module);
  }
  return targetObj;
}

static std::string translateModuleToISA(llvm::Module &module,
                                        llvm::TargetMachine &targetMachine) {
  std::string targetISA;
  {
    llvm::raw_string_ostream stream(targetISA);
    llvm::buffer_ostream pstream(stream);
    llvm::legacy::PassManager codegenPasses;
    targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr,
                                      llvm::CGFT_AssemblyFile);
    codegenPasses.run(module);
  }
  return targetISA;
}
class ROCMTargetBackend final : public TargetBackend {
 public:
  std::string name() const override { return "rocm"; }

  void getDependentDialects(DialectRegistry &registry) const override {
    mlir::registerLLVMDialectTranslation(registry);
    mlir::registerROCDLDialectTranslation(registry);
    registry.insert<IREE::Codegen::IREECodegenDialect>();
  }

  IREE::HAL::DeviceTargetAttr getDefaultDeviceTarget(
      MLIRContext *context) const override {
    Builder b(context);
    SmallVector<NamedAttribute> configItems;
    configItems.emplace_back(b.getStringAttr("executable_targets"),
                             getExecutableTargets(context));

    auto configAttr = b.getDictionaryAttr(configItems);
    return IREE::HAL::DeviceTargetAttr::get(
        context, b.getStringAttr(deviceID()), configAttr);
  }

  void buildTranslationPassPipeline(OpPassManager &passManager) override {
    buildLLVMGPUTransformPassPipeline(passManager, true);
  }

  LogicalResult serializeExecutable(const SerializationOptions &options,
                                    IREE::HAL::ExecutableVariantOp variantOp,
                                    OpBuilder &executableBuilder) override {
    // Perform the translation in a separate context to avoid any
    // multi-threading issues.
    llvm::LLVMContext context;

    // We name our files after the executable name so that they are easy to
    // track both during compilation (logs/artifacts/etc), as outputs (final
    // intermediate code/binary files), and at runtime (loaded
    // libraries/symbols/etc).
    auto libraryName =
        variantOp->getParentOfType<IREE::HAL::ExecutableOp>().getName().str();

    ModuleOp innerModuleOp = variantOp.getInnerModule();

    // Remove all the functions that are not part of the ROCM kernel.
    // TODO: Find a better solution to handle this.
    auto illegalFuncOps =
        llvm::to_vector<4>(innerModuleOp.getOps<func::FuncOp>());
    for (auto funcOp : illegalFuncOps) {
      funcOp.erase();
    }

    auto llvmModule =
        mlir::translateModuleToLLVMIR(innerModuleOp, context, libraryName);
    if (!llvmModule) {
      return variantOp.emitError() << "failed to translate the MLIR LLVM "
                                      "dialect to the native llvm::Module";
    }

    // Collect all the entry point names.
    llvm::StringMap<IREE::HAL::ExecutableEntryPointOp> entryPointOps;
    for (auto op : variantOp.getOps<IREE::HAL::ExecutableEntryPointOp>()) {
      entryPointOps[op.sym_name()] = op;
    }
    std::vector<std::array<int32_t, 3>> workgroupSizes;
    for (auto func : innerModuleOp.getOps<LLVM::LLVMFuncOp>()) {
      int32_t flatWgSize = 1;
      auto *llvmFunc = llvmModule->getFunction(func.getName());
      if (llvmFunc->isDeclaration()) continue;
      std::array<int32_t, 3> workgroup_size;
      auto entryPointOp = entryPointOps[func.getName()];
      if (Optional<ArrayAttr> workgroupSizeAttr =
              entryPointOp.workgroup_size()) {
        for (auto it : llvm::enumerate(workgroupSizeAttr.getValue())) {
          workgroup_size[it.index()] = it.value().cast<IntegerAttr>().getInt();
          flatWgSize *= it.value().cast<IntegerAttr>().getInt();
        }
      } else {
        workgroup_size = {1, 1, 1};
      }
      workgroupSizes.push_back(workgroup_size);
      // For GPU kernels,
      // 1. Insert AMDGPU_KERNEL calling convention.
      // 2. Insert amdgpu-flat-workgroup-size(1, 256) attribute.
      // 3. Insert amdgpu-implicitarg-num-bytes=56 (which must be set on OpenCL
      // and HIP kernels per Clang)
      llvmFunc->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
      std::string wgSizeRange = std::string("1, ") + std::to_string(flatWgSize);
      llvmFunc->addFnAttr("amdgpu-flat-work-group-size", wgSizeRange);
    }

    std::unique_ptr<llvm::TargetMachine> targetMachine;
    {
      llvm::Triple triple("amdgcn--amdhsa-amdgiz");
      std::string targetChip = clROCMTargetChip;
      std::string error;
      const llvm::Target *target =
          llvm::TargetRegistry::lookupTarget("", triple, error);
      if (target == nullptr) {
        return variantOp.emitError() << "cannot initialize target triple";
      }
      targetMachine.reset(
          target->createTargetMachine(triple.str(), targetChip, {}, {}, {}));
      if (targetMachine == nullptr) {
        return variantOp.emitError() << "cannot initialize target machine";
      }
    }

    llvmModule->setDataLayout(targetMachine->createDataLayout());

    iree_compiler::FlatbufferBuilder builder;
    iree_ROCMExecutableDef_start_as_root(builder);

    // Link module to Device Library
    if (clROCMLinkBC) {
      LinkROCDLIfNecessary(llvmModule.get(), clROCMTargetChip,
                           clROCMBitcodeDir);
    }

    // Serialize hsaco kernel into the binary that we will embed in the
    // final flatbuffer.
    std::string targetObj = translateModuleToObj(*llvmModule, *targetMachine);
    std::string targetHSACO = createHsaco(targetObj, libraryName);
    if (!options.dumpBinariesPath.empty()) {
      dumpDataToPath(options.dumpBinariesPath, options.dumpBaseName,
                     variantOp.getName(), ".hsaco", targetHSACO);
    }

    auto hsacoRef = flatbuffers_uint8_vec_create(
        builder, reinterpret_cast<const uint8_t *>(targetHSACO.c_str()),
        targetHSACO.size());

    auto entryPointNames = llvm::to_vector<8>(llvm::map_range(
        variantOp.getBlock()
            .getOps<iree_compiler::IREE::HAL::ExecutableEntryPointOp>(),
        [&](auto op) { return op.getName(); }));
    auto entryPointsRef = builder.createStringVec(entryPointNames);

    iree_ROCMBlockSizeDef_vec_start(builder);
    auto blockSizes = workgroupSizes.begin();
    for (int i = 0, e = entryPointNames.size(); i < e; ++i) {
      iree_ROCMBlockSizeDef_vec_push_create(builder, (*blockSizes)[0],
                                            (*blockSizes)[1], (*blockSizes)[2]);
      ++blockSizes;
    }
    auto blockSizesRef = iree_ROCMBlockSizeDef_vec_end(builder);

    iree_ROCMExecutableDef_entry_points_add(builder, entryPointsRef);
    iree_ROCMExecutableDef_block_sizes_add(builder, blockSizesRef);
    iree_ROCMExecutableDef_hsaco_image_add(builder, hsacoRef);
    iree_ROCMExecutableDef_end_as_root(builder);

    // Add the binary data to the target executable.
    executableBuilder.create<iree_compiler::IREE::HAL::ExecutableBinaryOp>(
        variantOp.getLoc(), variantOp.sym_name(),
        variantOp.target().getFormat(),
        builder.getBufferAttr(executableBuilder.getContext()));

    if (!options.dumpIntermediatesPath.empty()) {
      std::string targetISA = translateModuleToISA(*llvmModule, *targetMachine);
      dumpDataToPath(options.dumpIntermediatesPath, options.dumpBaseName,
                     variantOp.getName(), ".rocmasm", targetISA);
    }

    return success();
  }

 private:
  ArrayAttr getExecutableTargets(MLIRContext *context) const {
    SmallVector<Attribute> targetAttrs;
    // If we had multiple target environments we would generate one target attr
    // per environment, with each setting its own environment attribute.
    targetAttrs.push_back(getExecutableTarget(context));
    return ArrayAttr::get(context, targetAttrs);
  }

  IREE::HAL::ExecutableTargetAttr getExecutableTarget(
      MLIRContext *context) const {
    Builder b(context);
    SmallVector<NamedAttribute> configItems;

    auto configAttr = b.getDictionaryAttr(configItems);
    return IREE::HAL::ExecutableTargetAttr::get(
        context, b.getStringAttr("rocm"), b.getStringAttr("rocm-hsaco-fb"),
        configAttr);
  }
};

void registerROCMTargetBackends() {
  // #hal.device.target<"rocm", ...
  // #hal.executable.target<"rocm", ...
  static iree_compiler::IREE::HAL::TargetBackendRegistration registration(
      "rocm", [=]() {
        LLVMInitializeAMDGPUTarget();
        LLVMInitializeAMDGPUTargetMC();
        LLVMInitializeAMDGPUTargetInfo();
        LLVMInitializeAMDGPUAsmPrinter();
        return std::make_shared<ROCMTargetBackend>();
      });
}

}  // namespace HAL
}  // namespace IREE
}  // namespace iree_compiler
}  // namespace mlir
<|endoftext|>