blob: 82c328066d035969903bd5230d110a03dc4c5efe [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_INSTRUCTION_SET_VISITOR_H_
#define MPACT_SIM_DECODER_INSTRUCTION_SET_VISITOR_H_
#include <cstddef>
#include <deque>
#include <list>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "antlr4-runtime/ParserRuleContext.h"
#include "mpact/sim/decoder/InstructionSetLexer.h"
#include "mpact/sim/decoder/InstructionSetParser.h"
#include "mpact/sim/decoder/antlr_parser_wrapper.h"
#include "mpact/sim/decoder/bundle.h"
#include "mpact/sim/decoder/decoder_error_listener.h"
#include "mpact/sim/decoder/instruction.h"
#include "mpact/sim/decoder/instruction_set.h"
#include "mpact/sim/decoder/instruction_set_contexts.h"
#include "mpact/sim/decoder/opcode.h"
#include "mpact/sim/decoder/slot.h"
#include "mpact/sim/decoder/template_expression.h"
#include "util/regexp/re2/re2.h"
// This file declares the classes that interact with the antlr4 library
// to parse an input stream and generate the parse tree, then visiting the
// parse tree to build up the internal representation from which further
// processing and eventual c++ code generation is done.
namespace mpact {
namespace sim {
namespace machine_description {
namespace instruction_set {
// This struct holds information about a range assignment in an instruction
// generator.
struct RangeAssignmentInfo {
std::vector<std::string> range_names;
std::list<RE2> range_regexes;
std::vector<std::vector<std::string>> range_values;
};
using InstructionSetParser = ::sim::machine_description::instruction_set::
generated::InstructionSetParser;
using ::sim::machine_description::instruction_set::generated::
InstructionSetLexer;
using IsaAntlrParserWrapper =
decoder::AntlrParserWrapper<InstructionSetParser, InstructionSetLexer>;
// Visitor class for the Antlr4 parse tree. It does not derive from Antlr4
// base classes so that the return types and method parameters could be
// customized.
class InstructionSetVisitor {
public:
InstructionSetVisitor();
~InstructionSetVisitor();
// Entry point for processing a source_stream input, generating any output
// files in the given directory. Returns OK if no errors were encountered.
absl::Status Process(const std::vector<std::string>& file_names,
const std::string& prefix, const std::string& isa_name,
const std::vector<std::string>& include_roots,
absl::string_view directory);
// Global const expressions.
absl::Status AddConstant(absl::string_view name, absl::string_view type,
TemplateExpression* expr);
TemplateExpression* GetConstExpression(absl::string_view name) const;
// The current isa name.
const std::string& isa_name() const { return isa_name_; }
private:
struct TemplateFunctionEvaluator {
TemplateFunction::Evaluator function;
size_t arity;
TemplateFunctionEvaluator(TemplateFunction::Evaluator function_,
size_t arity_)
: function(std::move(function_)), arity(arity_) {}
};
// Checks that any references to slots or bundles within a bundle
// declaration are to valid slots/bundles.
void PerformBundleReferenceChecks(InstructionSet* instruction_set,
Bundle* bundle);
// The following methods visits the parts of the parse tree indicated by
// the method name and builds up the internal representation used for
// decoder generation.
void VisitTopLevel(TopLevelCtx* ctx);
std::unique_ptr<InstructionSet> VisitIsaDeclaration(IsaDeclCtx* ctx);
void VisitConstantDef(ConstantDefCtx* ctx);
void VisitBundleList(BundleListCtx* ctx, Bundle* bundle);
void VisitOpcodeList(OpcodeListCtx* ctx, Slot* slot);
void VisitOpcodeOperands(OpcodeOperandsCtx* ctx, int op_spec_number,
Instruction* parent, Instruction* child, Slot* slot);
void VisitSlotList(SlotListCtx* ctx, Bundle*);
void VisitIncludeFile(IncludeFileCtx* ctx);
void VisitSlotDeclaration(SlotDeclCtx* ctx, InstructionSet* instruction_set);
void VisitConstAndDefaultDecls(ConstAndDefaultCtx* ctx, Slot* slot);
TemplateExpression* VisitExpression(ExpressionCtx* ctx, Slot* slot,
Instruction* inst);
std::vector<int> VisitArraySpec(ArraySpecCtx* ctx);
void VisitNamespaceDecl(NamespaceDeclCtx* ctx, InstructionSet* isa);
void VisitBundleDeclaration(BundleDeclCtx* ctx,
InstructionSet* instruction_set);
void VisitDisasmWidthsDecl(DisasmWidthsCtx* ctx);
void VisitInstructionAttributeList(InstructionAttributeListCtx* ctx,
Slot* slot, Instruction* inst);
void VisitOpcodeAttributes(OpcodeAttributeListCtx* ctx, Instruction* inst,
Slot* slot);
void VisitSemfuncSpec(SemfuncSpecCtx* semfunc_spec, Instruction* inst);
void VisitResourceDetails(ResourceDetailsCtx* ctx, Instruction* inst,
Slot* slot);
std::optional<ResourceReference*> ProcessResourceReference(
Slot* slot, Instruction* inst, ResourceItemCtx* resource_item);
void VisitResourceDetailsLists(ResourceDetailsCtx* ctx, Slot* slot,
Instruction* inst, ResourceSpec* spec);
std::unique_ptr<InstructionSet> ProcessTopLevel(absl::string_view isa_name);
void ParseIncludeFile(antlr4::ParserRuleContext* ctx,
const std::string& file_name,
const std::vector<std::string>& dirs);
DestinationOperand* FindDestinationOpInExpression(ExpressionCtx* ctx,
const Slot* slot,
const Instruction* inst);
void PerformOpcodeOverrides(
absl::flat_hash_set<OpcodeSpecCtx*> overridden_ops_set, Slot* slot);
void PreProcessDeclarations(const std::vector<DeclarationCtx*>& ctx_vec);
void ProcessOpcodeList(
OpcodeListCtx* ctx, Slot* slot,
std::vector<Instruction*>& instruction_vec,
absl::flat_hash_set<std::string>& deleted_ops_set,
absl::flat_hash_set<OpcodeSpecCtx*>& overridden_ops_set);
void ProcessOpcodeSpec(
OpcodeSpecCtx* opcode_ctx, Slot* slot,
std::vector<Instruction*>& instruction_vec,
absl::flat_hash_set<std::string>& deleted_ops_set,
absl::flat_hash_set<OpcodeSpecCtx*>& overridden_ops_set);
// Process the GENERATE() directive.
absl::Status ProcessOpcodeGenerator(
OpcodeSpecCtx* ctx, Slot* slot,
std::vector<Instruction*>& instruction_vec,
absl::flat_hash_set<std::string>& deleted_ops_set,
absl::flat_hash_set<OpcodeSpecCtx*>& overridden_ops_set);
// Helper function fused by ProcessOpcodeGenerator.
std::string GenerateOpcodeSpec(
const std::vector<RangeAssignmentInfo*>& range_info_vec, int index,
const std::string& template_str_in) const;
// These methods parses the disassembly format string.
absl::Status ParseDisasmFormat(std::string format, Instruction* inst);
absl::StatusOr<std::string> ParseNumberFormat(std::string format);
absl::StatusOr<FormatInfo*> ParseFormatExpression(std::string expr,
Opcode* op);
// Generate file prologues/epilogues.
std::string GenerateHdrFileProlog(absl::string_view file_name,
absl::string_view opcode_file_name,
absl::string_view guard_name,
absl::string_view encoding_base_name,
const std::vector<std::string>& namespaces);
std::tuple<std::string, std::string> GenerateEncFilePrologs(
absl::string_view file_name, absl::string_view guard_name,
absl::string_view opcode_file_name, absl::string_view encoding_type_name,
const std::vector<std::string>& namespaces);
std::string GenerateHdrFileEpilog(absl::string_view guard_name,
const std::vector<std::string>& namespaces);
std::string GenerateCcFileProlog(absl::string_view hdr_file_name,
bool use_includes,
const std::vector<std::string>& namespaces);
std::string GenerateNamespaceEpilog(
const std::vector<std::string>& namespaces);
std::string GenerateSimpleHdrProlog(
absl::string_view guard_name, const std::vector<std::string>& namespaces);
// Error handler.
decoder::DecoderErrorListener* error_listener() const {
return error_listener_.get();
}
void set_error_listener(
std::unique_ptr<decoder::DecoderErrorListener> listener) {
error_listener_ = std::move(listener);
}
std::string isa_name_;
// Slot and bundle maps - these point to the contexts for every slot and
// bundle that have been declared.
absl::flat_hash_map<std::string, SlotDeclCtx*> slot_decl_map_;
absl::flat_hash_map<std::string, BundleDeclCtx*> bundle_decl_map_;
absl::flat_hash_map<std::string, IsaDeclCtx*> isa_decl_map_;
// Constant map
absl::flat_hash_map<std::string, TemplateExpression*> constant_map_;
// Include file strings.
absl::btree_set<std::string> include_files_;
int current_file_index_ = 0;
unsigned generator_version_;
// Vector of file names.
std::vector<std::string> file_names_;
// Map from context pointer to file index.
absl::flat_hash_map<antlr4::ParserRuleContext*, int> context_file_map_;
// Include file roots.
std::vector<std::string> include_dir_vec_;
// Keep track of files that are included in case there is recursive includes.
std::deque<std::string> include_file_stack_;
// Error listening object passed to the parser.
std::unique_ptr<decoder::DecoderErrorListener> error_listener_;
// For template functions evaluators.
absl::flat_hash_map<std::string, TemplateFunctionEvaluator>
template_function_evaluators_;
// Disassembler field widths.
std::vector<TemplateExpression*> disasm_field_widths_;
// AntlrParserWrapper vector.
std::vector<IsaAntlrParserWrapper*> antlr_parser_wrappers_;
};
} // namespace instruction_set
} // namespace machine_description
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_DECODER_INSTRUCTION_SET_VISITOR_H_