[rtems-central commit] validation: Fix skipping of transition variants

Sebastian Huber sebh at rtems.org
Fri Sep 24 11:32:07 UTC 2021


Module:    rtems-central
Branch:    master
Commit:    3756347e83f7e7a2cb7863849fa13a96c7b68acc
Changeset: http://git.rtems.org/rtems-central/commit/?id=3756347e83f7e7a2cb7863849fa13a96c7b68acc

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Sep 21 20:15:58 2021 +0200

validation: Fix skipping of transition variants

---

 rtemsspec/content.py               |  9 +++++
 rtemsspec/tests/test_validation.py | 45 ++++++++++++++----------
 rtemsspec/transitionmap.py         |  7 ++--
 rtemsspec/validation.py            | 70 +++++++++++++++++++++++++++-----------
 4 files changed, 91 insertions(+), 40 deletions(-)

diff --git a/rtemsspec/content.py b/rtemsspec/content.py
index 5d6711c..a743098 100644
--- a/rtemsspec/content.py
+++ b/rtemsspec/content.py
@@ -29,6 +29,7 @@
 from contextlib import contextmanager
 import collections
 import itertools
+import math
 import os
 import re
 import sys
@@ -1162,3 +1163,11 @@ def to_camel_case(name: str) -> str:
     return name[0].upper() + _CAMEL_CASE_TO_UPPER.sub(
         lambda match: match.group(1).upper(),
         _CAMEL_CASE_DISCARD.sub(" ", name[1:].replace("+", "X")))
+
+
+def get_integer_type(value: int) -> str:
+    """
+    Returns an unsigned integer type which is large enough to store the value.
+    """
+    power = 2**max(math.ceil(math.log2(math.floor(math.log2(value)) + 1)), 3)
+    return f"uint{power}_t"
diff --git a/rtemsspec/tests/test_validation.py b/rtemsspec/tests/test_validation.py
index 2bc8b93..fc1bdc4 100644
--- a/rtemsspec/tests/test_validation.py
+++ b/rtemsspec/tests/test_validation.py
@@ -2233,36 +2233,44 @@ static T_fixture Action2_Fixture = {
   .initial_context = &Action2_Instance
 };
 
-static inline Action2_Entry Action2_PopEntry( Action2_Context *ctx )
-{
-  size_t index;
-
-  index = ctx->Map.index;
-  ctx->Map.index = index + 1;
-  return Action2_Entries[
-    Action2_Map[ index ]
-  ];
-}
+static const uint8_t Action2_Weights[] = {
+  9, 3, 1
+};
 
 static void Action2_Skip( Action2_Context *ctx, size_t index )
 {
-  size_t increment;
-
-  ctx->Map.skip = false;
-  increment = 1;
-
   switch ( index + 1 ) {
     case 1:
-      increment *= Action2_Pre_B_NA - ctx->Map.pci[ 1 ];
       ctx->Map.pci[ 1 ] = Action2_Pre_B_NA - 1;
       /* Fall through */
     case 2:
-      increment *= Action2_Pre_C_NA - ctx->Map.pci[ 2 ];
       ctx->Map.pci[ 2 ] = Action2_Pre_C_NA - 1;
       break;
   }
+}
+
+static inline Action2_Entry Action2_PopEntry( Action2_Context *ctx )
+{
+  size_t index;
+
+  if ( ctx->Map.skip ) {
+    size_t i;
+
+    ctx->Map.skip = false;
+    index = 0;
+
+    for ( i = 0; i < 3; ++i ) {
+      index += Action2_Weights[ i ] * ctx->Map.pci[ i ];
+    }
+  } else {
+    index = ctx->Map.index;
+  }
+
+  ctx->Map.index = index + 1;
 
-  ctx->Map.index += increment - 1;
+  return Action2_Entries[
+    Action2_Map[ index ]
+  ];
 }
 
 static void Action2_SetPreConditionStates( Action2_Context *ctx )
