blob: 174a54cd4c3d843a0355a60ad11d3cbb4193de47 [file] [log] [blame]
# Copyright (c) 2014, 2016, 2018-2019, 2022 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.
def overrideInOperand(func):
func.override_in_operand = True
return func
overrideInOperand.overrides = dict()
class OperandDesc(object):
def __init__(
self, base_cls, dflt_ext, reg_spec, flags=None, sort_pri=None
):
from .isa_parser import makeList
# Canonical flag structure is a triple of lists, where each list
# indicates the set of flags implied by this operand always, when
# used as a source, and when used as a dest, respectively.
# For simplicity this can be initialized using a variety of fairly
# obvious shortcuts; we convert these to canonical form here.
if not flags:
# no flags specified (e.g., 'None')
flags = ([], [], [])
elif isinstance(flags, str):
# a single flag: assumed to be unconditional
flags = ([flags], [], [])
elif isinstance(flags, list):
# a list of flags: also assumed to be unconditional
flags = (flags, [], [])
elif isinstance(flags, tuple):
# it's a tuple: it should be a triple,
# but each item could be a single string or a list
(uncond_flags, src_flags, dest_flags) = flags
flags = (
makeList(uncond_flags),
makeList(src_flags),
makeList(dest_flags),
)
attrs = {}
# reg_spec is either just a string or a dictionary
# (for elems of vector)
if isinstance(reg_spec, tuple):
(reg_spec, elem_spec) = reg_spec
if isinstance(elem_spec, str):
attrs["elem_spec"] = elem_spec
else:
assert isinstance(elem_spec, dict)
attrs["elems"] = elem_spec
for key in dir(self):
val = getattr(self, key)
# If this is a method, extract the function that implements it.
if hasattr(val, "__func__"):
val = val.__func__
# If this should override something in the operand
if getattr(val, "override_in_operand", False):
attrs[key] = val
attrs.update(
{
"base_cls": base_cls,
"dflt_ext": dflt_ext,
"reg_spec": reg_spec,
"flags": flags,
"sort_pri": sort_pri,
}
)
self.attrs = attrs
def setName(self, name):
self.attrs["base_name"] = name
class Operand(object):
"""Base class for operand descriptors. An instance of this class
(or actually a class derived from this one) represents a specific
operand for a code block (e.g, "Rc.sq" as a dest). Intermediate
derived classes encapsulates the traits of a particular operand
type (e.g., "32-bit integer register")."""
src_reg_constructor = "\n\tsetSrcRegIdx(_numSrcRegs++, %s);"
dst_reg_constructor = "\n\tsetDestRegIdx(_numDestRegs++, %s);"
def regId(self):
return f"{self.reg_class}[{self.reg_spec}]"
def srcRegId(self):
return self.regId()
def destRegId(self):
return self.regId()
def __init__(self, parser, full_name, ext, is_src, is_dest):
self.parser = parser
self.full_name = full_name
self.ext = ext
self.is_src = is_src
self.is_dest = is_dest
# The 'effective extension' (eff_ext) is either the actual
# extension, if one was explicitly provided, or the default.
if ext:
self.eff_ext = ext
elif hasattr(self, "dflt_ext"):
self.eff_ext = self.dflt_ext
if hasattr(self, "eff_ext"):
self.ctype = parser.operandTypeMap[self.eff_ext]
# Finalize additional fields (primarily code fields). This step
# is done separately since some of these fields may depend on the
# register index enumeration that hasn't been performed yet at the
# time of __init__().
def finalize(self):
self.flags = self.getFlags()
self.constructor = self.makeConstructor()
self.op_decl = self.makeDecl()
if self.is_src:
self.op_rd = self.makeRead()
self.op_src_decl = self.makeDecl()
else:
self.op_rd = ""
self.op_src_decl = ""
if self.is_dest:
self.op_wb = self.makeWrite()
self.op_dest_decl = self.makeDecl()
else:
self.op_wb = ""
self.op_dest_decl = ""
def isMem(self):
return 0
def isReg(self):
return 0
def isPCState(self):
return 0
def isPCPart(self):
return self.isPCState() and self.reg_spec
def getFlags(self):
# note the empty slice '[:]' gives us a copy of self.flags[0]
# instead of a reference to it
my_flags = self.flags[0][:]
if self.is_src:
my_flags += self.flags[1]
if self.is_dest:
my_flags += self.flags[2]
return my_flags
def makeDecl(self):
# Note that initializations in the declarations are solely
# to avoid 'uninitialized variable' errors from the compiler.
return self.ctype + " " + self.base_name + " = 0;\n"
class RegOperand(Operand):
def isReg(self):
return 1
def makeConstructor(self):
c_src = ""
c_dest = ""
if self.is_src:
c_src = self.src_reg_constructor % self.srcRegId()
if self.is_dest:
c_dest = self.dst_reg_constructor % self.destRegId()
c_dest += f"\n\t_numTypedDestRegs[{self.reg_class}.type()]++;"
return c_src + c_dest
class RegValOperand(RegOperand):
def makeRead(self):
reg_val = f"xc->getRegOperand(this, {self.src_reg_idx})"
if self.ctype == "float":
reg_val = f"bitsToFloat32({reg_val})"
elif self.ctype == "double":
reg_val = f"bitsToFloat64({reg_val})"
return f"{self.base_name} = {reg_val};\n"
def makeWrite(self):
reg_val = self.base_name
if self.ctype == "float":
reg_val = f"floatToBits32({reg_val})"
elif self.ctype == "double":
reg_val = f"floatToBits64({reg_val})"
return f"""
{{
RegVal final_val = {reg_val};
xc->setRegOperand(this, {self.dest_reg_idx}, final_val);
if (traceData) {{
traceData->setData({self.reg_class}, final_val);
}}
}}"""
class RegOperandDesc(OperandDesc):
def __init__(self, reg_class, *args, **kwargs):
super().__init__(*args, **kwargs)
self.attrs["reg_class"] = reg_class
class IntRegOperandDesc(RegOperandDesc):
def __init__(self, *args, **kwargs):
super().__init__("intRegClass", RegValOperand, *args, **kwargs)
class FloatRegOperandDesc(RegOperandDesc):
def __init__(self, *args, **kwargs):
super().__init__("floatRegClass", RegValOperand, *args, **kwargs)
class CCRegOperandDesc(RegOperandDesc):
def __init__(self, *args, **kwargs):
super().__init__("ccRegClass", RegValOperand, *args, **kwargs)
class VecElemOperandDesc(RegOperandDesc):
def __init__(self, *args, **kwargs):
super().__init__("vecElemClass", RegValOperand, *args, **kwargs)
class VecRegOperand(RegOperand):
reg_class = "vecRegClass"
def __init__(self, parser, full_name, ext, is_src, is_dest):
super().__init__(parser, full_name, ext, is_src, is_dest)
self.elemExt = None
def makeDeclElem(self, elem_op):
(elem_name, elem_ext) = elem_op
(elem_spec, dflt_elem_ext) = self.elems[elem_name]
if elem_ext:
ext = elem_ext
else:
ext = dflt_elem_ext
ctype = self.parser.operandTypeMap[ext]
return f"\n\t{ctype} {elem_name} = 0;"
def makeDecl(self):
if not self.is_dest and self.is_src:
c_decl = f"\t/* Vars for {self.base_name}*/"
if hasattr(self, "active_elems"):
if self.active_elems:
for elem in self.active_elems:
c_decl += self.makeDeclElem(elem)
return c_decl + f"\t/* End vars for {self.base_name} */\n"
else:
return ""
# Read destination register to write
def makeReadWElem(self, elem_op):
(elem_name, elem_ext) = elem_op
(elem_spec, dflt_elem_ext) = self.elems[elem_name]
if elem_ext:
ext = elem_ext
else:
ext = dflt_elem_ext
ctype = self.parser.operandTypeMap[ext]
c_read = f"\t\t{ctype}& {elem_name} = {self.base_name}[{elem_spec}];\n"
return c_read
def makeReadW(self):
tmp_name = f"tmp_d{self.dest_reg_idx}"
c_readw = (
f"\t\tauto &{tmp_name} = \n"
f"\t\t *({self.parser.namespace}::VecRegContainer *)\n"
f"\t\t xc->getWritableRegOperand(\n"
f"\t\t this, {self.dest_reg_idx});\n"
)
if self.elemExt:
ext = f"{self.parser.operandTypeMap[self.elemExt]}"
c_readw += f"\t\tauto {self.base_name} = {tmp_name}.as<{ext}>();\n"
if self.ext:
ext = f"{self.parser.operandTypeMap[self.ext]}"
c_readw += f"\t\tauto {self.base_name} = {tmp_name}.as<{ext}>();\n"
if hasattr(self, "active_elems"):
if self.active_elems:
for elem in self.active_elems:
c_readw += self.makeReadWElem(elem)
return c_readw
# Normal source operand read
def makeReadElem(self, elem_op, name):
(elem_name, elem_ext) = elem_op
(elem_spec, dflt_elem_ext) = self.elems[elem_name]
if elem_ext:
ext = elem_ext
else:
ext = dflt_elem_ext
ctype = self.parser.operandTypeMap[ext]
c_read = f"\t\t{elem_name} = {name}[{elem_spec}];\n"
return c_read
def makeRead(self):
name = self.base_name
if self.is_dest and self.is_src:
name += "_merger"
tmp_name = f"tmp_s{self.src_reg_idx}"
c_read = (
f"\t\t{self.parser.namespace}::VecRegContainer "
f"{tmp_name};\n"
f"\t\txc->getRegOperand(this, {self.src_reg_idx},\n"
f"\t\t &{tmp_name});\n"
)
# If the parser has detected that elements are being access, create
# the appropriate view
if self.elemExt:
ext = f"{self.parser.operandTypeMap[self.elemExt]}"
c_read += f"\t\tauto {name} = {tmp_name}.as<{ext}>();\n"
if self.ext:
ext = f"{self.parser.operandTypeMap[self.ext]}"
c_read += f"\t\tauto {name} = {tmp_name}.as<{ext}>();\n"
if hasattr(self, "active_elems"):
if self.active_elems:
for elem in self.active_elems:
c_read += self.makeReadElem(elem, name)
return c_read
def makeWrite(self):
return f"""
if (traceData) {{
traceData->setData({self.reg_class}, &tmp_d{self.dest_reg_idx});
}}
"""
def finalize(self):
super().finalize()
if self.is_dest:
self.op_rd = self.makeReadW() + self.op_rd
class VecRegOperandDesc(RegOperandDesc):
def __init__(self, *args, **kwargs):
super().__init__("vecRegClass", VecRegOperand, *args, **kwargs)
class VecPredRegOperand(RegOperand):
reg_class = "vecPredRegClass"
def makeDecl(self):
return ""
def makeRead(self):
tmp_name = f"tmp_s{self.src_reg_idx}"
c_read = (
f"\t\t{self.parser.namespace}::VecPredRegContainer \n"
f"\t\t {tmp_name};\n"
f"xc->getRegOperand(this, {self.src_reg_idx}, "
f"&{tmp_name});\n"
)
if self.ext:
c_read += (
f"\t\tauto {self.base_name} = {tmp_name}.as<"
f"{self.parser.operandTypeMap[self.ext]}>();\n"
)
return c_read
def makeReadW(self):
tmp_name = f"tmp_d{self.dest_reg_idx}"
c_readw = (
f"\t\tauto &{tmp_name} = \n"
f"\t\t *({self.parser.namespace}::"
f"VecPredRegContainer *)xc->getWritableRegOperand("
f"this, {self.dest_reg_idx});\n"
)
if self.ext:
c_readw += (
f"\t\tauto {self.base_name} = {tmp_name}.as<"
f"{self.parser.operandTypeMap[self.ext]}>();\n"
)
return c_readw
def makeWrite(self):
return f"""
if (traceData) {{
traceData->setData({self.reg_class}, &tmp_d{self.dest_reg_idx});
}}
"""
def finalize(self):
super().finalize()
if self.is_dest:
self.op_rd = self.makeReadW() + self.op_rd
class VecPredRegOperandDesc(RegOperandDesc):
def __init__(self, *args, **kwargs):
super().__init__("vecPredRegClass", VecPredRegOperand, *args, **kwargs)
class MatRegOperand(RegOperand):
reg_class = "MatRegClass"
def __init__(self, parser, full_name, ext, is_src, is_dest):
super().__init__(parser, full_name, ext, is_src, is_dest)
def makeDecl(self):
return ""
def makeReadW(self):
c_readw = (
f"\t\tauto &tmp_d{self.dest_reg_idx} = \n"
f"\t\t *({self.parser.namespace}::MatRegContainer *)\n"
f"\t\t xc->getWritableRegOperand(this, \n"
f"\t\t {self.dest_reg_idx});\n"
f"\t\tauto &{self.base_name} = tmp_d{self.dest_reg_idx};\n"
)
return c_readw
def makeRead(self):
name = self.base_name
if self.is_dest and self.is_src:
name += "_merger"
c_read = (
f"\t\t{self.parser.namespace}::MatRegContainer "
f"\t\t tmp_s{self.src_reg_idx};\n"
f"\t\txc->getRegOperand(this, {self.src_reg_idx},\n"
f"\t\t &tmp_s{self.src_reg_idx});\n"
f"\t\tauto &{name} = tmp_s{self.src_reg_idx};\n"
)
# The following is required due to the way that the O3 CPU
# works. The ZA register is seen as two physical registers; one
# for reading from and one for writing to. We need to make sure
# to copy the data from the read-only copy to the writable
# reference (the destination). Failure to do this results in
# data loss for the O3 CPU. Other CPU models don't appear to
# require this.
if self.is_dest and self.is_src:
c_read += f"{self.base_name} = {name};"
return c_read
def makeWrite(self):
return f"""
if (traceData) {{
traceData->setData({self.reg_class}, &tmp_d{self.dest_reg_idx});
}}
"""
def finalize(self):
super().finalize()
if self.is_dest:
self.op_rd = self.makeReadW() + self.op_rd
class MatRegOperandDesc(RegOperandDesc):
def __init__(self, *args, **kwargs):
super().__init__("matRegClass", MatRegOperand, *args, **kwargs)
class ControlRegOperand(Operand):
reg_class = "miscRegClass"
def isReg(self):
return 1
def isControlReg(self):
return 1
def makeConstructor(self):
c_src = ""
c_dest = ""
if self.is_src:
c_src = self.src_reg_constructor % self.srcRegId()
if self.is_dest:
c_dest = self.dst_reg_constructor % self.destRegId()
return c_src + c_dest
def makeRead(self):
bit_select = 0
if self.ctype == "float" or self.ctype == "double":
error("Attempt to read control register as FP")
return (
f"{self.base_name} = "
f"xc->readMiscRegOperand(this, {self.src_reg_idx});\n"
)
def makeWrite(self):
if self.ctype == "float" or self.ctype == "double":
error("Attempt to write control register as FP")
wb = (
f"xc->setMiscRegOperand(this, "
f"{self.dest_reg_idx}, {self.base_name});\n"
)
wb += f"""
if (traceData) {{
traceData->setData({self.reg_class}, {self.base_name});
}}
"""
return wb
class ControlRegOperandDesc(RegOperandDesc):
def __init__(self, *args, **kwargs):
super().__init__("miscRegClass", ControlRegOperand, *args, **kwargs)
class MemOperand(Operand):
def isMem(self):
return 1
def makeConstructor(self):
return ""
def makeDecl(self):
# Declare memory data variable.
return f"{self.ctype} {self.base_name} = {{}};\n"
def makeRead(self):
return ""
def makeWrite(self):
return ""
class MemOperandDesc(OperandDesc):
def __init__(self, *args, **kwargs):
super().__init__(MemOperand, *args, **kwargs)
class PCStateOperand(Operand):
def __init__(self, parser, *args, **kwargs):
super().__init__(parser, *args, **kwargs)
self.parser = parser
def makeConstructor(self):
return ""
def makeRead(self):
if self.reg_spec:
# A component of the PC state.
return (
f"{self.base_name} = "
f"__parserAutoPCState.{self.reg_spec}();\n"
)
else:
# The whole PC state itself.
return (
f"{self.base_name} = "
f"xc->pcState().as<{self.parser.namespace}::PCState>();\n"
)
def makeWrite(self):
if self.reg_spec:
# A component of the PC state.
return f"__parserAutoPCState.{self.reg_spec}({self.base_name});\n"
else:
# The whole PC state itself.
return f"xc->pcState({self.base_name});\n"
def makeDecl(self):
ctype = f"{self.parser.namespace}::PCState"
if self.isPCPart():
ctype = self.ctype
# Note that initializations in the declarations are solely
# to avoid 'uninitialized variable' errors from the compiler.
return f"{ctype} {self.base_name} = 0;\n"
def isPCState(self):
return 1
class PCStateOperandDesc(OperandDesc):
def __init__(self, *args, **kwargs):
super().__init__(PCStateOperand, *args, **kwargs)