Merge pull request #468 from antmicro/wsip/reduce_expr

Reduce expressions in logic typespecs
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
index 2dc7f0c..ca8f32d 100644
--- a/systemverilog-plugin/UhdmAst.cc
+++ b/systemverilog-plugin/UhdmAst.cc
@@ -11,6 +11,7 @@
 #include "libs/sha1/sha1.h"
 
 // UHDM
+#include <uhdm/ExprEval.h>
 #include <uhdm/uhdm.h>
 #include <uhdm/vpi_user.h>
 
@@ -2173,6 +2174,19 @@
     add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
 }
 
+static UHDM::expr *reduce_expression(const UHDM::any *expr, const UHDM::any *inst, const UHDM::any *pexpr)
+{
+    log_assert(expr);
+    log_assert(inst);
+    log_assert(pexpr);
+
+    bool invalidvalue = false;
+    UHDM::ExprEval eval;
+    UHDM::expr *resolved_operation = eval.reduceExpr(expr, invalidvalue, inst, pexpr);
+    log_assert(!invalidvalue);
+    return resolved_operation;
+}
+
 void UhdmAst::process_enum_typespec()
 {
     // BaseTypespec specifies underlying type of the enum.
@@ -2180,6 +2194,42 @@
     // When base type is not specified in SystemVerilog code, it is assumed to be an int.
     // Type of enum items (constants) is the same as the enum type.
     current_node = make_ast_node(AST::AST_ENUM);
+
+    const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
+    const auto *enum_object = (const UHDM::enum_typespec *)handle->object;
+    const auto *typespec = enum_object->Base_typespec();
+
+    if (typespec && typespec->UhdmType() == UHDM::uhdmlogic_typespec) {
+        // If it's a logic_typespec, try to reduce expressions inside of it.
+        // The `reduceExpr` function needs the whole context of the enum typespec
+        //   so it's called here instead of `process_operation` or any other more specific function.
+
+        const UHDM::logic_typespec *logic_typespec_obj = enum_object->Base_typespec()->Cast<const UHDM::logic_typespec *>();
+        std::vector<UHDM::range *> ranges;
+        // Check if ranges exist, as Ranges() returns a pointer to std::vector.
+        if (logic_typespec_obj->Ranges()) {
+            ranges = *(logic_typespec_obj->Ranges());
+        }
+        for (UHDM::range *range_obj : ranges) {
+            // For each range, take both left and right and reduce them if they're of type uhdmoperation.
+            const auto *leftrange_obj = range_obj->Left_expr();
+            const auto *rightrange_obj = range_obj->Right_expr();
+            log_assert(leftrange_obj);
+            log_assert(rightrange_obj);
+
+            if (leftrange_obj->UhdmType() == UHDM::uhdmoperation) {
+                // Substitute the previous leftrange with the resolved operation result.
+                range_obj->Left_expr(reduce_expression(leftrange_obj, enum_object->Instance() ? enum_object->Instance() : enum_object->VpiParent(),
+                                                       enum_object->VpiParent()));
+            }
+            if (rightrange_obj->UhdmType() == UHDM::uhdmoperation) {
+                // Substitute the previous rightrange with the resolved operation result.
+                range_obj->Right_expr(reduce_expression(rightrange_obj, enum_object->Instance() ? enum_object->Instance() : enum_object->VpiParent(),
+                                                        enum_object->VpiParent()));
+            }
+        }
+    }
+
     bool has_base_type = false;
     visit_one_to_one({vpiBaseTypespec}, obj_h, [&](AST::AstNode *node) {
         has_base_type = true;