@@ -2307,6 +2315,7 @@ void Action2_Run( int *a, int b, int *c )
   ctx = T_push_fixture( &Action2_Node, &Action2_Fixture );
   ctx->Map.in_action_loop = true;
   ctx->Map.index = 0;
+  ctx->Map.skip = false;
 
   for (
     ctx->Map.pci[ 0 ] = Action2_Pre_A_A0;
diff --git a/rtemsspec/transitionmap.py b/rtemsspec/transitionmap.py
index 9d6ab8a..f3ad398 100644
--- a/rtemsspec/transitionmap.py
+++ b/rtemsspec/transitionmap.py
@@ -32,7 +32,8 @@ import math
 import textwrap
 from typing import Any, Dict, Iterator, List, NamedTuple, Optional, Tuple
 
-from rtemsspec.content import CContent, enabled_by_to_exp, ExpressionMapper
+from rtemsspec.content import CContent, enabled_by_to_exp, ExpressionMapper, \
+    get_integer_type
 from rtemsspec.items import is_enabled, Item
 
 
@@ -663,9 +664,9 @@ class TransitionMap:
         content.add([f"static const {ident}_Entry", f"{ident}_Entries[] = {{"])
         entries[-1] = entries[-1].replace("},", "}")
         content.append(entries)
-        bits = max(8, math.ceil(math.log2(len(self._entries)) / 8) * 8)
+        integer_type = get_integer_type(len(self._entries))
         content.append(
-            ["};", "", f"static const uint{bits}_t", f"{ident}_Map[] = {{"])
+            ["};", "", f"static const {integer_type}", f"{ident}_Map[] = {{"])
         text = ", ".join(
             str(self._entries[transitions.key][1])
             for transitions in self._map)
diff --git a/rtemsspec/validation.py b/rtemsspec/validation.py
index a4d284f..0a21808 100644
--- a/rtemsspec/validation.py
+++ b/rtemsspec/validation.py
@@ -27,12 +27,13 @@
 # pylint: disable=too-many-lines
 
 import itertools
+import functools
 import os
 import re
 from typing import Any, Dict, List, Optional, Tuple
 
 from rtemsspec.content import CContent, CInclude, \
-    GenericContent, get_value_params, get_value_plural, \
+    GenericContent, get_integer_type, get_value_params, get_value_plural, \
     get_value_doxygen_group, get_value_doxygen_function, to_camel_case
 from rtemsspec.items import Item, ItemCache, \
     ItemGetValueContext, ItemMapper
@@ -601,25 +602,32 @@ class _ActionRequirementTestItem(_TestItem):
             content.call_function(None, f"{self.ident}_{name}", ["ctx"])
 
     def _add_skip(self, content: CContent) -> Any:
+        state_counts = [len(enum) - 2 for enum in self._pre_co_idx_to_enum]
+        weigths = [
+            str(
+                functools.reduce((lambda x, y: x * y),
+                                 state_counts[index + 1:], 1))
+            for index in range(self._pre_co_count)
+        ]
+        integer_type = get_integer_type(int(weigths[0]))
+        content.add(f"static const {integer_type} {self.ident}_Weights[] = {{")
+        with content.indent():
+            content.wrap(", ".join(weigths))
+        content.add("};")
         with content.function("static void", f"{self.ident}_Skip",
                               [f"{self.context} *ctx", "size_t index"]):
-            content.append([
-                "size_t increment;", "", "ctx->Map.skip = false;",
-                "increment = 1;", "", "switch ( index + 1 ) {"
-            ])
+            content.append("switch ( index + 1 ) {")
             fall_through = "/* Fall through */"
             with content.indent():
                 for index, enum in enumerate(self._pre_co_idx_to_enum[1:], 1):
                     content.add(f"case {index}:")
                     with content.indent():
                         pci = f"ctx->Map.{self._pci}[ {index} ]"
-                        content.append([
-                            f"increment *= {enum[-1]} - {pci};",
-                            f"{pci} = {enum[-1]} - 1;", fall_through
-                        ])
+                        content.append(
+                            [f"{pci} = {enum[-1]} - 1;", fall_through])
                 content.lines[-1] = content.lines[-1].replace(
                     fall_through, "break;")
