blob: 47ba8352448306d370d576a631a1ec1275dee670 [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_INSTRUCTION_HELPERS_H_
#define MPACT_SIM_GENERIC_INSTRUCTION_HELPERS_H_
#include <functional>
#include "mpact/sim/generic/instruction.h"
// This file contains a set of inline templated functions that can be used to
// avoid a lot of the boiler plate code in writing simple semantic functions.
// Using optimization level of O3 should allow these functions to be perfectly
// inlined in the semantic functions that reference them.
namespace mpact {
namespace sim {
namespace generic {
// This is a templated helper function used to factor out common code in
// two operand instruction semantic functions. It reads two source operands
// and applies the function argument to them, storing the result to the
// destination operand. This version supports different types for the result and
// each of the two source operands.
template <typename Result, typename Argument1, typename Argument2>
inline void BinaryOp(Instruction *instruction,
std::function<Result(Argument1, Argument2)> operation) {
Argument1 lhs = generic::GetInstructionSource<Argument1>(instruction, 0);
Argument2 rhs = generic::GetInstructionSource<Argument2>(instruction, 1);
Result dest_value = operation(lhs, rhs);
auto *db = instruction->Destination(0)->AllocateDataBuffer();
db->SetSubmit<Result>(0, dest_value);
}
// This is a templated helper function used to factor out common code in
// two operand instruction semantic functions. It reads two source operands
// and applies the function argument to them, storing the result to the
// destination operand. This version supports different types for the result
// and the operands, but the two source operands must have the same type.
template <typename Result, typename Argument>
inline void BinaryOp(Instruction *instruction,
std::function<Result(Argument, Argument)> operation) {
Argument lhs = generic::GetInstructionSource<Argument>(instruction, 0);
Argument rhs = generic::GetInstructionSource<Argument>(instruction, 1);
Result dest_value = operation(lhs, rhs);
auto *db = instruction->Destination(0)->AllocateDataBuffer();
db->SetSubmit<Result>(0, dest_value);
}
// This is a templated helper function used to factor out common code in
// two operand instruction semantic functions. It reads two source operands
// and applies the function argument to them, storing the result to the
// destination operand. This version requires both result and source operands
// to have the same type.
template <typename Result>
inline void BinaryOp(Instruction *instruction,
std::function<Result(Result, Result)> operation) {
Result lhs = generic::GetInstructionSource<Result>(instruction, 0);
Result rhs = generic::GetInstructionSource<Result>(instruction, 1);
Result dest_value = operation(lhs, rhs);
auto *db = instruction->Destination(0)->AllocateDataBuffer();
db->SetSubmit<Result>(0, dest_value);
}
// This is a templated helper function used to factor out common code in
// single operand instruction semantic functions. It reads one source operand
// and applies the function argument to it, storing the result to the
// destination operand. This version supports the result and argument having
// different types.
template <typename Result, typename Argument>
inline void UnaryOp(Instruction *instruction,
std::function<Result(Argument)> operation) {
Argument lhs = generic::GetInstructionSource<Argument>(instruction, 0);
Result dest_value = operation(lhs);
auto *db = instruction->Destination(0)->AllocateDataBuffer();
db->SetSubmit<Result>(0, dest_value);
}
// This is a templated helper function used to factor out common code in
// single operand instruction semantic functions. It reads one source operand
// and applies the function argument to it, storing the result to the
// destination operand. This version requires that the result and argument have
// the same type.
template <typename Result>
inline void UnaryOp(Instruction *instruction,
std::function<Result(Result)> operation) {
Result lhs = generic::GetInstructionSource<Result>(instruction, 0);
Result dest_value = operation(lhs);
auto *db = instruction->Destination(0)->AllocateDataBuffer();
db->SetSubmit<Result>(0, dest_value);
}
// This is a templated helper function used to factor out common code in
// three operand vector instruction semantic functions. This version
// allows for different types for the result and each argument.
template <typename Result, typename Argument1, typename Argument2,
typename Argument3>
inline void TernaryVectorOp(
Instruction *instruction,
std::function<Result(Argument1, Argument2, Argument3)> operation) {
auto *dst = instruction->Destination(0);
auto *db = dst->AllocateDataBuffer();
int size = dst->shape()[0];
for (int i = 0; i < size; i++) {
Argument1 x_val =
generic::GetInstructionSource<Argument1>(instruction, 0, i);
Argument2 y_val =
generic::GetInstructionSource<Argument2>(instruction, 1, i);
Argument3 z_val =
generic::GetInstructionSource<Argument3>(instruction, 2, i);
Result value = operation(x_val, y_val, z_val);
db->Set<Result>(i, value);
}
db->Submit();
}
// This is a templated helper function used to factor out common code in
// three operand vector instruction semantic functions. This version
// allows for different types for the result and the three arguments, though
// the arguments have to all have the same type.
template <typename Result, typename Argument>
inline void TernaryVectorOp(
Instruction *instruction,
std::function<Result(Argument, Argument, Argument)> operation) {
auto *dst = instruction->Destination(0);
auto *db = dst->AllocateDataBuffer();
int size = dst->shape()[0];
for (int i = 0; i < size; i++) {
Argument x_val = generic::GetInstructionSource<Argument>(instruction, 0, i);
Argument y_val = generic::GetInstructionSource<Argument>(instruction, 1, i);
Argument z_val = generic::GetInstructionSource<Argument>(instruction, 2, i);
Result value = operation(x_val, y_val, z_val);
db->Set<Result>(i, value);
}
db->Submit();
}
// This is a templated helper function used to factor out common code in
// three operand vector instruction semantic functions. This version
// requires the result and arguments to have the same type.
template <typename Result>
inline void TernaryVectorOp(
Instruction *instruction,
std::function<Result(Result, Result, Result)> operation) {
auto *dst = instruction->Destination(0);
auto *db = dst->AllocateDataBuffer();
int size = dst->shape()[0];
for (int i = 0; i < size; i++) {
Result x_val = generic::GetInstructionSource<Result>(instruction, 0, i);
Result y_val = generic::GetInstructionSource<Result>(instruction, 1, i);
Result z_val = generic::GetInstructionSource<Result>(instruction, 2, i);
Result value = operation(x_val, y_val, z_val);
db->Set<Result>(i, value);
}
db->Submit();
}
// This is a templated helper function used to factor out common code in
// two operand vector instruction semantic functions. This version
// allows for different types for the result and each argument.
template <typename Result, typename Argument1, typename Argument2>
inline void BinaryVectorOp(
Instruction *instruction,
std::function<Result(Argument1, Argument2)> operation) {
auto *dst = instruction->Destination(0);
auto *db = dst->AllocateDataBuffer();
int size = dst->shape()[0];
for (int i = 0; i < size; i++) {
Argument1 lhs = generic::GetInstructionSource<Argument1>(instruction, 0, i);
Argument2 rhs = generic::GetInstructionSource<Argument2>(instruction, 1, i);
Result value = operation(lhs, rhs);
db->Set<Result>(i, value);
}
db->Submit();
}
// This is a templated helper function used to factor out common code in
// two operand vector instruction semantic functions. This version
// allows for different types for the result and the three arguments, though
// the arguments have to have the same type.
template <typename Result, typename Argument>
inline void BinaryVectorOp(
Instruction *instruction,
std::function<Result(Argument, Argument)> operation) {
auto *dst = instruction->Destination(0);
auto *db = dst->AllocateDataBuffer();
int size = dst->shape()[0];
for (int i = 0; i < size; i++) {
Argument lhs = generic::GetInstructionSource<Argument>(instruction, 0, i);
Argument rhs = generic::GetInstructionSource<Argument>(instruction, 1, i);
Result value = operation(lhs, rhs);
db->Set<Result>(i, value);
}
db->Submit();
}
// This is a templated helper function used to factor out common code in
// two operand vector instruction semantic functions. This version
// requires the result and arguments to have the same type.
template <typename Result>
inline void BinaryVectorOp(Instruction *instruction,
std::function<Result(Result, Result)> operation) {
auto *dst = instruction->Destination(0);
auto *db = dst->AllocateDataBuffer();
int size = dst->shape()[0];
for (int i = 0; i < size; i++) {
Result lhs = generic::GetInstructionSource<Result>(instruction, 0, i);
Result rhs = generic::GetInstructionSource<Result>(instruction, 1, i);
Result value = operation(lhs, rhs);
db->Set<Result>(i, value);
}
db->Submit();
}
// This is a templated helper function used to factor out common code in
// single operand vector instruction semantic functions. This version
// allows the result and argument to have different types.
template <typename Result, typename Argument>
inline void UnaryVectorOp(Instruction *instruction,
std::function<Result(Argument)> operation) {
auto *dst = instruction->Destination(0);
auto *db = dst->AllocateDataBuffer();
int size = dst->shape()[0];
for (int i = 0; i < size; i++) {
Argument lhs = generic::GetInstructionSource<Argument>(instruction, 0, i);
Result value = operation(lhs);
db->Set<Result>(i, value);
}
db->Submit();
}
// This is a templated helper function used to factor out common code in
// single operand vector instruction semantic functions. This version
// requires the result and argument to have the same type.
template <typename Result>
inline void UnaryVectorOp(Instruction *instruction,
std::function<Result(Result)> operation) {
auto *dst = instruction->Destination(0);
auto *db = dst->AllocateDataBuffer();
int size = dst->shape()[0];
for (int i = 0; i < size; i++) {
Result lhs = generic::GetInstructionSource<Result>(instruction, 0, i);
Result value = operation(lhs);
db->Set<Result>(i, value);
}
db->Submit();
}
} // namespace generic
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_GENERIC_INSTRUCTION_HELPERS_H_