This patch has been generated by applying flynt to the gem5 repo (ext has been excluded) JIRA: https://gem5.atlassian.net/browse/GEM5-831 Change-Id: I0935db6223d5426b99515959bde78e374cbadb04 Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/68957 Maintainer: Bobby Bruce <bbruce@ucdavis.edu> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu>
245 lines
10 KiB
Python
Executable File
245 lines
10 KiB
Python
Executable File
# 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
|
|
for match in parser.operandsRE().finditer(code):
|
|
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)
|
|
|
|
self.sort()
|
|
|
|
# enumerate source & dest register operands... used in building
|
|
# constructor later
|
|
regs = list(filter(lambda i: i.isReg(), self.items))
|
|
mem = list(filter(lambda i: i.isMem(), self.items))
|
|
srcs = list(filter(lambda r: r.is_src, regs))
|
|
dests = list(filter(lambda r: r.is_dest, regs))
|
|
|
|
for idx, reg in enumerate(srcs):
|
|
reg.src_reg_idx = idx
|
|
for idx, reg in enumerate(dests):
|
|
reg.dest_reg_idx = idx
|
|
|
|
self.numSrcRegs = len(srcs)
|
|
self.numDestRegs = len(dests)
|
|
|
|
if len(mem) > 1:
|
|
error("Code block has more than one memory operand")
|
|
|
|
self.memOperand = mem[0] if mem else None
|
|
|
|
# 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()
|
|
|
|
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
|
|
for match in parser.operandsRE().finditer(code):
|
|
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(
|
|
f"Found operand {op_base} which is not in the requestor list!"
|
|
)
|
|
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])
|
|
|
|
self.sort()
|
|
|
|
pcs = list(filter(lambda i: i.isPCState(), self.items))
|
|
mem = list(filter(lambda i: i.isMem(), self.items))
|
|
|
|
if len(mem) > 1:
|
|
error("Code block has more than one memory operand")
|
|
|
|
part = any(p.isPCPart() for p in pcs)
|
|
whole = any(not p.isPCPart() for p in pcs)
|
|
|
|
if part and whole:
|
|
error("Mixed whole and partial PC state operands")
|
|
|
|
self.memOperand = mem[0] if mem else None
|
|
|
|
# Whether the whole PC needs to be read so parts of it can be accessed
|
|
self.readPC = any(i.isPCPart() for i in self.items)
|
|
# Whether the whole PC needs to be written after parts of it were
|
|
# changed
|
|
self.setPC = any(i.isPCPart() and i.is_dest for i in self.items)
|
|
# 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
|
|
if part:
|
|
self.pcPart = True
|
|
if whole:
|
|
self.pcPart = False
|