-            content.append(["}", "", "ctx->Map.index += increment - 1;"])
+            content.append("}")
 
     def _add_test_variant(self, content: CContent,
                           transition_map: TransitionMap) -> None:
@@ -694,19 +702,38 @@ class _ActionRequirementTestItem(_TestItem):
                     gap = False
                     content.add(pcs_pci)
 
-    def _add_test_case(self, content: CContent, transition_map: TransitionMap,
-                       header: Dict[str, Any]) -> None:
+    def _add_pop_entry(self, content: CContent) -> None:
         ret = f"static inline {self.ident}_Entry"
         name = f"{self.ident}_PopEntry"
         params = [f"{self.context} *ctx"]
         with content.function(ret, name, params, align=True):
+            content.add("size_t index;")
+            if self._pre_co_skip:
+                with content.first_condition("ctx->Map.skip"):
+                    content.add([
+                        "size_t i;", "", "ctx->Map.skip = false;", "index = 0;"
+                    ])
+                    with content.for_loop("i = 0", f"i < {self._pre_co_count}",
+                                          "++i"):
+                        content.append(f"index += {self.ident}_Weights[ i ]"
+                                       f" * ctx->Map.{self._pci}[ i ];")
+                with content.final_condition():
+                    content.add("index = ctx->Map.index;")
+                content.add("ctx->Map.index = index + 1;")
+            else:
+                content.add(
+                    ["index = ctx->Map.index;", "ctx->Map.index = index + 1;"])
+                content.gap = False
             content.add([
-                "size_t index;", "", "index = ctx->Map.index;",
-                "ctx->Map.index = index + 1;", f"return {self.ident}_Entries[",
+                f"return {self.ident}_Entries[",
                 f"  {self.ident}_Map[ index ]", "];"
             ])
+
+    def _add_test_case(self, content: CContent, transition_map: TransitionMap,
+                       header: Dict[str, Any]) -> None:
         if self._pre_co_skip:
             self._add_skip(content)
+        self._add_pop_entry(content)
         if transition_map.has_pre_co_not_applicable():
             self._add_set_pre_co_states(content, transition_map)
         with content.function("static void", f"{self.ident}_TestVariant",
@@ -715,6 +742,11 @@ class _ActionRequirementTestItem(_TestItem):
         fixture = f"{self.ident}_Fixture"
         prologue = CContent()
         epilogue = CContent()
+        map_members_initialization = [
+            "ctx->Map.in_action_loop = true;", "ctx->Map.index = 0;"
+        ]
+        if self._pre_co_skip:
+            map_members_initialization.append("ctx->Map.skip = false;")
         if header:
             content.add(f"static T_fixture_node {self.ident}_Node;")
             ret = "void"
@@ -724,8 +756,7 @@ class _ActionRequirementTestItem(_TestItem):
             self.assign_run_params(prologue, header)
             prologue.call_function("ctx =", "T_push_fixture",
                                    [f"&{self.ident}_Node", f"&{fixture}"])
-            prologue.append(
-                ["ctx->Map.in_action_loop = true;", "ctx->Map.index = 0;"])
+            prologue.append(map_members_initialization)
             epilogue.add("T_pop_fixture();")
             align = True
         else:
@@ -737,9 +768,10 @@ class _ActionRequirementTestItem(_TestItem):
             name = "T_TEST_CASE_FIXTURE"
             params = [f"{self.ident}", f"&{fixture}"]
             prologue.add([
-                f"{self.context} *ctx;", "", "ctx = T_fixture_context();",
-                "ctx->Map.in_action_loop = true;", "ctx->Map.index = 0;"
-            ])
+                f"{self.context} *ctx;",
+                "",
+                "ctx = T_fixture_context();",
+            ] + map_members_initialization)
             align = False
         with content.function(ret, name, params, align=align):
             content.add(prologue)



More information about the vc mailing list