blob: 4cb5f2bfd3b11536d63da580941b28144eea8164 [file]
// Copyright 2023 Google LLC
//
// 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
//
// https://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.
#ifndef MPACT_SIM_GENERIC_IMMEDIATE_OPERAND_H_
#define MPACT_SIM_GENERIC_IMMEDIATE_OPERAND_H_
#include <any>
#include <cstdint>
#include <string>
#include <vector>
#include "mpact/sim/generic/operand_interface.h"
namespace mpact {
namespace sim {
namespace generic {
// Immediate source operand with value type T. While the value is a scalar,
// it can be used for a vector or matrix immediate as well, since the index in
// the accessor methods is ignored.
template <typename T>
class ImmediateOperand : public SourceOperandInterface {
public:
explicit ImmediateOperand(T val)
: value_(val), shape_({1}), as_string_(absl::StrCat(val)) {}
ImmediateOperand(T val, std::string as_string)
: value_(val), shape_({1}), as_string_(as_string) {}
ImmediateOperand(T val, const std::vector<int> &shape)
: value_(val), shape_(shape), as_string_(absl::StrCat(val)) {}
ImmediateOperand(T val, const std::vector<int> &shape, std::string as_string)
: value_(val), shape_(shape), as_string_(as_string) {}
// Methods for accessing the immediate value. Always returns the same
// value regardless of the index parameter.
bool AsBool(int) override { return static_cast<bool>(value_); }
int8_t AsInt8(int) override { return static_cast<int8_t>(value_); }
uint8_t AsUint8(int) override { return static_cast<uint8_t>(value_); }
int16_t AsInt16(int) override { return static_cast<int16_t>(value_); }
uint16_t AsUint16(int) override { return static_cast<uint16_t>(value_); }
int32_t AsInt32(int) override { return static_cast<int32_t>(value_); }
uint32_t AsUint32(int) override { return static_cast<uint32_t>(value_); }
int64_t AsInt64(int) override { return static_cast<int64_t>(value_); }
uint64_t AsUint64(int) override { return static_cast<uint64_t>(value_); }
// Returns empty absl::any, as the immediate operand does not have an
// underlying object that models any processor state.
std::any GetObject() const override { return std::any(); }
// Returns the shape of the operand (the number of elements in each
// dimension). For instance {1} indicates a scalar quantity, whereas {128}
// indicates an 128 element vector quantity. A 2D 64 by 32 array would have
// shape {64, 32}.
// ** Note: in principle a scalar shaped object should be encoded as an
// empty vector {}, i.e., point with zero dimensions. However, some code was
// simplified by not allowing an empty vector. Therefore, a 1 dimensional
// vector shape with dimension size 1 used for a scalar shape.
std::vector<int> shape() const override { return shape_; }
std::string AsString() const override { return as_string_; }
private:
T value_;
std::vector<int> shape_;
std::string as_string_;
};
// Vector Immediate source operand with value type T. This allows each vector
// element to have a different value. It is initialized with a std::vector<T>.
template <typename T>
class VectorImmediateOperand : public SourceOperandInterface {
public:
explicit VectorImmediateOperand(std::vector<T> val) : value_(val) {
shape_.push_back(value_.size());
}
VectorImmediateOperand(std::vector<T> val, const std::vector<int> &shape)
: value_(val), shape_(shape) {
ABSL_HARDENING_ASSERT((shape.size() == 1) && (shape[0] == val.size()));
}
// Methods for accessing the immediate value.
bool AsBool(int i) override { return static_cast<bool>(value_[i]); }
int8_t AsInt8(int i) override { return static_cast<int8_t>(value_[i]); }
uint8_t AsUint8(int i) override { return static_cast<uint8_t>(value_[i]); }
int16_t AsInt16(int i) override { return static_cast<int16_t>(value_[i]); }
uint16_t AsUint16(int i) override { return static_cast<uint16_t>(value_[i]); }
int32_t AsInt32(int i) override { return static_cast<int32_t>(value_[i]); }
uint32_t AsUint32(int i) override { return static_cast<uint32_t>(value_[i]); }
int64_t AsInt64(int i) override { return static_cast<int64_t>(value_[i]); }
uint64_t AsUint64(int i) override { return static_cast<uint64_t>(value_[i]); }
// Returns empty absl::any, as the immediate operand does not have an
// underlying object that models any processor state.
std::any GetObject() const override { return std::any(); }
// Return the shape of the operand (the number of elements in each dimension).
// For instance {1} indicates a scalar quantity, whereas {128} indicates an
// 128 element vector quantity.
std::vector<int> shape() const override { return shape_; }
std::string AsString() const override {
return absl::StrCat("[", value_[0], "...", value_.back(), "]");
}
private:
std::vector<T> value_;
std::vector<int> shape_;
};
} // namespace generic
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_GENERIC_IMMEDIATE_OPERAND_H_