blob: a29d17801d6f1fe0b0224ff09eb32c45fa115b9e [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 <deque>
#include <iostream>
#include <istream>
#include <memory>
#include <optional>
#include <string>
#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/strings/string_view.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/opcode.h"
#include "mpact/sim/decoder/slot.h"
#include "mpact/sim/decoder/template_expression.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 {
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::string &file_name, 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_) {}
};
// Type aliases for antlr4 context types.
using TopLevelCtx = InstructionSetParser::Top_levelContext;
using NamespaceDeclCtx = InstructionSetParser::Namespace_declContext;
using ConstantDefCtx = InstructionSetParser::Constant_defContext;
using IncludeFileCtx = InstructionSetParser::Include_fileContext;
using DeclarationCtx = InstructionSetParser::DeclarationContext;
using IsaDeclCtx = InstructionSetParser::Isa_declarationContext;
using BundleDeclCtx = InstructionSetParser::Bundle_declarationContext;
using SlotDeclCtx = InstructionSetParser::Slot_declarationContext;
using BaseItemListCtx = InstructionSetParser::Base_item_listContext;
using ExpressionCtx = InstructionSetParser::ExpressionContext;
using ArraySpecCtx = InstructionSetParser::Array_specContext;
using OpcodeSpecCtx = InstructionSetParser::Opcode_specContext;
using BundleListCtx = InstructionSetParser::Bundle_listContext;
using SlotListCtx = InstructionSetParser::Slot_listContext;
using OpcodeListCtx = InstructionSetParser::Opcode_listContext;
using OpcodeOperandsCtx = InstructionSetParser::Opcode_operandsContext;
using IdentListCtx = InstructionSetParser::Ident_listContext;
using DisasmWidthsCtx = InstructionSetParser::Disasm_widthsContext;
using ConstAndDefaultCtx =
InstructionSetParser::Const_and_default_declContext;
using OpcodeAttributeListCtx =
InstructionSetParser::Opcode_attribute_listContext;
using InstructionAttributeListCtx =
InstructionSetParser::Instruction_attribute_listContext;
using SemfuncSpecCtx = InstructionSetParser::Semfunc_specContext;
using ResourceItemCtx = InstructionSetParser::Resource_itemContext;
using ResourceDetailsCtx = InstructionSetParser::Resource_detailsContext;
// Checks that any references to slots or bundles within a bundle
// declaration are to valid slots/bundles.
absl::Status 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.
std::unique_ptr<InstructionSet> VisitTopLevel(TopLevelCtx *ctx,
const std::string &isa_name);
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);
DestinationOperand *FindDestinationOpInExpression(
ExpressionCtx *ctx, const Slot *slot, const Instruction *inst) const;
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);
// 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::string GenerateHdrFileEpilog(absl::string_view guard_name,
const std::vector<std::string> &namespaces);
std::string GenerateCcFileProlog(absl::string_view hdr_file_name,
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_;
// 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_