arch: Build the operand REs in the isa_parser on demand.
authorGabe Black <gabeblack@google.com>
Mon, 28 Sep 2020 08:12:14 +0000 (01:12 -0700)
committerGabe Black <gabeblack@google.com>
Fri, 9 Oct 2020 04:32:00 +0000 (04:32 +0000)
These regular expressions search code snippets to find places where
operands are used. Rather than build them explicitly at the end of
processing the operands{{}} construct, wait until they're first going to
be used. That way, we'll be able to define operands in as many places as
we want, as long as we've done all we're going to do before the first
instructions are defined.

This will pave the way to defining operands in regular python in let
blocks, and then possibly outside of the parser altogether, perhaps into
scons where having lots of output files for individual instructions will
be easier to manage. For now, this just lets you define multiple
operands blocks which is not all that exciting on its own :)

Change-Id: I1179092316c1c0ac2613810bfd236a32235502fb
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35237
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Richard Cooper <richard.cooper@arm.com>
Reviewed-by: Steve Reinhardt <stever@gmail.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/arch/isa_parser.py

index 86f50892ff6ee0e34c4c1a48b623047c3191964a..955d4e276f6fbb3a1a664147ec448665757453eb 100755 (executable)
@@ -1133,7 +1133,7 @@ class OperandList(object):
         # search for operands
         next_pos = 0
         while 1:
-            match = parser.operandsRE.search(code, next_pos)
+            match = parser.operandsRE().search(code, next_pos)
             if not match:
                 # no more matches: we're done
                 break
@@ -1303,7 +1303,7 @@ class SubOperandList(OperandList):
         # search for operands
         next_pos = 0
         while 1:
-            match = parser.operandsRE.search(code, next_pos)
+            match = parser.operandsRE().search(code, next_pos)
             if not match:
                 # no more matches: we're done
                 break
@@ -1558,6 +1558,13 @@ class ISAParser(Grammar):
         # variable to hold templates
         self.templateMap = {}
 
+        # variable to hold operands
+        self.operandNameMap = {}
+
+        # Regular expressions for working with operands
+        self._operandsRE = None
+        self._operandsWithExtRE = None
+
         # This dictionary maps format name strings to Format objects.
         self.formatMap = {}
 
@@ -1590,6 +1597,16 @@ class ISAParser(Grammar):
         self.maxInstDestRegs = 0
         self.maxMiscDestRegs = 0
 
+    def operandsRE(self):
+        if not self._operandsRE:
+            self.buildOperandREs()
+        return self._operandsRE
+
+    def operandsWithExtRE(self):
+        if not self._operandsWithExtRE:
+            self.buildOperandREs()
+        return self._operandsWithExtRE
+
     def __getitem__(self, i):    # Allow object (self) to be
         return getattr(self, i)  # passed to %-substitutions
 
@@ -2581,18 +2598,19 @@ StaticInstPtr
             # in tmp_dict, just as if we evaluated a class declaration.
             operand_name[op_name] = type(cls_name, (base_cls,), tmp_dict)
 
-        self.operandNameMap = operand_name
+        self.operandNameMap.update(operand_name)
 
+    def buildOperandREs(self):
         # Define operand variables.
-        operands = list(user_dict.keys())
+        operands = list(self.operandNameMap.keys())
         # Add the elems defined in the vector operands and
         # build a map elem -> vector (used in OperandList)
         elem_to_vec = {}
-        for op in user_dict.keys():
-            if hasattr(self.operandNameMap[op], 'elems'):
-                for elem in self.operandNameMap[op].elems.keys():
+        for op_name, op in self.operandNameMap.items():
+            if hasattr(op, 'elems'):
+                for elem in op.elems.keys():
                     operands.append(elem)
-                    elem_to_vec[elem] = op
+                    elem_to_vec[elem] = op_name
         self.elemToVector = elem_to_vec
         extensions = self.operandTypeMap.keys()
 
@@ -2602,7 +2620,8 @@ StaticInstPtr
         (?!\w)       # neg. lookahead assertion: prevent partial matches
         ''' % ('|'.join(operands), '|'.join(extensions))
 
-        self.operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE)
+        self._operandsRE = re.compile(operandsREString,
+                                      re.MULTILINE | re.VERBOSE)
 
         # Same as operandsREString, but extension is mandatory, and only two
         # groups are returned (base and ext, not full name as above).
@@ -2610,14 +2629,14 @@ StaticInstPtr
         operandsWithExtREString = r'(?<!\w)(%s)_(%s)(?!\w)' \
             % ('|'.join(operands), '|'.join(extensions))
 
-        self.operandsWithExtRE = \
+        self._operandsWithExtRE = \
             re.compile(operandsWithExtREString, re.MULTILINE)
 
     def substMungedOpNames(self, code):
         '''Munge operand names in code string to make legal C++
         variable names.  This means getting rid of the type extension
         if any.  Will match base_name attribute of Operand object.)'''
-        return self.operandsWithExtRE.sub(r'\1', code)
+        return self.operandsWithExtRE().sub(r'\1', code)
 
     def mungeSnippet(self, s):
         '''Fix up code snippets for final substitution in templates.'''