blob: 9f470baddf54b04882261f10db7dd3a26e593840 [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_DECODER_ENCODING_GROUP_H_
#define MPACT_SIM_DECODER_ENCODING_GROUP_H_
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
#include "absl/container/flat_hash_set.h"
#include "absl/strings/string_view.h"
#include "mpact/sim/decoder/extract.h"
#include "mpact/sim/decoder/format.h"
namespace mpact {
namespace sim {
namespace decoder {
namespace bin_format {
class InstructionGroup;
class InstructionEncoding;
struct Constraint;
struct Field;
class Overlay;
// The encoding group is a class that allows instruction encodings to be grouped
// together to facilitate breaking the instruction encodings into a tree like
// hierarchy of instructions that have overlapping bits in the encoding that
// can be used to differentiate the encodings.
class EncodingGroup {
public:
EncodingGroup(InstructionGroup* inst_group, uint64_t ignore);
EncodingGroup(EncodingGroup* parent, InstructionGroup* inst_group,
uint64_t ignore);
~EncodingGroup();
// Remove bits from a mask that are already handled by parent encoding group.
void AdjustMask();
void AddEncoding(InstructionEncoding* enc);
// True if the encoding can be added to the group (i.e., there are
// sufficiently many "overlapping" bits.
bool CanAddEncoding(InstructionEncoding* enc);
// True if the encodings can be decoded using a simple lookup table without
// any further comparisons.
bool IsSimpleDecode();
// Break the current group into subgroups recursively.
void AddSubGroups();
// Verify that there are no collisions of opcodes in the simple decoders.
void CheckEncodings() const;
// Emit code for the initializers (decode tables) and the decoder functions.
void EmitInitializers(absl::string_view name, std::string* initializers_ptr,
const std::string& opcode_enum) const;
void EmitDecoders(absl::string_view name, std::string* declarations_ptr,
std::string* definitions_ptr,
const std::string& opcode_enum) const;
// Return a string containing information about the current group. This will
// be removed at a later stage.
// TODO(torerik): remove when no longer needed.
std::string DumpGroup(std::string prefix, std::string indent);
// Accessors.
// Return the parent encoding group if it exists.
EncodingGroup* parent() const { return parent_; }
// The mask is the intersection of the bits that are significant to the
// instruction encodings in this group. The bits that are used to select this
// group from the parent are removed from the mask.
uint64_t mask() const { return mask_; }
// The value of the group is the value of the bits in the instruction
// encodings that are the same across the encodings in the group.
uint64_t value() const { return value_; }
// The varying bits is the subset of the bits in the mask that varies in value
// across the encodings in this group.
uint64_t varying() const { return varying_; }
// The constant bits is the subset of the bits in the mask that are constant
// across the encodings in this group.
uint64_t constant() const { return constant_; }
// The discriminator is non-zero if this encoding group has subgroups. The
// discriminator is the set of bits used to compute the value from the
// instruction encoding to determine which sub-group a particular instruction
// encoding in this group belongs to,
uint64_t discriminator() const { return discriminator_; }
// Simple decoding is true if an opcode can be determined solely based on the
// discriminator, and no further constraints exist (such as a field having to
// be non-zero).
bool simple_decoding() const { return simple_decoding_; }
// The vector of encodings in this group.
const std::vector<InstructionEncoding*>& encoding_vec() const {
return encoding_vec_;
}
// The vector of subgroups in this group.
std::vector<EncodingGroup*>& encoding_group_vec() {
return encoding_group_vec_;
}
private:
// Methods that factors out some of the complexities of the public code
// emitting methods.
void EmitComplexDecoderBody(std::string* definitions_ptr,
absl::string_view index_extraction,
absl::string_view opcode_enum) const;
void EmitComplexDecoderBodyIfSequence(std::string* definitions_ptr,
absl::string_view opcode_enum) const;
int EmitEncodingIfStatement(int indent, const InstructionEncoding* encoding,
absl::string_view opcode_enum,
absl::flat_hash_set<std::string>& extracted,
std::string* definitions_ptr) const;
void ProcessConstraint(const absl::flat_hash_set<std::string>& extracted,
Constraint* constraint,
std::string* definitions_ptr) const;
void EmitFieldExtraction(const Field* field, const std::string& indent_str,
absl::flat_hash_set<std::string>& extracted,
std::string* definitions_ptr) const;
void EmitOverlayExtraction(const Overlay* overlay,
const std::string& indent_str,
absl::flat_hash_set<std::string>& extracted,
std::string* definitions_ptr) const;
void EmitExtractions(int indent, const std::vector<Constraint*>& constraints,
absl::flat_hash_set<std::string>& extracted,
std::string* definitions_ptr) const;
int EmitConstraintConditions(const std::vector<Constraint*>& constraints,
absl::string_view comparison,
std::string& connector,
std::string* condition) const;
int EmitOtherConstraintConditions(const std::vector<Constraint*>& constraints,
std::string& connector,
std::string* condition) const;
InstructionGroup* inst_group_ = nullptr;
EncodingGroup* parent_ = nullptr;
uint64_t varying_ = 0;
uint64_t discriminator_ = 0;
size_t discriminator_size_ = 0;
ExtractionRecipe discriminator_recipe_;
uint64_t constant_;
uint64_t mask_ = 0;
uint64_t value_ = 0;
uint64_t last_value_ = 0;
uint64_t ignore_ = 0;
bool simple_decoding_ = false;
std::string inst_word_type_;
std::vector<InstructionEncoding*> encoding_vec_;
std::vector<EncodingGroup*> encoding_group_vec_;
};
} // namespace bin_format
} // namespace decoder
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_DECODER_ENCODING_GROUP_H_