No public description PiperOrigin-RevId: 975822396 Change-Id: Ic29e7d48e56192a98d10c5b807fe73b1be53b7d7
diff --git a/mpact/sim/decoder/InstructionSet.g4 b/mpact/sim/decoder/InstructionSet.g4 index cefbc9a..48e4192 100644 --- a/mpact/sim/decoder/InstructionSet.g4 +++ b/mpact/sim/decoder/InstructionSet.g4
@@ -401,7 +401,11 @@ // An opcode attribute is either a disassembly specifier or a semfunc specifier. opcode_attribute - : disasm_spec | semfunc_spec | resource_spec | instruction_attribute_spec + : disasm_spec + | semfunc_spec + | resource_spec + | instruction_attribute_spec + | latency_spec ; // The disassembly specifier lists a sequence of format strings. Each formatted @@ -413,6 +417,20 @@ : DISASM ':' STRING_LITERAL ( ',' STRING_LITERAL )* ; +// The latency specifier lists the destination operands and their latencies. +latency_spec + : LATENCY ':' dest_operand_latency_list + ; + +dest_operand_latency_list + : dest_operand_with_latency (',' dest_operand_with_latency)* + ; + +dest_operand_with_latency + : (op_name=IDENT | '[' array_dest=IDENT ']') + ('(' (expression | wildcard='*' ) ')')? + ; + // The semantic function specifier lists a sequence of strings that in C++ can // be assigned to a C++ callables with signature void(Instruction *). These // will be used when dispatching the instruction. There will be one string
diff --git a/mpact/sim/decoder/instruction.cc b/mpact/sim/decoder/instruction.cc index 2d9ed19..4991775 100644 --- a/mpact/sim/decoder/instruction.cc +++ b/mpact/sim/decoder/instruction.cc
@@ -137,7 +137,9 @@ // Instruction attributes. for (auto const& [attr_name, expr_ptr] : attribute_map_) { - auto result = expr_ptr->Evaluate(args); + auto result = (expr_ptr != nullptr) + ? expr_ptr->Evaluate(args) + : absl::InternalError("Null expression"); if (result.ok()) { new_slot->AddAttributeName(attr_name); new_inst->AddInstructionAttribute(attr_name, result.value());
diff --git a/mpact/sim/decoder/instruction_set_contexts.h b/mpact/sim/decoder/instruction_set_contexts.h index ca8d67d..9df06b6 100644 --- a/mpact/sim/decoder/instruction_set_contexts.h +++ b/mpact/sim/decoder/instruction_set_contexts.h
@@ -49,6 +49,7 @@ InstructionSetParser::Opcode_attribute_listContext; using InstructionAttributeListCtx = InstructionSetParser::Instruction_attribute_listContext; +using LatencySpecCtx = InstructionSetParser::Latency_specContext; using SemfuncSpecCtx = InstructionSetParser::Semfunc_specContext; using ResourceItemCtx = InstructionSetParser::Resource_itemContext; using ResourceDetailsCtx = InstructionSetParser::Resource_detailsContext;
diff --git a/mpact/sim/decoder/instruction_set_visitor.cc b/mpact/sim/decoder/instruction_set_visitor.cc index d6a0b21..8cd97f2 100644 --- a/mpact/sim/decoder/instruction_set_visitor.cc +++ b/mpact/sim/decoder/instruction_set_visitor.cc
@@ -1214,12 +1214,11 @@ bool has_semfunc = false; bool has_resources = false; bool has_attributes = false; + bool has_latency = false; // Visit the opcode attributes. for (auto* attribute_ctx : ctx->opcode_attribute()) { // Process any disassembly specifications. if (attribute_ctx->disasm_spec() != nullptr) { - // In case of override, need to clear any disasm info in instruction. - inst->ClearDisasmFormat(); // Signal error if there is more than one disassembly spec. if (has_disasm) { error_listener()->semanticError( @@ -1228,6 +1227,8 @@ continue; } has_disasm = true; + // In case of override, need to clear any disasm info in instruction. + inst->ClearDisasmFormat(); for (auto* disasm_fmt : attribute_ctx->disasm_spec()->STRING_LITERAL()) { std::string format = disasm_fmt->getText(); // Trim the double quotes. @@ -1247,8 +1248,6 @@ // Process the semantic function specification. if (attribute_ctx->semfunc_spec() != nullptr) { - // In case of override, need to clear the semantic function string. - inst->ClearSemfuncCodeString(); // Signal error if there is more than one semantic function spec. if (has_semfunc) { error_listener()->semanticError( @@ -1257,14 +1256,14 @@ continue; } has_semfunc = true; + // In case of override, need to clear the semantic function string. + inst->ClearSemfuncCodeString(); VisitSemfuncSpec(attribute_ctx->semfunc_spec(), inst); continue; } // Process resource specification. if (attribute_ctx->resource_spec() != nullptr) { - // In case of override, need to clear the resource specifications. - inst->ClearResourceSpecs(); // Signal error if there is more than one resource specification. if (has_resources) { error_listener()->semanticError( @@ -1273,6 +1272,8 @@ continue; } has_resources = true; + // In case of override, need to clear the resource specifications. + inst->ClearResourceSpecs(); VisitResourceDetails(attribute_ctx->resource_spec()->resource_details(), inst, slot); continue; @@ -1280,8 +1281,6 @@ // Process instruction attribute specification. if (attribute_ctx->instruction_attribute_spec() != nullptr) { - // In case of override, need to clear the attribute specification. - inst->ClearAttributeSpecs(); // Signal error if there is more than one attribute specification. if (has_attributes) { error_listener()->semanticError( @@ -1289,6 +1288,8 @@ attribute_ctx->start, "Multiple attribute specifications"); continue; } + // In case of override, need to clear the attribute specification. + inst->ClearAttributeSpecs(); has_attributes = true; auto attr_list_ctx = attribute_ctx->instruction_attribute_spec() ->instruction_attribute_list(); @@ -1296,6 +1297,19 @@ continue; } + if (attribute_ctx->latency_spec() != nullptr) { + // Signal error if there is more than one latency specification. + if (has_latency) { + error_listener()->semanticError( + file_names_[context_file_map_.at(slot->ctx())], + attribute_ctx->start, "Multiple latency specifications"); + continue; + } + has_latency = true; + VisitLatencySpec(attribute_ctx->latency_spec(), slot, inst); + continue; + } + // Unknown attribute type. error_listener()->semanticError( file_names_[context_file_map_.at(slot->ctx())], attribute_ctx->start, @@ -1350,6 +1364,42 @@ attributes.clear(); } +void InstructionSetVisitor::VisitLatencySpec(LatencySpecCtx* latency_spec, + Slot* slot, Instruction* inst) { + for (auto* dest_op_with_latency : + latency_spec->dest_operand_latency_list()->dest_operand_with_latency()) { + std::string name; + if (dest_op_with_latency->op_name != nullptr) { + name = dest_op_with_latency->op_name->getText(); + } else { + name = dest_op_with_latency->array_dest->getText(); + } + // Make sure the destination operand exists. + DestinationOperand* dest_op = inst->GetDestOp(name); + if (dest_op == nullptr) { + error_listener()->semanticError( + file_names_[context_file_map_.at(slot->ctx())], + dest_op_with_latency->start, + absl::StrCat("Unknown destination operand '", name, "'")); + continue; + } + dest_op->ClearExpression(); + if (dest_op_with_latency->expression() != nullptr) { + context_file_map_.insert({dest_op_with_latency->expression(), + context_file_map_.at(slot->ctx())}); + auto* latency_expression = + VisitExpression(dest_op_with_latency->expression(), slot, inst); + dest_op->SetExpression(latency_expression); + } else if (dest_op_with_latency->wildcard == nullptr) { + if (slot->default_latency() != nullptr) { + dest_op->SetExpression(slot->default_latency()->DeepCopy()); + } else { + dest_op->SetExpression(new TemplateConstant(1)); + } + } + } +} + void InstructionSetVisitor::VisitSemfuncSpec(SemfuncSpecCtx* semfunc_spec, Instruction* inst) { auto* child = inst;
diff --git a/mpact/sim/decoder/instruction_set_visitor.h b/mpact/sim/decoder/instruction_set_visitor.h index 83fa3ba..0bd300d 100644 --- a/mpact/sim/decoder/instruction_set_visitor.h +++ b/mpact/sim/decoder/instruction_set_visitor.h
@@ -132,6 +132,8 @@ void VisitOpcodeAttributes(OpcodeAttributeListCtx* ctx, Instruction* inst, Slot* slot); void VisitSemfuncSpec(SemfuncSpecCtx* semfunc_spec, Instruction* inst); + void VisitLatencySpec(LatencySpecCtx* latency_spec, Slot* slot, + Instruction* inst); void VisitResourceDetails(ResourceDetailsCtx* ctx, Instruction* inst, Slot* slot); std::optional<ResourceReference*> ProcessResourceReference(
diff --git a/mpact/sim/decoder/opcode.cc b/mpact/sim/decoder/opcode.cc index a5e7e2e..c931bb5 100644 --- a/mpact/sim/decoder/opcode.cc +++ b/mpact/sim/decoder/opcode.cc
@@ -71,6 +71,12 @@ return nullptr; } +void Opcode::ClearDestLatencies() { + for (auto* dest_op : dest_op_vec_) { + dest_op->ClearExpression(); + } +} + bool Opcode::ValidateDestLatencies( const std::function<bool(int)>& validator) const { for (auto const* dest_op : dest_op_vec_) {
diff --git a/mpact/sim/decoder/opcode.h b/mpact/sim/decoder/opcode.h index ca04563..6bee33c 100644 --- a/mpact/sim/decoder/opcode.h +++ b/mpact/sim/decoder/opcode.h
@@ -80,6 +80,16 @@ expression_ = nullptr; } + void SetExpression(TemplateExpression* expression) { + if (expression_ != nullptr) delete expression_; + expression_ = expression; + } + + void ClearExpression() { + delete expression_; + expression_ = nullptr; + } + const std::string& name() const { return name_; } const std::string& pascal_case_name() const { return pascal_case_name_; } TemplateExpression* expression() const { return expression_; } @@ -238,6 +248,8 @@ // Checks destination latencies with the given function. Returns true if all // comply. bool ValidateDestLatencies(const std::function<bool(int)>& validator) const; + // Clear destination latencies. + void ClearDestLatencies(); int instruction_size() const { return instruction_size_; } void set_instruction_size(int val) { instruction_size_ = val; } Opcode* child() const { return child_; }
diff --git a/mpact/sim/generic/simple_resource_operand.h b/mpact/sim/generic/simple_resource_operand.h index 9b6f9b9..6484d0d 100644 --- a/mpact/sim/generic/simple_resource_operand.h +++ b/mpact/sim/generic/simple_resource_operand.h
@@ -65,7 +65,7 @@ // If the latency is 0 release immediately, otherwise, add the resource set // to the resource set delay line for release after 'latency' cycles. - inline void Release(int latency) { + void Release(int latency) { if (latency == 0) { resource_set_->Release(); return; @@ -74,7 +74,7 @@ } // Uses latency_. - inline void Release() { Release(latency_); } + void Release() { Release(latency_); } bool IsFree() override { return resource_set_->IsFree(); }