This fixes handling of instruction attributes.

Attributes are now per slot.

PiperOrigin-RevId: 864978959
Change-Id: I3e3e22ba6eb6bf0b7239ea6899b8ab79addd07ac
diff --git a/mpact/sim/decoder/instruction_set.cc b/mpact/sim/decoder/instruction_set.cc
index 710326d..796cc74 100644
--- a/mpact/sim/decoder/instruction_set.cc
+++ b/mpact/sim/decoder/instruction_set.cc
@@ -38,8 +38,6 @@
 namespace machine_description {
 namespace instruction_set {
 
-absl::btree_set<std::string>* InstructionSet::attribute_names_ = nullptr;
-
 static void EmitEnumNames(const absl::btree_set<std::string>& names,
                           absl::string_view namespace_name,
                           absl::string_view op_name, std::string& h_output,
@@ -159,16 +157,6 @@
   slot_order_.push_back(slot);
 }
 
-void InstructionSet::AddAttributeName(const std::string& name) {
-  if (attribute_names_ == nullptr) {
-    attribute_names_ = new absl::btree_set<std::string>();
-  }
-  auto iter = attribute_names_->find(name);
-  if (iter == attribute_names_->end()) {
-    attribute_names_->insert(name);
-  }
-}
-
 // Return a string containing class header file, for all bundles and slots.
 // As an example the following shows an abbreviated example of code that is
 // generated.
@@ -751,16 +739,22 @@
   EmitEnumNames(name_set, "list_complex_resource_names", "ListComplexResource",
                 h_output, cc_output);
   // Emit instruction attribute types.
-  absl::StrAppend(&h_output, "  enum class AttributeEnum {\n");
-  int attribute_count = 0;
-  if (InstructionSet::attribute_names_ != nullptr) {
-    for (auto const& name : *InstructionSet::attribute_names_) {
-      absl::StrAppend(&h_output, "    k", ToPascalCase(name), " = ",
-                      attribute_count++, ",\n");
+
+  for (auto const& [name, slot_ptr] : slots_by_name) {
+    if (slot_ptr->attribute_names().empty()) continue;
+    absl::StrAppend(&h_output, "namespace ", ToSnakeCase(name), " {\n\n");
+    absl::StrAppend(&h_output, "  enum class AttributeEnum {\n");
+    int attribute_count = 0;
+    if (!slot_ptr->attribute_names().empty()) {
+      for (auto const& attribute_name : slot_ptr->attribute_names()) {
+        absl::StrAppend(&h_output, "    k", ToPascalCase(attribute_name), " = ",
+                        attribute_count++, ",\n");
+      }
     }
+    absl::StrAppend(&h_output, "    kPastMaxValue = ", attribute_count,
+                    "\n  };\n\n");
+    absl::StrAppend(&h_output, "}  // namespace ", name, "\n\n");
   }
-  absl::StrAppend(&h_output, "    kPastMaxValue = ", attribute_count,
-                  "\n  };\n\n");
 
   return {h_output, cc_output};
 }
diff --git a/mpact/sim/decoder/instruction_set.h b/mpact/sim/decoder/instruction_set.h
index a1a2efc..825eeba 100644
--- a/mpact/sim/decoder/instruction_set.h
+++ b/mpact/sim/decoder/instruction_set.h
@@ -80,8 +80,6 @@
   // defined.
   StringPair GenerateEnums(absl::string_view file_name);
 
-  static void AddAttributeName(const std::string& name);
-
   void AddInstruction(Instruction* inst) {
     if (instruction_map_.contains(inst->opcode()->name())) return;
     instruction_map_.emplace(inst->opcode()->name(), inst);
@@ -95,10 +93,7 @@
   Bundle* bundle() { return bundle_; }
   OpcodeFactory* opcode_factory() const { return opcode_factory_.get(); }
   ResourceFactory* resource_factory() const { return resource_factory_.get(); }
-  // Attribute names are shared across the isa's.
-  static const absl::btree_set<std::string>* attribute_names() {
-    return attribute_names_;
-  }
+
   absl::flat_hash_map<std::string, Bundle*>& bundle_map() {
     return bundle_map_;
   }
@@ -141,8 +136,6 @@
   // Maps from names to bundle/slot pointers.
   absl::flat_hash_map<std::string, Bundle*> bundle_map_;
   absl::flat_hash_map<std::string, Slot*> slot_map_;
-  // Attribute name list - shared across all the isas.
-  static absl::btree_set<std::string>* attribute_names_;
   // Maps from operand names to enum values.
   absl::flat_hash_map<std::string, int> pred_op_map_;
   absl::flat_hash_map<std::string, int> source_op_map_;
diff --git a/mpact/sim/decoder/instruction_set_visitor.cc b/mpact/sim/decoder/instruction_set_visitor.cc
index 00172e4..0c9bf89 100644
--- a/mpact/sim/decoder/instruction_set_visitor.cc
+++ b/mpact/sim/decoder/instruction_set_visitor.cc
@@ -1314,7 +1314,7 @@
           absl::StrCat("Duplicate attribute name '", name, "' in list"));
       continue;
     }
-    InstructionSet::AddAttributeName(name);
+    slot->AddAttributeName(name);
     if (attribute->expression() != nullptr) {
       context_file_map_.insert(
           {attribute->expression(), context_file_map_.at(slot->ctx())});
@@ -1322,7 +1322,7 @@
       attributes.emplace(name, expr);
       continue;
     }
-    attributes.emplace(name, new TemplateConstant(1));
+    attributes.emplace(name, new TemplateConstant(0));
   }
   // Are we parsing attributes for an instruction?
   if (inst != nullptr) {
diff --git a/mpact/sim/decoder/slot.cc b/mpact/sim/decoder/slot.cc
index e7cf436..d967ec5 100644
--- a/mpact/sim/decoder/slot.cc
+++ b/mpact/sim/decoder/slot.cc
@@ -252,33 +252,35 @@
                                              const Instruction* inst) const {
   std::string output;
   absl::StrAppend(&output, "void ", name, "(Instruction *inst) {\n");
-  if (!attribute_map_.empty()) {
+  int size = attribute_names_.size();
+  if (size > 0) {
     // Allocate the array and initialize to zero.
-    absl::StrAppend(&output, "  int *attrs = new int[", attribute_map_.size(),
+    absl::StrAppend(&output, "  int *attrs = new int[", size,
                     "];\n"
-                    "  attrs = {");
-    std::string sep = "";
-    for (auto const& [name, expr] : inst->attribute_map()) {
-      auto result = expr->GetValue();
+                    "  *attrs = {");
+    for (auto const& attribute_name : attribute_names_) {
+      auto it = inst->attribute_map().find(attribute_name);
+      if (it == inst->attribute_map().end()) {
+        absl::StrAppend(&output, "0, ");
+        continue;
+      }
+      auto result = it->second->GetValue();
       if (!result.ok()) {
-        absl::StrAppend(&output, "    #error Expression for '", name,
-                        "' has no constant value\n");
+        absl::StrAppend(&output, "0, ");
         continue;
       }
       int* value = std::get_if<int>(&result.value());
       if (value == nullptr) {
-        absl::StrAppend(&output, "    #error Expression for '", name,
-                        "' does not have type int\n");
+        absl::StrAppend(&output, "0, ");
         continue;
       }
-      absl::StrAppend(&output, sep, "*value");
-      sep = ", ";
+      absl::StrAppend(&output, *value, ", ");
     }
     absl::StrAppend(&output, "};\n");
-    absl::StrAppend(&output,
-                    "  inst->SetAttributes(absl::Span<int>(attrs, size));\n");
+    absl::StrAppend(&output, "  inst->SetAttributes(absl::Span<int>(attrs,",
+                    size, "));\n");
   }
-  absl::StrAppend(&output, "}\n");
+  absl::StrAppend(&output, "}\n\n");
   return output;
 }
 
@@ -1490,6 +1492,12 @@
   attribute_map_.emplace(name, expr);
 }
 
+void Slot::AddAttributeName(const std::string& name) {
+  if (!attribute_names_.contains(name)) {
+    attribute_names_.insert(name);
+  }
+}
+
 }  // namespace instruction_set
 }  // namespace machine_description
 }  // namespace sim
