Changes to accomodate the new OO style

This commit is contained in:
stefandesouza
2023-08-28 15:19:46 +02:00
parent 36549dd679
commit 615ef82f04
11 changed files with 198 additions and 216 deletions

0
osaca/db_interface.py Executable file → Normal file
View File

0
osaca/frontend.py Executable file → Normal file
View File

5
osaca/osaca.py Executable file → Normal file
View File

@@ -430,10 +430,7 @@ def get_unmatched_instruction_ratio(kernel):
"""Return ratio of unmatched from total instructions in kernel."""
unmatched_counter = 0
for instruction in kernel:
if (
INSTR_FLAGS.TP_UNKWN in instruction["flags"]
and INSTR_FLAGS.LT_UNKWN in instruction["flags"]
):
if INSTR_FLAGS.TP_UNKWN in instruction.flags and INSTR_FLAGS.LT_UNKWN in instruction.flags:
unmatched_counter += 1
return unmatched_counter / len(kernel)

View File

@@ -4,18 +4,6 @@ from osaca.parser.directive import DirectiveOperand
class InstructionForm:
# Identifiers for operand types
COMMENT_ID = "comment"
DIRECTIVE_ID = "directive"
IMMEDIATE_ID = "immediate"
LABEL_ID = "label"
IDENTIFIER_ID = "identifier"
MEMORY_ID = "memory"
REGISTER_ID = "register"
SEGMENT_EXT_ID = "segment_extension"
INSTRUCTION_ID = "instruction"
OPERANDS_ID = "operands"
def __init__(
self,
INSTRUCTION_ID=None,
@@ -91,6 +79,18 @@ class InstructionForm:
def flags(self):
return self._FLAGS
@property
def throughput(self):
return self._THROUGHPUT
@property
def latency(self):
return self._LATENCY
@property
def latency_wo_load(self):
return self._LATENCY_WO_LOAD
@semantic_operands.setter
def semantic_operands(self, semantic_operands):
self._SEMANTIC_OPERANDS = semantic_operands
@@ -135,6 +135,18 @@ class InstructionForm:
def flags(self, flags):
self._FLAGS = flags
@throughput.setter
def throughput(self, throughput):
self._THROUGHPUT = throughput
@latency.setter
def latency(self, latency):
self._LATENCY = latency
@latency_wo_load.setter
def latency_wo_load(self, latency_wo_load):
self._LATENCY_WO_LOAD = latency_wo_load
def __repr__(self):
return f"InstructionForm(INSTRUCTION_ID={self._INSTRUCTION_ID}, OPERANDS_ID={self._OPERANDS_ID}, DIRECTIVE_ID={self._DIRECTIVE_ID}, COMMENT_ID={self._COMMENT_ID}, LABEL_ID={self._LABEL_ID}, LINE={self._LINE}, LINE_NUMBER={self._LINE_NUMBER}, SEMANTIC_OPERANDS={self._SEMANTIC_OPERANDS})"

View File

@@ -386,8 +386,8 @@ class ParserX86ATT(BaseParser):
def is_reg_dependend_of(self, reg_a, reg_b):
"""Check if ``reg_a`` is dependent on ``reg_b``"""
# Normalize name
reg_a_name = reg_a["name"].upper()
reg_b_name = reg_b["name"].upper()
reg_a_name = reg_a.name.upper()
reg_b_name = reg_b.name.upper()
# Check if they are the same registers
if reg_a_name == reg_b_name:
@@ -428,8 +428,8 @@ class ParserX86ATT(BaseParser):
def is_basic_gpr(self, register):
"""Check if register is a basic general purpose register (ebi, rax, ...)"""
if any(char.isdigit() for char in register["name"]) or any(
register["name"].lower().startswith(x) for x in ["mm", "xmm", "ymm", "zmm"]
if any(char.isdigit() for char in register.name) or any(
register.name.lower().startswith(x) for x in ["mm", "xmm", "ymm", "zmm"]
):
return False
return True
@@ -446,7 +446,7 @@ class ParserX86ATT(BaseParser):
"""Check if register is a vector register"""
if register is None:
return False
if register["name"].rstrip(string.digits).lower() in [
if register.name.rstrip(string.digits).lower() in [
"mm",
"xmm",
"ymm",

View File

@@ -69,9 +69,7 @@ class ArchSemantics(ISASemantics):
indices = [port_list.index(p) for p in ports]
# check if port sum of used ports for uop are unbalanced
port_sums = self._to_list(itemgetter(*indices)(self.get_throughput_sum(kernel)))
instr_ports = self._to_list(
itemgetter(*indices)(instruction_form.port_pressure)
)
instr_ports = self._to_list(itemgetter(*indices)(instruction_form.port_pressure))
if len(set(port_sums)) > 1:
# balance ports
# init list for keeping track of the current change
@@ -110,9 +108,7 @@ class ArchSemantics(ISASemantics):
][0]
instruction_form.port_pressure[zero_index] = 0.0
# Remove from further balancing
indices = [
p for p in indices if instruction_form.port_pressure[p] > 0
]
indices = [p for p in indices if instruction_form.port_pressure[p] > 0]
instr_ports = self._to_list(
itemgetter(*indices)(instruction_form.port_pressure)
)
@@ -193,6 +189,7 @@ class ArchSemantics(ISASemantics):
instruction_data = self._machine_model.get_instruction(
instruction_form.instruction, instruction_form.operands
)
if (
not instruction_data
and self._isa == "x86"

View File

@@ -14,6 +14,11 @@ import ruamel.yaml
from osaca import __version__, utils
from osaca.parser import ParserX86ATT
from ruamel.yaml.compat import StringIO
from osaca.parser.operand import Operand
from osaca.parser.memory import MemoryOperand
from osaca.parser.register import RegisterOperand
from osaca.parser.immediate import ImmediateOperand
from osaca.parser.identifier import IdentifierOperand
class MachineModel(object):
@@ -21,7 +26,7 @@ class MachineModel(object):
INTERNAL_VERSION = 1 # increase whenever self._data format changes to invalidate cache!
_runtime_cache = {}
def __init__(self, arch=None, path_to_yaml=None, isa=None, lazy=False):
def __init__(self, arch=None, path_to_yaml=None, isa=None, lazy=True):
if not arch and not path_to_yaml:
if not isa:
raise ValueError("One of arch, path_to_yaml and isa must be specified")
@@ -97,6 +102,7 @@ class MachineModel(object):
# Normalize instruction_form names (to UPPERCASE) and build dict for faster access:
self._data["instruction_forms_dict"] = defaultdict(list)
for iform in self._data["instruction_forms"]:
print(iform)
iform["name"] = iform["name"].upper()
self._data["instruction_forms_dict"][iform["name"]].append(iform)
self._data["internal_version"] = self.INTERNAL_VERSION
@@ -128,6 +134,7 @@ class MachineModel(object):
if name is None:
return None
name_matched_iforms = self._data["instruction_forms_dict"].get(name.upper(), [])
# print(name_matched_iforms)
try:
return next(
instruction_form
@@ -264,7 +271,7 @@ class MachineModel(object):
def get_full_instruction_name(instruction_form):
"""Get one instruction name string including the mnemonic and all operands."""
operands = []
for op in instruction_form["operands"]:
for op in instruction_form.operands:
op_attrs = [
y + ":" + str(op[y])
for y in list(filter(lambda x: True if x != "class" else False, op))
@@ -526,7 +533,9 @@ class MachineModel(object):
def _check_operands(self, i_operand, operand):
"""Check if the types of operand ``i_operand`` and ``operand`` match."""
# check for wildcard
if self.WILDCARD in operand.name:
if (isinstance(operand, Operand) and operand.name == self.WILDCARD) or (
not isinstance(operand, Operand) and self.WILDCARD in operand
):
if (
"class" in i_operand
and i_operand["class"] == "register"
@@ -601,25 +610,27 @@ class MachineModel(object):
def _check_x86_operands(self, i_operand, operand):
"""Check if the types of operand ``i_operand`` and ``operand`` match."""
if "class" in operand.name:
# compare two DB entries
return self._compare_db_entries(i_operand, operand)
# if "class" in operand.name:
# compare two DB entries
# return self._compare_db_entries(i_operand, operand)
# register
if "register" in operand.name:
if isinstance(operand, RegisterOperand):
if i_operand["class"] != "register":
return False
return self._is_x86_reg_type(i_operand, operand, consider_masking=False)
# memory
if "memory" in operand.name:
if isinstance(operand, MemoryOperand):
if i_operand["class"] != "memory":
return False
return self._is_x86_mem_type(i_operand, operand)
# immediate
if "immediate" in operand.name or operand.value != None:
if isinstance(operand, ImmediateOperand):
# if "immediate" in operand.name or operand.value != None:
return i_operand["class"] == "immediate" and i_operand["imd"] == "int"
# identifier (e.g., labels)
if "identifier" in operand.name:
if isinstance(operand, IdentifierOperand):
return i_operand["class"] == "identifier"
return self._compare_db_entries(i_operand, operand)
def _compare_db_entries(self, operand_1, operand_2):
"""Check if operand types in DB format (i.e., not parsed) match."""
@@ -676,29 +687,29 @@ class MachineModel(object):
return True
return False
# check for wildcards
if i_reg_name == self.WILDCARD or reg["name"] == self.WILDCARD:
if i_reg_name == self.WILDCARD or reg.name == self.WILDCARD:
return True
# differentiate between vector registers (mm, xmm, ymm, zmm) and others (gpr)
parser_x86 = ParserX86ATT()
if parser_x86.is_vector_register(reg):
if reg["name"].rstrip(string.digits).lower() == i_reg_name:
if reg.name.rstrip(string.digits).lower() == i_reg_name:
# Consider masking and zeroing for AVX512
if consider_masking:
mask_ok = zero_ok = True
if "mask" in reg or "mask" in i_reg:
if reg.mask != None or "mask" in i_reg:
# one instruction is missing the masking while the other has it
mask_ok = False
# check for wildcard
if (
(
"mask" in reg
and reg["mask"].rstrip(string.digits).lower() == i_reg.get("mask")
reg.mask != None
and reg.mask.rstrip(string.digits).lower() == i_reg.get("mask")
)
or reg.get("mask") == self.WILDCARD
or reg.mask == self.WILDCARD
or i_reg.get("mask") == self.WILDCARD
):
mask_ok = True
if bool("zeroing" in reg) ^ bool("zeroing" in i_reg):
if bool(reg.zeroing) ^ bool("zeroing" in i_reg):
# one instruction is missing zeroing while the other has it
zero_ok = False
# check for wildcard
@@ -776,48 +787,48 @@ class MachineModel(object):
if (
# check base
(
(mem["base"] is None and i_mem["base"] is None)
(mem.base is None and i_mem["base"] is None)
or i_mem["base"] == self.WILDCARD
or self._is_x86_reg_type(i_mem["base"], mem["base"])
or self._is_x86_reg_type(i_mem["base"], mem.base)
)
# check offset
and (
mem["offset"] == i_mem["offset"]
mem.offset == i_mem["offset"]
or i_mem["offset"] == self.WILDCARD
or (
mem["offset"] is not None
and "identifier" in mem["offset"]
mem.offset is not None
and "identifier" in mem.offset
and i_mem["offset"] == "identifier"
)
or (
mem["offset"] is not None
and "value" in mem["offset"]
mem.offset is not None
and "value" in mem.offset
and (
i_mem["offset"] == "imd"
or (i_mem["offset"] is None and mem["offset"]["value"] == "0")
i_mem.offset == "imd"
or (i_mem["offset"] is None and mem.offset["value"] == "0")
)
)
or (
mem["offset"] is not None
and "identifier" in mem["offset"]
mem.offset is not None
and "identifier" in mem.offset
and i_mem["offset"] == "id"
)
)
# check index
and (
mem["index"] == i_mem["index"]
mem.index == i_mem["index"]
or i_mem["index"] == self.WILDCARD
or (
mem["index"] is not None
and "name" in mem["index"]
and self._is_x86_reg_type(i_mem["index"], mem["index"])
mem.index is not None
and "name" in mem.index
and self._is_x86_reg_type(i_mem["index"], mem.index)
)
)
# check scale
and (
mem["scale"] == i_mem["scale"]
mem.scale == i_mem["scale"]
or i_mem["scale"] == self.WILDCARD
or (mem["scale"] != 1 and i_mem["scale"] != 1)
or (mem.scale != 1 and i_mem["scale"] != 1)
)
):
return True

View File

@@ -4,39 +4,10 @@ from itertools import chain
from osaca import utils
from osaca.parser import AttrDict, ParserAArch64, ParserX86ATT
from osaca.parser.memory import MemoryOperand
from osaca.parser.register import RegisterOperand
from .hw_model import MachineModel
class SemanticForm:
def __init__(self, SOURCE_ID = [], DESTINATION_ID = [], SRC_DST = []):
self._SOURCE_ID = SOURCE_ID
self._DESTINATION_ID = DESTINATION_ID
self._SRC_DST = SRC_DST
@property
def source(self):
return self._SOURCE_ID
@source.setter
def source(self, source):
self._SOURCE_ID = source
@property
def destination(self):
return self._DESTINATION_ID
@destination.setter
def destination(self, destination):
self._DESTINATION_ID = destination
@property
def src_dst(self):
return self._SRC_DST
@src_dst.setter
def src_dst(self, src_dst):
self._SRC_DST = src_dst
class INSTR_FLAGS:
"""
@@ -77,9 +48,7 @@ class ISASemantics(object):
"""Update instruction form dictionary with source, destination and flag information."""
# if the instruction form doesn't have operands or is None, there's nothing to do
if instruction_form.operands is None or instruction_form.instruction is None:
instruction_form.semantic_operands = SemanticForm(
SOURCE_ID = [], DESTINATION_ID = [], SRC_DST = []
)
instruction_form.semantic_operands = {"source": [], "destination": [], "src_dst": []}
return
# check if instruction form is in ISA yaml, otherwise apply standard operand assignment
# (one dest, others source)
@@ -111,8 +80,7 @@ class ISASemantics(object):
# Couldn't found instruction form in ISA DB
assign_default = True
# check for equivalent register-operands DB entry if LD/ST
if isinstance(operands, MemoryOperand) and operands.name == "memory":
if any([isinstance(op, MemoryOperand) for op in operands]):
operands_reg = self.substitute_mem_address(instruction_form.operands)
isa_data_reg = self._isa_model.get_instruction(
instruction_form.instruction, operands_reg
@@ -146,46 +114,34 @@ class ISASemantics(object):
op_dict["src_dst"] = []
# post-process pre- and post-indexing for aarch64 memory operands
if self._isa == "aarch64":
for operand in [op for op in op_dict["source"] if "memory" in op]:
post_indexed = (
"post_indexed" in operand["memory"] and operand["memory"]["post_indexed"]
)
pre_indexed = (
"pre_indexed" in operand["memory"] and operand["memory"]["pre_indexed"]
)
for operand in [op for op in op_dict["source"] if isinstance(op, MemoryOperand)]:
post_indexed = operand.post_indexed
pre_indexed = operand.pre_indexed
if post_indexed or pre_indexed:
op_dict["src_dst"].append(
AttrDict.convert_dict(
{
"register": operand["memory"]["base"],
"pre_indexed": pre_indexed,
"post_indexed": post_indexed,
}
)
{
"register": operand.base,
"pre_indexed": pre_indexed,
"post_indexed": post_indexed,
}
)
for operand in [op for op in op_dict["destination"] if "memory" in op]:
post_indexed = (
"post_indexed" in operand["memory"] and operand["memory"]["post_indexed"]
)
pre_indexed = (
"pre_indexed" in operand["memory"] and operand["memory"]["pre_indexed"]
)
for operand in [op for op in op_dict["destination"] if isinstance(op, MemoryOperand)]:
post_indexed = operand.post_indexed
pre_indexed = operand.pre_indexed
if post_indexed or pre_indexed:
op_dict["src_dst"].append(
AttrDict.convert_dict(
{
"register": operand["memory"]["base"],
"pre_indexed": pre_indexed,
"post_indexed": post_indexed,
}
)
{
"register": operand.base,
"pre_indexed": pre_indexed,
"post_indexed": post_indexed,
}
)
# store operand list in dict and reassign operand key/value pair
instruction_form.semantic_operands = AttrDict.convert_dict(op_dict)
instruction_form.semantic_operands = op_dict
# assign LD/ST flags
instruction_form.flags = (
instruction_form.flags if instruction_form.flags != [] else []
)
# instruction_form.flags = (
# instruction_form.flags if "flags" in instruction_form else []
# )
if self._has_load(instruction_form):
instruction_form.flags += [INSTR_FLAGS.HAS_LD]
if self._has_store(instruction_form):
@@ -198,15 +154,15 @@ class ISASemantics(object):
Empty dict if no changes of registers occured. None for registers with unknown changes.
If only_postindexed is True, only considers changes due to post_indexed memory references.
"""
if instruction_form.get("instruction") is None:
if instruction_form.instruction is None:
return {}
dest_reg_names = [
op.register.get("prefix", "") + op.register.name
op.prefix if op.prefix != None else "" + op.name
for op in chain(
instruction_form.semantic_operands.destination,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["destination"],
instruction_form.semantic_operands["src_dst"],
)
if "register" in op
if isinstance(op, RegisterOperand)
]
isa_data = self._isa_model.get_instruction(
instruction_form.instruction, instruction_form.operands
@@ -243,7 +199,7 @@ class ISASemantics(object):
operand_state = {} # e.g., {'op1': {'name': 'rax', 'value': 0}} 0 means unchanged
for o in instruction_form.operands:
if "pre_indexed" in o.get("memory", {}):
if isinstance(o, MemoryOperand) and o.pre_indexed:
# Assuming no isa_data.operation
if isa_data is not None and isa_data.get("operation", None) is not None:
raise ValueError(
@@ -340,20 +296,20 @@ class ISASemantics(object):
def _has_load(self, instruction_form):
"""Check if instruction form performs a LOAD"""
for operand in chain(
instruction_form.semantic_operands.source,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["source"],
instruction_form.semantic_operands["src_dst"],
):
if operand.name == "memory":
if isinstance(operand, MemoryOperand):
return True
return False
def _has_store(self, instruction_form):
"""Check if instruction form perfroms a STORE"""
for operand in chain(
instruction_form.semantic_operands.destination,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["destination"],
instruction_form.semantic_operands["src_dst"],
):
if "memory" in operand:
if isinstance(operand, MemoryOperand):
return True
return False
@@ -386,7 +342,9 @@ class ISASemantics(object):
def substitute_mem_address(self, operands):
"""Create memory wildcard for all memory operands"""
return [self._create_reg_wildcard() if "memory" in op else op for op in operands]
return [
self._create_reg_wildcard() if isinstance(op, MemoryOperand) else op for op in operands
]
def _create_reg_wildcard(self):
"""Wildcard constructor"""

View File

@@ -9,6 +9,8 @@ from multiprocessing import Manager, Process, cpu_count
import networkx as nx
from osaca.semantics import INSTR_FLAGS, ArchSemantics, MachineModel
from osaca.parser.memory import MemoryOperand
from osaca.parser.register import RegisterOperand
class KernelDG(nx.DiGraph):
@@ -60,8 +62,7 @@ class KernelDG(nx.DiGraph):
dg = nx.DiGraph()
for i, instruction_form in enumerate(kernel):
dg.add_node(instruction_form.line_number)
print(dg.nodes[instruction_form.line_number])
dg.nodes[instruction_form.line_number].instruction_form = instruction_form
dg.nodes[instruction_form.line_number]["instruction_form"] = instruction_form
# add load as separate node if existent
if (
INSTR_FLAGS.HAS_LD in instruction_form.flags
@@ -271,8 +272,8 @@ class KernelDG(nx.DiGraph):
if instruction_form.semantic_operands is None:
return
for dst in chain(
instruction_form.semantic_operands.destination,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["destination"],
instruction_form.semantic_operands["src_dst"],
):
# TODO instructions before must be considered as well, if they update registers
# not used by insruction_form. E.g., validation/build/A64FX/gcc/O1/gs-2d-5pt.marked.s
@@ -281,27 +282,32 @@ class KernelDG(nx.DiGraph):
for i, instr_form in enumerate(instructions):
self._update_reg_changes(instr_form, register_changes)
# print(" TO", instr_form.line, register_changes)
if "register" in dst:
if isinstance(dst, RegisterOperand):
# read of register
if self.is_read(dst.register, instr_form):
if self.is_read(dst, instr_form):
if dst.get("pre_indexed", False) or dst.get("post_indexed", False):
yield instr_form, ["p_indexed"]
else:
yield instr_form, []
# write to register -> abort
if self.is_written(dst.register, instr_form):
if self.is_written(dst, instr_form):
break
if "flag" in dst and flag_dependencies:
if (
not isinstance(dst, RegisterOperand)
and not isinstance(dst, MemoryOperandOperand)
and "flag" in dst
and flag_dependencies
):
# read of flag
if self.is_read(dst.flag, instr_form):
yield instr_form, []
# write to flag -> abort
if self.is_written(dst.flag, instr_form):
break
if "memory" in dst:
if isinstance(dst, MemoryOperand):
# base register is altered during memory access
if "pre_indexed" in dst.memory:
if self.is_written(dst.memory.base, instr_form):
if dist.pre_indexed != None:
if self.is_written(dst.base, instr_form):
break
# if dst.memory.base:
# if self.is_read(dst.memory.base, instr_form):
@@ -309,18 +315,18 @@ class KernelDG(nx.DiGraph):
# if dst.memory.index:
# if self.is_read(dst.memory.index, instr_form):
# yield instr_form, []
if "post_indexed" in dst.memory:
if dst.post_indexed:
# Check for read of base register until overwrite
if self.is_written(dst.memory.base, instr_form):
if self.is_written(dst.base, instr_form):
break
# TODO record register changes
# (e.g., mov, leaadd, sub, inc, dec) in instructions[:i]
# and pass to is_memload and is_memstore to consider relevance.
# load from same location (presumed)
if self.is_memload(dst.memory, instr_form, register_changes):
if self.is_memload(dst, instr_form, register_changes):
yield instr_form, ["storeload_dep"]
# store to same location (presumed)
if self.is_memstore(dst.memory, instr_form, register_changes):
if self.is_memstore(dst, instr_form, register_changes):
break
self._update_reg_changes(instr_form, register_changes, only_postindexed=True)
@@ -364,32 +370,32 @@ class KernelDG(nx.DiGraph):
if instruction_form.semantic_operands is None:
return is_read
for src in chain(
instruction_form.semantic_operands.source,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["source"],
instruction_form.semantic_operands["src_dst"],
):
if "register" in src:
is_read = self.parser.is_reg_dependend_of(register, src.register) or is_read
if "flag" in src:
if isinstance(src, RegisterOperand):
is_read = self.parser.is_reg_dependend_of(register, src) or is_read
if (
not isinstance(src, RegisterOperand)
and not isinstance(src, MemoryOperand)
and "flag" in src
):
is_read = self.parser.is_flag_dependend_of(register, src.flag) or is_read
if "memory" in src:
if src.memory.base is not None:
is_read = self.parser.is_reg_dependend_of(register, src.memory.base) or is_read
if src.memory.index is not None:
is_read = (
self.parser.is_reg_dependend_of(register, src.memory.index) or is_read
)
if isinstance(src, MemoryOperand):
if src.base is not None:
is_read = self.parser.is_reg_dependend_of(register, src.base) or is_read
if src.index is not None:
is_read = self.parser.is_reg_dependend_of(register, src.index) or is_read
# Check also if read in destination memory address
for dst in chain(
instruction_form.semantic_operands.destination,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["destination"],
instruction_form.semantic_operands["src_dst"],
):
if "memory" in dst:
if dst.memory.base is not None:
is_read = self.parser.is_reg_dependend_of(register, dst.memory.base) or is_read
if dst.memory.index is not None:
is_read = (
self.parser.is_reg_dependend_of(register, dst.memory.index) or is_read
)
if isinstance(dst, MemoryOperand):
if dst.base is not None:
is_read = self.parser.is_reg_dependend_of(register, dst.base) or is_read
if dst.index is not None:
is_read = self.parser.is_reg_dependend_of(register, dst.index) or is_read
return is_read
def is_memload(self, mem, instruction_form, register_changes={}):
@@ -455,28 +461,28 @@ class KernelDG(nx.DiGraph):
if instruction_form.semantic_operands is None:
return is_written
for dst in chain(
instruction_form.semantic_operands.destination,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["destination"],
instruction_form.semantic_operands["src_dst"],
):
if "register" in dst:
is_written = self.parser.is_reg_dependend_of(register, dst.register) or is_written
if "flag" in dst:
if isinstance(dst, RegisterOperand):
is_written = self.parser.is_reg_dependend_of(register, dst) or is_written
if (
not isinstance(dst, RegisterOperand)
and not isinstance(dst, MemoryOperand)
and "flag" in dst
):
is_written = self.parser.is_flag_dependend_of(register, dst.flag) or is_written
if "memory" in dst:
if "pre_indexed" in dst.memory or "post_indexed" in dst.memory:
is_written = (
self.parser.is_reg_dependend_of(register, dst.memory.base) or is_written
)
if isinstance(dst, MemoryOperand):
if dst.pre_indexed or dst.post_indexed:
is_written = self.parser.is_reg_dependend_of(register, dst.base) or is_written
# Check also for possible pre- or post-indexing in memory addresses
for src in chain(
instruction_form.semantic_operands.source,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["source"],
instruction_form.semantic_operands["src_dst"],
):
if "memory" in src:
if "pre_indexed" in src.memory or "post_indexed" in src.memory:
is_written = (
self.parser.is_reg_dependend_of(register, src.memory.base) or is_written
)
if isinstance(src, MemoryOperand):
if src.pre_indexed or src.post_indexed:
is_written = self.parser.is_reg_dependend_of(register, src.base) or is_written
return is_written
def is_memstore(self, mem, instruction_form, register_changes={}):
@@ -485,10 +491,10 @@ class KernelDG(nx.DiGraph):
if instruction_form.semantic_operands is None:
return is_store
for dst in chain(
instruction_form.semantic_operands.destination,
instruction_form.semantic_operands.src_dst,
instruction_form.semantic_operands["destination"],
instruction_form.semantic_operands["src_dst"],
):
if "memory" in dst:
if isinstance(dst, MemoryOperand):
is_store = mem == dst["memory"] or is_store
return is_store

View File

@@ -150,7 +150,7 @@ def find_marked_section(
"immediate" in source
and parser.normalize_imd(source.immediate) == mov_vals[0]
and "register" in destination
and parser.get_full_reg_name(destination['register']) == mov_reg
and parser.get_full_reg_name(destination["register"]) == mov_reg
):
# operands of first instruction match start, check for second one
match, line_count = match_bytes(lines, i + 1, nop_bytes)
@@ -161,7 +161,7 @@ def find_marked_section(
"immediate" in source
and parser.normalize_imd(source.immediate) == mov_vals[1]
and "register" in destination
and parser.get_full_reg_name(destination['register']) == mov_reg
and parser.get_full_reg_name(destination["register"]) == mov_reg
):
# operand of first instruction match end, check for second one
match, line_count = match_bytes(lines, i + 1, nop_bytes)
@@ -169,7 +169,8 @@ def find_marked_section(
# return line of the marker
index_end = i
except TypeError:
print(i, line)
pass
# print("TESTER",i, line)
if index_start != -1 and index_end != -1:
break
return index_start, index_end

View File

@@ -256,38 +256,38 @@ class TestSemanticTools(unittest.TestCase):
def test_src_dst_assignment_x86(self):
for instruction_form in self.kernel_x86:
with self.subTest(instruction_form=instruction_form):
if instruction_form["semantic_operands"] is not None:
self.assertTrue("source" in instruction_form["semantic_operands"])
self.assertTrue("destination" in instruction_form["semantic_operands"])
self.assertTrue("src_dst" in instruction_form["semantic_operands"])
if instruction_form.semantic_operands is not None:
self.assertTrue("source" in instruction_form.semantic_operands)
self.assertTrue("destination" in instruction_form.semantic_operands)
self.assertTrue("src_dst" in instruction_form.semantic_operands)
def test_src_dst_assignment_AArch64(self):
for instruction_form in self.kernel_AArch64:
with self.subTest(instruction_form=instruction_form):
if instruction_form["semantic_operands"] is not None:
self.assertTrue("source" in instruction_form["semantic_operands"])
self.assertTrue("destination" in instruction_form["semantic_operands"])
self.assertTrue("src_dst" in instruction_form["semantic_operands"])
if instruction_form.semantic_operands is not None:
self.assertTrue("source" in instruction_form.semantic_operands)
self.assertTrue("destination" in instruction_form.semantic_operands)
self.assertTrue("src_dst" in instruction_form.semantic_operands)
def test_tp_lt_assignment_x86(self):
self.assertTrue("ports" in self.machine_model_csx)
port_num = len(self.machine_model_csx["ports"])
for instruction_form in self.kernel_x86:
with self.subTest(instruction_form=instruction_form):
self.assertTrue("throughput" in instruction_form)
self.assertTrue("latency" in instruction_form)
self.assertIsInstance(instruction_form["port_pressure"], list)
self.assertEqual(len(instruction_form["port_pressure"]), port_num)
self.assertTrue(instruction_form.throughput != None)
self.assertTrue(instruction_form.latency != None)
self.assertIsInstance(instruction_form.port_pressure, list)
self.assertEqual(len(instruction_form.port_pressure), port_num)
def test_tp_lt_assignment_AArch64(self):
self.assertTrue("ports" in self.machine_model_tx2)
port_num = len(self.machine_model_tx2["ports"])
for instruction_form in self.kernel_AArch64:
with self.subTest(instruction_form=instruction_form):
self.assertTrue("throughput" in instruction_form)
self.assertTrue("latency" in instruction_form)
self.assertIsInstance(instruction_form["port_pressure"], list)
self.assertEqual(len(instruction_form["port_pressure"]), port_num)
self.assertTrue(instruction_form.throughput != None)
self.assertTrue(instruction_form.latency != None)
self.assertIsInstance(instruction_form.port_pressure, list)
self.assertEqual(len(instruction_form.port_pressure), port_num)
def test_optimal_throughput_assignment(self):
# x86