from types import *
from m5.util.grammar import Grammar
+from .operand_list import *
from .operand_types import *
from .util import *
else:
return [ arg ]
-class OperandList(object):
- '''Find all the operands in the given code block. Returns an operand
- descriptor list (instance of class OperandList).'''
- def __init__(self, parser, code):
- self.items = []
- self.bases = {}
- # delete strings and comments so we don't match on operands inside
- for regEx in (stringRE, commentRE):
- code = regEx.sub('', code)
- # search for operands
- next_pos = 0
- while 1:
- match = parser.operandsRE().search(code, next_pos)
- if not match:
- # no more matches: we're done
- break
- op = match.groups()
- # regexp groups are operand full name, base, and extension
- (op_full, op_base, op_ext) = op
- # If is a elem operand, define or update the corresponding
- # vector operand
- isElem = False
- if op_base in parser.elemToVector:
- isElem = True
- elem_op = (op_base, op_ext)
- op_base = parser.elemToVector[op_base]
- op_ext = '' # use the default one
- # if the token following the operand is an assignment, this is
- # a destination (LHS), else it's a source (RHS)
- is_dest = (assignRE.match(code, match.end()) != None)
- is_src = not is_dest
-
- # see if we've already seen this one
- op_desc = self.find_base(op_base)
- if op_desc:
- if op_ext and op_ext != '' and op_desc.ext != op_ext:
- error ('Inconsistent extensions for operand %s: %s - %s' \
- % (op_base, op_desc.ext, op_ext))
- op_desc.is_src = op_desc.is_src or is_src
- op_desc.is_dest = op_desc.is_dest or is_dest
- if isElem:
- (elem_base, elem_ext) = elem_op
- found = False
- for ae in op_desc.active_elems:
- (ae_base, ae_ext) = ae
- if ae_base == elem_base:
- if ae_ext != elem_ext:
- error('Inconsistent extensions for elem'
- ' operand %s' % elem_base)
- else:
- found = True
- if not found:
- op_desc.active_elems.append(elem_op)
- else:
- # new operand: create new descriptor
- op_desc = parser.operandNameMap[op_base](parser,
- op_full, op_ext, is_src, is_dest)
- # if operand is a vector elem, add the corresponding vector
- # operand if not already done
- if isElem:
- op_desc.elemExt = elem_op[1]
- op_desc.active_elems = [elem_op]
- self.append(op_desc)
- # start next search after end of current match
- next_pos = match.end()
- self.sort()
- # enumerate source & dest register operands... used in building
- # constructor later
- self.numSrcRegs = 0
- self.numDestRegs = 0
- self.numFPDestRegs = 0
- self.numIntDestRegs = 0
- self.numVecDestRegs = 0
- self.numVecPredDestRegs = 0
- self.numCCDestRegs = 0
- self.numMiscDestRegs = 0
- self.memOperand = None
-
- # Flags to keep track if one or more operands are to be read/written
- # conditionally.
- self.predRead = False
- self.predWrite = False
-
- for op_desc in self.items:
- if op_desc.isReg():
- if op_desc.is_src:
- op_desc.src_reg_idx = self.numSrcRegs
- self.numSrcRegs += 1
- if op_desc.is_dest:
- op_desc.dest_reg_idx = self.numDestRegs
- self.numDestRegs += 1
- if op_desc.isFloatReg():
- self.numFPDestRegs += 1
- elif op_desc.isIntReg():
- self.numIntDestRegs += 1
- elif op_desc.isVecReg():
- self.numVecDestRegs += 1
- elif op_desc.isVecPredReg():
- self.numVecPredDestRegs += 1
- elif op_desc.isCCReg():
- self.numCCDestRegs += 1
- elif op_desc.isControlReg():
- self.numMiscDestRegs += 1
- elif op_desc.isMem():
- if self.memOperand:
- error("Code block has more than one memory operand.")
- self.memOperand = op_desc
-
- # Check if this operand has read/write predication. If true, then
- # the microop will dynamically index source/dest registers.
- self.predRead = self.predRead or op_desc.hasReadPred()
- self.predWrite = self.predWrite or op_desc.hasWritePred()
-
- if parser.maxInstSrcRegs < self.numSrcRegs:
- parser.maxInstSrcRegs = self.numSrcRegs
- if parser.maxInstDestRegs < self.numDestRegs:
- parser.maxInstDestRegs = self.numDestRegs
- if parser.maxMiscDestRegs < self.numMiscDestRegs:
- parser.maxMiscDestRegs = self.numMiscDestRegs
-
- # now make a final pass to finalize op_desc fields that may depend
- # on the register enumeration
- for op_desc in self.items:
- op_desc.finalize(self.predRead, self.predWrite)
-
- def __len__(self):
- return len(self.items)
-
- def __getitem__(self, index):
- return self.items[index]
-
- def append(self, op_desc):
- self.items.append(op_desc)
- self.bases[op_desc.base_name] = op_desc
-
- def find_base(self, base_name):
- # like self.bases[base_name], but returns None if not found
- # (rather than raising exception)
- return self.bases.get(base_name)
-
- # internal helper function for concat[Some]Attr{Strings|Lists}
- def __internalConcatAttrs(self, attr_name, filter, result):
- for op_desc in self.items:
- if filter(op_desc):
- result += getattr(op_desc, attr_name)
- return result
-
- # return a single string that is the concatenation of the (string)
- # values of the specified attribute for all operands
- def concatAttrStrings(self, attr_name):
- return self.__internalConcatAttrs(attr_name, lambda x: 1, '')
-
- # like concatAttrStrings, but only include the values for the operands
- # for which the provided filter function returns true
- def concatSomeAttrStrings(self, filter, attr_name):
- return self.__internalConcatAttrs(attr_name, filter, '')
-
- # return a single list that is the concatenation of the (list)
- # values of the specified attribute for all operands
- def concatAttrLists(self, attr_name):
- return self.__internalConcatAttrs(attr_name, lambda x: 1, [])
-
- # like concatAttrLists, but only include the values for the operands
- # for which the provided filter function returns true
- def concatSomeAttrLists(self, filter, attr_name):
- return self.__internalConcatAttrs(attr_name, filter, [])
-
- def sort(self):
- self.items.sort(key=lambda a: a.sort_pri)
-
-class SubOperandList(OperandList):
- '''Find all the operands in the given code block. Returns an operand
- descriptor list (instance of class OperandList).'''
- def __init__(self, parser, code, requestor_list):
- self.items = []
- self.bases = {}
- # delete strings and comments so we don't match on operands inside
- for regEx in (stringRE, commentRE):
- code = regEx.sub('', code)
- # search for operands
- next_pos = 0
- while 1:
- match = parser.operandsRE().search(code, next_pos)
- if not match:
- # no more matches: we're done
- break
- op = match.groups()
- # regexp groups are operand full name, base, and extension
- (op_full, op_base, op_ext) = op
- # If is a elem operand, define or update the corresponding
- # vector operand
- if op_base in parser.elemToVector:
- elem_op = op_base
- op_base = parser.elemToVector[elem_op]
- # find this op in the requestor list
- op_desc = requestor_list.find_base(op_base)
- if not op_desc:
- error('Found operand %s which is not in the requestor list!'
- % op_base)
- else:
- # See if we've already found this operand
- op_desc = self.find_base(op_base)
- if not op_desc:
- # if not, add a reference to it to this sub list
- self.append(requestor_list.bases[op_base])
-
- # start next search after end of current match
- next_pos = match.end()
- self.sort()
- self.memOperand = None
- # Whether the whole PC needs to be read so parts of it can be accessed
- self.readPC = False
- # Whether the whole PC needs to be written after parts of it were
- # changed
- self.setPC = False
- # Whether this instruction manipulates the whole PC or parts of it.
- # Mixing the two is a bad idea and flagged as an error.
- self.pcPart = None
-
- # Flags to keep track if one or more operands are to be read/written
- # conditionally.
- self.predRead = False
- self.predWrite = False
-
- for op_desc in self.items:
- if op_desc.isPCPart():
- self.readPC = True
- if op_desc.is_dest:
- self.setPC = True
-
- if op_desc.isPCState():
- if self.pcPart is not None:
- if self.pcPart and not op_desc.isPCPart() or \
- not self.pcPart and op_desc.isPCPart():
- error("Mixed whole and partial PC state operands.")
- self.pcPart = op_desc.isPCPart()
-
- if op_desc.isMem():
- if self.memOperand:
- error("Code block has more than one memory operand.")
- self.memOperand = op_desc
-
- # Check if this operand has read/write predication. If true, then
- # the microop will dynamically index source/dest registers.
- self.predRead = self.predRead or op_desc.hasReadPred()
- self.predWrite = self.predWrite or op_desc.hasWritePred()
-
-# Regular expression object to match C++ strings
-stringRE = re.compile(r'"([^"\\]|\\.)*"')
-
-# Regular expression object to match C++ comments
-# (used in findOperands())
-commentRE = re.compile(r'(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?',
- re.DOTALL | re.MULTILINE)
-
-# Regular expression object to match assignment statements (used in
-# findOperands()). If the code immediately following the first
-# appearance of the operand matches this regex, then the operand
-# appears to be on the LHS of an assignment, and is thus a
-# destination. basically we're looking for an '=' that's not '=='.
-# The heinous tangle before that handles the case where the operand
-# has an array subscript.
-assignRE = re.compile(r'(\[[^\]]+\])?\s*=(?!=)', re.MULTILINE)
-
def makeFlagConstructor(flag_list):
if len(flag_list) == 0:
return ''
--- /dev/null
+# Copyright (c) 2014, 2016, 2018-2019 ARM Limited
+# All rights reserved
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder. You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Copyright (c) 2003-2005 The Regents of The University of Michigan
+# Copyright (c) 2013,2015 Advanced Micro Devices, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from .util import assignRE, commentRE, stringRE
+from .util import error
+
+class OperandList(object):
+ '''Find all the operands in the given code block. Returns an operand
+ descriptor list (instance of class OperandList).'''
+ def __init__(self, parser, code):
+ self.items = []
+ self.bases = {}
+ # delete strings and comments so we don't match on operands inside
+ for regEx in (stringRE, commentRE):
+ code = regEx.sub('', code)
+ # search for operands
+ next_pos = 0
+ while 1:
+ match = parser.operandsRE().search(code, next_pos)
+ if not match:
+ # no more matches: we're done
+ break
+ op = match.groups()
+ # regexp groups are operand full name, base, and extension
+ (op_full, op_base, op_ext) = op
+ # If is a elem operand, define or update the corresponding
+ # vector operand
+ isElem = False
+ if op_base in parser.elemToVector:
+ isElem = True
+ elem_op = (op_base, op_ext)
+ op_base = parser.elemToVector[op_base]
+ op_ext = '' # use the default one
+ # if the token following the operand is an assignment, this is
+ # a destination (LHS), else it's a source (RHS)
+ is_dest = (assignRE.match(code, match.end()) != None)
+ is_src = not is_dest
+
+ # see if we've already seen this one
+ op_desc = self.find_base(op_base)
+ if op_desc:
+ if op_ext and op_ext != '' and op_desc.ext != op_ext:
+ error ('Inconsistent extensions for operand %s: %s - %s' \
+ % (op_base, op_desc.ext, op_ext))
+ op_desc.is_src = op_desc.is_src or is_src
+ op_desc.is_dest = op_desc.is_dest or is_dest
+ if isElem:
+ (elem_base, elem_ext) = elem_op
+ found = False
+ for ae in op_desc.active_elems:
+ (ae_base, ae_ext) = ae
+ if ae_base == elem_base:
+ if ae_ext != elem_ext:
+ error('Inconsistent extensions for elem'
+ ' operand %s' % elem_base)
+ else:
+ found = True
+ if not found:
+ op_desc.active_elems.append(elem_op)
+ else:
+ # new operand: create new descriptor
+ op_desc = parser.operandNameMap[op_base](parser,
+ op_full, op_ext, is_src, is_dest)
+ # if operand is a vector elem, add the corresponding vector
+ # operand if not already done
+ if isElem:
+ op_desc.elemExt = elem_op[1]
+ op_desc.active_elems = [elem_op]
+ self.append(op_desc)
+ # start next search after end of current match
+ next_pos = match.end()
+ self.sort()
+ # enumerate source & dest register operands... used in building
+ # constructor later
+ self.numSrcRegs = 0
+ self.numDestRegs = 0
+ self.numFPDestRegs = 0
+ self.numIntDestRegs = 0
+ self.numVecDestRegs = 0
+ self.numVecPredDestRegs = 0
+ self.numCCDestRegs = 0
+ self.numMiscDestRegs = 0
+ self.memOperand = None
+
+ # Flags to keep track if one or more operands are to be read/written
+ # conditionally.
+ self.predRead = False
+ self.predWrite = False
+
+ for op_desc in self.items:
+ if op_desc.isReg():
+ if op_desc.is_src:
+ op_desc.src_reg_idx = self.numSrcRegs
+ self.numSrcRegs += 1
+ if op_desc.is_dest:
+ op_desc.dest_reg_idx = self.numDestRegs
+ self.numDestRegs += 1
+ if op_desc.isFloatReg():
+ self.numFPDestRegs += 1
+ elif op_desc.isIntReg():
+ self.numIntDestRegs += 1
+ elif op_desc.isVecReg():
+ self.numVecDestRegs += 1
+ elif op_desc.isVecPredReg():
+ self.numVecPredDestRegs += 1
+ elif op_desc.isCCReg():
+ self.numCCDestRegs += 1
+ elif op_desc.isControlReg():
+ self.numMiscDestRegs += 1
+ elif op_desc.isMem():
+ if self.memOperand:
+ error("Code block has more than one memory operand.")
+ self.memOperand = op_desc
+
+ # Check if this operand has read/write predication. If true, then
+ # the microop will dynamically index source/dest registers.
+ self.predRead = self.predRead or op_desc.hasReadPred()
+ self.predWrite = self.predWrite or op_desc.hasWritePred()
+
+ if parser.maxInstSrcRegs < self.numSrcRegs:
+ parser.maxInstSrcRegs = self.numSrcRegs
+ if parser.maxInstDestRegs < self.numDestRegs:
+ parser.maxInstDestRegs = self.numDestRegs
+ if parser.maxMiscDestRegs < self.numMiscDestRegs:
+ parser.maxMiscDestRegs = self.numMiscDestRegs
+
+ # now make a final pass to finalize op_desc fields that may depend
+ # on the register enumeration
+ for op_desc in self.items:
+ op_desc.finalize(self.predRead, self.predWrite)
+
+ def __len__(self):
+ return len(self.items)
+
+ def __getitem__(self, index):
+ return self.items[index]
+
+ def append(self, op_desc):
+ self.items.append(op_desc)
+ self.bases[op_desc.base_name] = op_desc
+
+ def find_base(self, base_name):
+ # like self.bases[base_name], but returns None if not found
+ # (rather than raising exception)
+ return self.bases.get(base_name)
+
+ # internal helper function for concat[Some]Attr{Strings|Lists}
+ def __internalConcatAttrs(self, attr_name, filter, result):
+ for op_desc in self.items:
+ if filter(op_desc):
+ result += getattr(op_desc, attr_name)
+ return result
+
+ # return a single string that is the concatenation of the (string)
+ # values of the specified attribute for all operands
+ def concatAttrStrings(self, attr_name):
+ return self.__internalConcatAttrs(attr_name, lambda x: 1, '')
+
+ # like concatAttrStrings, but only include the values for the operands
+ # for which the provided filter function returns true
+ def concatSomeAttrStrings(self, filter, attr_name):
+ return self.__internalConcatAttrs(attr_name, filter, '')
+
+ # return a single list that is the concatenation of the (list)
+ # values of the specified attribute for all operands
+ def concatAttrLists(self, attr_name):
+ return self.__internalConcatAttrs(attr_name, lambda x: 1, [])
+
+ # like concatAttrLists, but only include the values for the operands
+ # for which the provided filter function returns true
+ def concatSomeAttrLists(self, filter, attr_name):
+ return self.__internalConcatAttrs(attr_name, filter, [])
+
+ def sort(self):
+ self.items.sort(key=lambda a: a.sort_pri)
+
+class SubOperandList(OperandList):
+ '''Find all the operands in the given code block. Returns an operand
+ descriptor list (instance of class OperandList).'''
+ def __init__(self, parser, code, requestor_list):
+ self.items = []
+ self.bases = {}
+ # delete strings and comments so we don't match on operands inside
+ for regEx in (stringRE, commentRE):
+ code = regEx.sub('', code)
+ # search for operands
+ next_pos = 0
+ while 1:
+ match = parser.operandsRE().search(code, next_pos)
+ if not match:
+ # no more matches: we're done
+ break
+ op = match.groups()
+ # regexp groups are operand full name, base, and extension
+ (op_full, op_base, op_ext) = op
+ # If is a elem operand, define or update the corresponding
+ # vector operand
+ if op_base in parser.elemToVector:
+ elem_op = op_base
+ op_base = parser.elemToVector[elem_op]
+ # find this op in the requestor list
+ op_desc = requestor_list.find_base(op_base)
+ if not op_desc:
+ error('Found operand %s which is not in the requestor list!'
+ % op_base)
+ else:
+ # See if we've already found this operand
+ op_desc = self.find_base(op_base)
+ if not op_desc:
+ # if not, add a reference to it to this sub list
+ self.append(requestor_list.bases[op_base])
+
+ # start next search after end of current match
+ next_pos = match.end()
+ self.sort()
+ self.memOperand = None
+ # Whether the whole PC needs to be read so parts of it can be accessed
+ self.readPC = False
+ # Whether the whole PC needs to be written after parts of it were
+ # changed
+ self.setPC = False
+ # Whether this instruction manipulates the whole PC or parts of it.
+ # Mixing the two is a bad idea and flagged as an error.
+ self.pcPart = None
+
+ # Flags to keep track if one or more operands are to be read/written
+ # conditionally.
+ self.predRead = False
+ self.predWrite = False
+
+ for op_desc in self.items:
+ if op_desc.isPCPart():
+ self.readPC = True
+ if op_desc.is_dest:
+ self.setPC = True
+
+ if op_desc.isPCState():
+ if self.pcPart is not None:
+ if self.pcPart and not op_desc.isPCPart() or \
+ not self.pcPart and op_desc.isPCPart():
+ error("Mixed whole and partial PC state operands.")
+ self.pcPart = op_desc.isPCPart()
+
+ if op_desc.isMem():
+ if self.memOperand:
+ error("Code block has more than one memory operand.")
+ self.memOperand = op_desc
+
+ # Check if this operand has read/write predication. If true, then
+ # the microop will dynamically index source/dest registers.
+ self.predRead = self.predRead or op_desc.hasReadPred()
+ self.predWrite = self.predWrite or op_desc.hasWritePred()