diff --git a/mpact/sim/decoder/slot.h b/mpact/sim/decoder/slot.h
index 9065874..fbdae67 100644
--- a/mpact/sim/decoder/slot.h
+++ b/mpact/sim/decoder/slot.h
@@ -22,6 +22,7 @@
 
 #include "absl/base/no_destructor.h"
 #include "absl/container/btree_map.h"
+#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"
@@ -112,6 +113,9 @@
   // Resources
   Resource* GetOrInsertResource(const std::string& name);
 
+  // Attributes
+  void AddAttributeName(const std::string& name);
+
   // Getters and setters.
   InstructionSet* instruction_set() const { return instruction_set_; }
   const SlotDeclCtx* ctx() const { return ctx_; }
@@ -159,6 +163,10 @@
     return attribute_map_;
   }
 
+  const absl::btree_set<std::string>& attribute_names() const {
+    return attribute_names_;
+  }
+
  private:
   // These functions generate the functions that are called by the decoder to
   // set the instruction operands.
@@ -251,6 +259,7 @@
   absl::btree_map<std::string, IdentListCtx*> resource_array_ref_map_;
   // Default instruction attributes.
   absl::btree_map<std::string, TemplateExpression*> attribute_map_;
+  absl::btree_set<std::string> attribute_names_;
 };
 
 }  // namespace instruction_set
diff --git a/mpact/sim/generic/instruction.h b/mpact/sim/generic/instruction.h
index b8606dc..12b66b6 100644
--- a/mpact/sim/generic/instruction.h
+++ b/mpact/sim/generic/instruction.h
@@ -219,7 +219,7 @@
       absl::MakeConstSpan(static_cast<int*>(nullptr), 0);
   // Architecture state object.
   ArchState* state_;
-  // Instruction execution context (this is usuall nullptr).
+  // Instruction execution context (this is usually nullptr).
   ReferenceCount* context_;
   // Semantic function that implements the instruction semantics.
   SemanticFunction semantic_fcn_;