mirror of
https://github.com/RRZE-HPC/OSACA.git
synced 2026-01-04 18:20:09 +01:00
Merge branch 'master' into feat/spr
This commit is contained in:
603
osaca/semantics/hw_model.py
Executable file → Normal file
603
osaca/semantics/hw_model.py
Executable file → Normal file
@@ -6,13 +6,21 @@ import pickle
|
||||
import re
|
||||
import string
|
||||
from collections import defaultdict
|
||||
from copy import deepcopy
|
||||
from itertools import product
|
||||
from pathlib import Path
|
||||
|
||||
import ruamel.yaml
|
||||
from osaca import __version__, utils
|
||||
from osaca.parser import ParserX86ATT
|
||||
from osaca.parser.instruction_form import InstructionForm
|
||||
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
|
||||
from osaca.parser.condition import ConditionOperand
|
||||
from osaca.parser.flag import FlagOperand
|
||||
from osaca.parser.prefetch import PrefetchOperand
|
||||
from ruamel.yaml.compat import StringIO
|
||||
|
||||
|
||||
@@ -41,7 +49,6 @@ class MachineModel(object):
|
||||
"index": i,
|
||||
"offset": o,
|
||||
"scale": s,
|
||||
"port_pressure": [],
|
||||
}
|
||||
for b, i, o, s in product(["gpr"], ["gpr", None], ["imd", None], [1, 8])
|
||||
],
|
||||
@@ -96,11 +103,88 @@ class MachineModel(object):
|
||||
self._data["instruction_forms"].remove(entry)
|
||||
# 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"]:
|
||||
iform["name"] = iform["name"].upper()
|
||||
self._data["instruction_forms_dict"][iform["name"]].append(iform)
|
||||
if iform["operands"] != []:
|
||||
new_operands = []
|
||||
# Change operand types from dicts to classes
|
||||
for o in iform["operands"]:
|
||||
self.operand_to_class(o, new_operands)
|
||||
iform["operands"] = new_operands
|
||||
# Do the same for hidden operands
|
||||
if "hidden_operands" in iform:
|
||||
new_operands = []
|
||||
# Change operand types from dicts to classes
|
||||
for o in iform["hidden_operands"]:
|
||||
self.operand_to_class(o, new_operands)
|
||||
iform["hidden_operands"] = new_operands
|
||||
|
||||
# Change dict iform style to class style
|
||||
new_iform = InstructionForm(
|
||||
mnemonic=iform["name"].upper() if "name" in iform else None,
|
||||
operands=iform["operands"] if "operands" in iform else [],
|
||||
hidden_operands=(
|
||||
iform["hidden_operands"] if "hidden_operands" in iform else []
|
||||
),
|
||||
directive_id=iform["directive"] if "directive" in iform else None,
|
||||
comment_id=iform["comment"] if "comment" in iform else None,
|
||||
line=iform["line"] if "line" in iform else None,
|
||||
line_number=iform["line_number"] if "line_number" in iform else None,
|
||||
latency=iform["latency"] if "latency" in iform else None,
|
||||
throughput=iform["throughput"] if "throughput" in iform else None,
|
||||
uops=iform["uops"] if "uops" in iform else None,
|
||||
port_pressure=iform["port_pressure"] if "port_pressure" in iform else None,
|
||||
operation=iform["operation"] if "operation" in iform else None,
|
||||
breaks_dependency_on_equal_operands=(
|
||||
iform["breaks_dependency_on_equal_operands"]
|
||||
if "breaks_dependency_on_equal_operands" in iform
|
||||
else False
|
||||
),
|
||||
semantic_operands=(
|
||||
iform["semantic_operands"]
|
||||
if "semantic_operands" in iform
|
||||
else {"source": [], "destination": [], "src_dst": []}
|
||||
),
|
||||
)
|
||||
# List containing classes with same name/instruction
|
||||
self._data["instruction_forms_dict"][iform["name"]].append(new_iform)
|
||||
self._data["internal_version"] = self.INTERNAL_VERSION
|
||||
|
||||
# Convert load and store throughput memory operands to classes
|
||||
new_throughputs = []
|
||||
if "load_throughput" in self._data:
|
||||
for m in self._data["load_throughput"]:
|
||||
new_throughputs.append(
|
||||
(
|
||||
MemoryOperand(
|
||||
base=m["base"],
|
||||
offset=m["offset"],
|
||||
scale=m["scale"],
|
||||
index=m["index"],
|
||||
dst=m["dst"] if "dst" in m else None,
|
||||
),
|
||||
m["port_pressure"],
|
||||
)
|
||||
)
|
||||
self._data["load_throughput"] = new_throughputs
|
||||
|
||||
new_throughputs = []
|
||||
if "store_throughput" in self._data:
|
||||
for m in self._data["store_throughput"]:
|
||||
new_throughputs.append(
|
||||
(
|
||||
MemoryOperand(
|
||||
base=m["base"],
|
||||
offset=m["offset"],
|
||||
scale=m["scale"],
|
||||
index=m["index"],
|
||||
),
|
||||
m["port_pressure"],
|
||||
)
|
||||
)
|
||||
self._data["store_throughput"] = new_throughputs
|
||||
|
||||
if not lazy:
|
||||
# cache internal representation for future use
|
||||
self._write_in_cache(self._path)
|
||||
@@ -108,6 +192,84 @@ class MachineModel(object):
|
||||
if not lazy:
|
||||
MachineModel._runtime_cache[self._path] = self._data
|
||||
|
||||
def operand_to_class(self, o, new_operands):
|
||||
"""Convert an operand from dict type to class"""
|
||||
if o["class"] == "register":
|
||||
new_operands.append(
|
||||
RegisterOperand(
|
||||
name=o["name"] if "name" in o else None,
|
||||
prefix=o["prefix"] if "prefix" in o else None,
|
||||
shape=o["shape"] if "shape" in o else None,
|
||||
mask=o["mask"] if "mask" in o else False,
|
||||
pre_indexed=o["pre_indexed"] if "pre_indexed" in o else False,
|
||||
post_indexed=o["post_indexed"] if "post_indexed" in o else False,
|
||||
source=o["source"] if "source" in o else False,
|
||||
destination=o["destination"] if "destination" in o else False,
|
||||
)
|
||||
)
|
||||
elif o["class"] == "memory":
|
||||
if isinstance(o["base"], dict):
|
||||
o["base"] = RegisterOperand(name=o["base"]["name"])
|
||||
if isinstance(o["index"], dict):
|
||||
o["index"] = RegisterOperand(
|
||||
name=o["index"]["name"],
|
||||
prefix=o["index"]["prefix"] if "prefix" in o["index"] else None,
|
||||
)
|
||||
new_operands.append(
|
||||
MemoryOperand(
|
||||
base=o["base"],
|
||||
offset=o["offset"],
|
||||
index=o["index"],
|
||||
scale=o["scale"],
|
||||
source=o["source"] if "source" in o else False,
|
||||
destination=o["destination"] if "destination" in o else False,
|
||||
pre_indexed=o["pre_indexed"] if "pre_indexed" in o else False,
|
||||
post_indexed=o["post_indexed"] if "post_indexed" in o else False,
|
||||
)
|
||||
)
|
||||
elif o["class"] == "immediate":
|
||||
new_operands.append(
|
||||
ImmediateOperand(
|
||||
imd_type=o["imd"],
|
||||
source=o["source"] if "source" in o else False,
|
||||
destination=o["destination"] if "destination" in o else False,
|
||||
)
|
||||
)
|
||||
elif o["class"] == "identifier":
|
||||
new_operands.append(
|
||||
IdentifierOperand(
|
||||
name=o["name"] if "name" in o else None,
|
||||
source=o["source"] if "source" in o else False,
|
||||
destination=o["destination"] if "destination" in o else False,
|
||||
)
|
||||
)
|
||||
elif o["class"] == "condition":
|
||||
new_operands.append(
|
||||
ConditionOperand(
|
||||
ccode=o["ccode"].upper(),
|
||||
source=o["source"] if "source" in o else False,
|
||||
destination=o["destination"] if "destination" in o else False,
|
||||
)
|
||||
)
|
||||
elif o["class"] == "flag":
|
||||
new_operands.append(
|
||||
FlagOperand(
|
||||
name=o["name"],
|
||||
source=o["source"] if "source" in o else False,
|
||||
destination=o["destination"] if "destination" in o else False,
|
||||
)
|
||||
)
|
||||
elif o["class"] == "prfop":
|
||||
new_operands.append(
|
||||
PrefetchOperand(
|
||||
type_id=o["type"] if "type" in o else None,
|
||||
target=o["target"] if "target" in o else None,
|
||||
policy=o["policy"] if "policy" in o else None,
|
||||
)
|
||||
)
|
||||
else:
|
||||
new_operands.append(o)
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""Return config entry for key or default/None."""
|
||||
return self._data.get(key, default)
|
||||
@@ -128,12 +290,13 @@ class MachineModel(object):
|
||||
if name is None:
|
||||
return None
|
||||
name_matched_iforms = self._data["instruction_forms_dict"].get(name.upper(), [])
|
||||
|
||||
try:
|
||||
return next(
|
||||
instruction_form
|
||||
for instruction_form in name_matched_iforms
|
||||
if self._match_operands(
|
||||
instruction_form["operands"] if "operands" in instruction_form else [],
|
||||
instruction_form.operands,
|
||||
operands,
|
||||
)
|
||||
)
|
||||
@@ -162,7 +325,7 @@ class MachineModel(object):
|
||||
|
||||
def set_instruction(
|
||||
self,
|
||||
name,
|
||||
mnemonic,
|
||||
operands=None,
|
||||
latency=None,
|
||||
port_pressure=None,
|
||||
@@ -171,28 +334,30 @@ class MachineModel(object):
|
||||
):
|
||||
"""Import instruction form information."""
|
||||
# If it already exists. Overwrite information.
|
||||
instr_data = self.get_instruction(name, operands)
|
||||
instr_data = self.get_instruction(mnemonic, operands)
|
||||
if instr_data is None:
|
||||
instr_data = {}
|
||||
instr_data = InstructionForm()
|
||||
self._data["instruction_forms"].append(instr_data)
|
||||
self._data["instruction_forms_dict"][name].append(instr_data)
|
||||
self._data["instruction_forms_dict"][mnemonic].append(instr_data)
|
||||
|
||||
instr_data["name"] = name
|
||||
instr_data["operands"] = operands
|
||||
instr_data["latency"] = latency
|
||||
instr_data["port_pressure"] = port_pressure
|
||||
instr_data["throughput"] = throughput
|
||||
instr_data["uops"] = uops
|
||||
instr_data.mnemonic = mnemonic
|
||||
instr_data.operands = operands
|
||||
instr_data.latency = latency
|
||||
instr_data.port_pressure = port_pressure
|
||||
instr_data.throughput = throughput
|
||||
instr_data.uops = uops
|
||||
|
||||
def set_instruction_entry(self, entry):
|
||||
"""Import instruction as entry object form information."""
|
||||
if entry.mnemonic is None and entry.operands == []:
|
||||
raise KeyError
|
||||
self.set_instruction(
|
||||
entry["name"],
|
||||
entry["operands"] if "operands" in entry else None,
|
||||
entry["latency"] if "latency" in entry else None,
|
||||
entry["port_pressure"] if "port_pressure" in entry else None,
|
||||
entry["throughput"] if "throughput" in entry else None,
|
||||
entry["uops"] if "uops" in entry else None,
|
||||
entry.mnemonic,
|
||||
entry.operands,
|
||||
entry.latency,
|
||||
entry.port_pressure,
|
||||
entry.throughput,
|
||||
entry.uops,
|
||||
)
|
||||
|
||||
def add_port(self, port):
|
||||
@@ -224,10 +389,10 @@ class MachineModel(object):
|
||||
|
||||
def get_load_throughput(self, memory):
|
||||
"""Return load thorughput for given register type."""
|
||||
ld_tp = [m for m in self._data["load_throughput"] if self._match_mem_entries(memory, m)]
|
||||
ld_tp = [m for m in self._data["load_throughput"] if self._match_mem_entries(memory, m[0])]
|
||||
if len(ld_tp) > 0:
|
||||
return ld_tp.copy()
|
||||
return [{"port_pressure": self._data["load_throughput_default"].copy()}]
|
||||
return [(memory, self._data["load_throughput_default"].copy())]
|
||||
|
||||
def get_store_latency(self, reg_type):
|
||||
"""Return store latency for given register type."""
|
||||
@@ -236,16 +401,19 @@ class MachineModel(object):
|
||||
|
||||
def get_store_throughput(self, memory, src_reg=None):
|
||||
"""Return store throughput for a given destination and register type."""
|
||||
st_tp = [m for m in self._data["store_throughput"] if self._match_mem_entries(memory, m)]
|
||||
st_tp = [
|
||||
m for m in self._data["store_throughput"] if self._match_mem_entries(memory, m[0])
|
||||
]
|
||||
if src_reg is not None:
|
||||
st_tp = [
|
||||
tp
|
||||
for tp in st_tp
|
||||
if "src" in tp and self._check_operands(src_reg, {"register": {"name": tp["src"]}})
|
||||
if "src" in tp[0]
|
||||
and self._check_operands(src_reg, RegisterOperand(name=tp[0]["src"]))
|
||||
]
|
||||
if len(st_tp) > 0:
|
||||
return st_tp.copy()
|
||||
return [{"port_pressure": self._data["store_throughput_default"].copy()}]
|
||||
return [(memory, self._data["store_throughput_default"].copy())]
|
||||
|
||||
def _match_mem_entries(self, mem, i_mem):
|
||||
"""Check if memory addressing ``mem`` and ``i_mem`` are of the same type."""
|
||||
@@ -260,18 +428,6 @@ class MachineModel(object):
|
||||
data_ports = [x for x in filter(data_port.match, self._data["ports"])]
|
||||
return data_ports
|
||||
|
||||
@staticmethod
|
||||
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"]:
|
||||
op_attrs = [
|
||||
y + ":" + str(op[y])
|
||||
for y in list(filter(lambda x: True if x != "class" else False, op))
|
||||
]
|
||||
operands.append("{}({})".format(op["class"], ",".join(op_attrs)))
|
||||
return "{} {}".format(instruction_form["name"].lower(), ",".join(operands))
|
||||
|
||||
@staticmethod
|
||||
def get_isa_for_arch(arch):
|
||||
"""Return ISA for given micro-arch ``arch``."""
|
||||
@@ -311,23 +467,75 @@ class MachineModel(object):
|
||||
else:
|
||||
raise ValueError("Unknown architecture {!r}.".format(arch))
|
||||
|
||||
def class_to_dict(self, op):
|
||||
"""Need to convert operand classes to dicts for the dump. Memory operand types may have their index/base/offset as a register operand/"""
|
||||
if isinstance(op, Operand):
|
||||
dict_op = dict(
|
||||
(key.lstrip("_"), value)
|
||||
for key, value in op.__dict__.items()
|
||||
if not callable(value) and not key.startswith("__")
|
||||
)
|
||||
if isinstance(op, MemoryOperand):
|
||||
if isinstance(dict_op["index"], Operand):
|
||||
dict_op["index"] = dict(
|
||||
(key.lstrip("_"), value)
|
||||
for key, value in dict_op["index"].__dict__.items()
|
||||
if not callable(value) and not key.startswith("__")
|
||||
)
|
||||
if isinstance(dict_op["offset"], Operand):
|
||||
dict_op["offset"] = dict(
|
||||
(key.lstrip("_"), value)
|
||||
for key, value in dict_op["offset"].__dict__.items()
|
||||
if not callable(value) and not key.startswith("__")
|
||||
)
|
||||
if isinstance(dict_op["base"], Operand):
|
||||
dict_op["base"] = dict(
|
||||
(key.lstrip("_"), value)
|
||||
for key, value in dict_op["base"].__dict__.items()
|
||||
if not callable(value) and not key.startswith("__")
|
||||
)
|
||||
return dict_op
|
||||
return op
|
||||
|
||||
def dump(self, stream=None):
|
||||
"""Dump machine model to stream or return it as a ``str`` if no stream is given."""
|
||||
# Replace instruction form's port_pressure with styled version for RoundtripDumper
|
||||
formatted_instruction_forms = deepcopy(self._data["instruction_forms"])
|
||||
for instruction_form in formatted_instruction_forms:
|
||||
formatted_instruction_forms = []
|
||||
for instruction_form in self._data["instruction_forms"]:
|
||||
if isinstance(instruction_form, InstructionForm):
|
||||
instruction_form = dict(
|
||||
(key.lstrip("_"), value)
|
||||
for key, value in instruction_form.__dict__.items()
|
||||
if not callable(value) and not key.startswith("__")
|
||||
)
|
||||
if instruction_form["port_pressure"] is not None:
|
||||
cs = ruamel.yaml.comments.CommentedSeq(instruction_form["port_pressure"])
|
||||
cs.fa.set_flow_style()
|
||||
instruction_form["port_pressure"] = cs
|
||||
dict_operands = []
|
||||
for op in instruction_form["operands"]:
|
||||
dict_operands.append(self.class_to_dict(op))
|
||||
instruction_form["operands"] = dict_operands
|
||||
formatted_instruction_forms.append(instruction_form)
|
||||
|
||||
# Replace load_throughput with styled version for RoundtripDumper
|
||||
formatted_load_throughput = []
|
||||
for lt in self._data["load_throughput"]:
|
||||
cm = ruamel.yaml.comments.CommentedMap(lt)
|
||||
cm = self.class_to_dict(lt[0])
|
||||
cm["port_pressure"] = lt[1]
|
||||
cm = ruamel.yaml.comments.CommentedMap(cm)
|
||||
cm.fa.set_flow_style()
|
||||
formatted_load_throughput.append(cm)
|
||||
|
||||
# Replace store_throughput with styled version for RoundtripDumper
|
||||
formatted_store_throughput = []
|
||||
for st in self._data["store_throughput"]:
|
||||
cm = self.class_to_dict(st[0])
|
||||
cm["port_pressure"] = st[1]
|
||||
cm = ruamel.yaml.comments.CommentedMap(cm)
|
||||
cm.fa.set_flow_style()
|
||||
formatted_store_throughput.append(cm)
|
||||
|
||||
# Create YAML object
|
||||
yaml = self._create_yaml_object()
|
||||
if not stream:
|
||||
@@ -342,12 +550,15 @@ class MachineModel(object):
|
||||
"instruction_forms",
|
||||
"instruction_forms_dict",
|
||||
"load_throughput",
|
||||
"store_throughput",
|
||||
"internal_version",
|
||||
]
|
||||
},
|
||||
stream,
|
||||
)
|
||||
|
||||
yaml.dump({"load_throughput": formatted_load_throughput}, stream)
|
||||
yaml.dump({"store_throughput": formatted_store_throughput}, stream)
|
||||
yaml.dump({"instruction_forms": formatted_instruction_forms}, stream)
|
||||
|
||||
if isinstance(stream, StringIO):
|
||||
@@ -449,48 +660,46 @@ class MachineModel(object):
|
||||
operand_string += (
|
||||
"s" if operand["scale"] == self.WILDCARD or operand["scale"] > 1 else ""
|
||||
)
|
||||
if "pre-indexed" in operand:
|
||||
operand_string += "r" if operand["pre-indexed"] else ""
|
||||
operand_string += "p" if operand["post-indexed"] else ""
|
||||
if "pre_indexed" in operand:
|
||||
operand_string += "r" if operand["pre_indexed"] else ""
|
||||
operand_string += "p" if operand["post_indexed"] else ""
|
||||
return operand_string
|
||||
|
||||
def _create_db_operand_aarch64(self, operand):
|
||||
"""Create instruction form operand for DB out of operand string."""
|
||||
if operand == "i":
|
||||
return {"class": "immediate", "imd": "int"}
|
||||
return ImmediateOperand(imd_type="int")
|
||||
elif operand in "wxbhsdq":
|
||||
return {"class": "register", "prefix": operand}
|
||||
return RegisterOperand(prefix=operand)
|
||||
elif operand.startswith("v"):
|
||||
return {"class": "register", "prefix": "v", "shape": operand[1:2]}
|
||||
return RegisterOperand(prefix="v", shape=operand[1:2])
|
||||
elif operand.startswith("m"):
|
||||
return {
|
||||
"class": "memory",
|
||||
"base": "x" if "b" in operand else None,
|
||||
"offset": "imd" if "o" in operand else None,
|
||||
"index": "gpr" if "i" in operand else None,
|
||||
"scale": 8 if "s" in operand else 1,
|
||||
"pre-indexed": True if "r" in operand else False,
|
||||
"post-indexed": True if "p" in operand else False,
|
||||
}
|
||||
return MemoryOperand(
|
||||
base="x" if "b" in operand else None,
|
||||
offset="imd" if "o" in operand else None,
|
||||
index="gpr" if "i" in operand else None,
|
||||
scale=8 if "s" in operand else 1,
|
||||
pre_indexed=True if "r" in operand else False,
|
||||
post_indexed=True if "p" in operand else False,
|
||||
)
|
||||
else:
|
||||
raise ValueError("Parameter {} is not a valid operand code".format(operand))
|
||||
|
||||
def _create_db_operand_x86(self, operand):
|
||||
"""Create instruction form operand for DB out of operand string."""
|
||||
if operand == "r":
|
||||
return {"class": "register", "name": "gpr"}
|
||||
return RegisterOperand(name="gpr")
|
||||
elif operand in "xyz":
|
||||
return {"class": "register", "name": operand + "mm"}
|
||||
return RegisterOperand(name=operand + "mm")
|
||||
elif operand == "i":
|
||||
return {"class": "immediate", "imd": "int"}
|
||||
return ImmediateOperand(imd_type="int")
|
||||
elif operand.startswith("m"):
|
||||
return {
|
||||
"class": "memory",
|
||||
"base": "gpr" if "b" in operand else None,
|
||||
"offset": "imd" if "o" in operand else None,
|
||||
"index": "gpr" if "i" in operand else None,
|
||||
"scale": 8 if "s" in operand else 1,
|
||||
}
|
||||
return MemoryOperand(
|
||||
base="gpr" if "b" in operand else None,
|
||||
offset="imd" if "o" in operand else None,
|
||||
index="gpr" if "i" in operand else None,
|
||||
scale=8 if "s" in operand else 1,
|
||||
)
|
||||
else:
|
||||
raise ValueError("Parameter {} is not a valid operand code".format(operand))
|
||||
|
||||
@@ -529,12 +738,8 @@ 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:
|
||||
if (
|
||||
"class" in i_operand
|
||||
and i_operand["class"] == "register"
|
||||
or "register" in i_operand
|
||||
):
|
||||
if isinstance(operand, dict) and self.WILDCARD in operand:
|
||||
if isinstance(i_operand, RegisterOperand):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -545,87 +750,87 @@ class MachineModel(object):
|
||||
|
||||
def _check_AArch64_operands(self, i_operand, operand):
|
||||
"""Check if the types of operand ``i_operand`` and ``operand`` match."""
|
||||
if "class" in operand:
|
||||
# compare two DB entries
|
||||
return self._compare_db_entries(i_operand, operand)
|
||||
# if "class" in operand:
|
||||
# compare two DB entries
|
||||
# return self._compare_db_entries(i_operand, operand)
|
||||
# TODO support class wildcards
|
||||
# register
|
||||
if "register" in operand:
|
||||
if i_operand["class"] != "register":
|
||||
if isinstance(operand, RegisterOperand):
|
||||
if not isinstance(i_operand, RegisterOperand):
|
||||
return False
|
||||
return self._is_AArch64_reg_type(i_operand, operand["register"])
|
||||
return self._is_AArch64_reg_type(i_operand, operand)
|
||||
# memory
|
||||
if "memory" in operand:
|
||||
if i_operand["class"] != "memory":
|
||||
if isinstance(operand, MemoryOperand):
|
||||
if not isinstance(i_operand, MemoryOperand):
|
||||
return False
|
||||
return self._is_AArch64_mem_type(i_operand, operand["memory"])
|
||||
return self._is_AArch64_mem_type(i_operand, operand)
|
||||
# immediate
|
||||
if i_operand["class"] == "immediate" and i_operand["imd"] == self.WILDCARD:
|
||||
return "value" in operand or (
|
||||
"immediate" in operand and "value" in operand["immediate"]
|
||||
if isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == self.WILDCARD:
|
||||
return isinstance(operand, ImmediateOperand) and (operand.value is not None)
|
||||
|
||||
if isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == "int":
|
||||
return (
|
||||
isinstance(operand, ImmediateOperand)
|
||||
and operand.imd_type == "int"
|
||||
and operand.value is not None
|
||||
)
|
||||
if i_operand["class"] == "immediate" and i_operand["imd"] == "int":
|
||||
return ("value" in operand and operand.get("type", None) == "int") or (
|
||||
"immediate" in operand
|
||||
and "value" in operand["immediate"]
|
||||
and operand["immediate"].get("type", None) == "int"
|
||||
|
||||
if isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == "float":
|
||||
return (
|
||||
isinstance(operand, ImmediateOperand)
|
||||
and operand.imd_type == "float"
|
||||
and operand.value is not None
|
||||
)
|
||||
if i_operand["class"] == "immediate" and i_operand["imd"] == "float":
|
||||
return ("float" in operand and operand.get("type", None) == "float") or (
|
||||
"immediate" in operand
|
||||
and "float" in operand["immediate"]
|
||||
and operand["immediate"].get("type", None) == "float"
|
||||
)
|
||||
if i_operand["class"] == "immediate" and i_operand["imd"] == "double":
|
||||
return ("double" in operand and operand.get("type", None) == "double") or (
|
||||
"immediate" in operand
|
||||
and "double" in operand["immediate"]
|
||||
and operand["immediate"].get("type", None) == "double"
|
||||
|
||||
if isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == "double":
|
||||
return (
|
||||
isinstance(operand, ImmediateOperand)
|
||||
and operand.imd_type == "double"
|
||||
and operand.value is not None
|
||||
)
|
||||
|
||||
# identifier
|
||||
if "identifier" in operand or (
|
||||
"immediate" in operand and "identifier" in operand["immediate"]
|
||||
if isinstance(operand, IdentifierOperand) or (
|
||||
isinstance(operand, ImmediateOperand) and operand.identifier is not None
|
||||
):
|
||||
return i_operand["class"] == "identifier"
|
||||
return isinstance(i_operand, IdentifierOperand)
|
||||
# prefetch option
|
||||
if "prfop" in operand:
|
||||
return i_operand["class"] == "prfop"
|
||||
if isinstance(operand, PrefetchOperand):
|
||||
return isinstance(i_operand, PrefetchOperand)
|
||||
# condition
|
||||
if "condition" in operand:
|
||||
if i_operand["class"] == "condition" and i_operand["ccode"] == self.WILDCARD:
|
||||
return True
|
||||
return i_operand["class"] == "condition" and (
|
||||
operand.get("condition", None) == i_operand.get("ccode", None).upper()
|
||||
if isinstance(i_operand.get("ccode", None), str)
|
||||
else i_operand.get("ccode", None)
|
||||
)
|
||||
if isinstance(operand, ConditionOperand):
|
||||
if isinstance(i_operand, ConditionOperand):
|
||||
return (i_operand.ccode == self.WILDCARD) or (i_operand.ccode == operand.ccode)
|
||||
# no match
|
||||
return False
|
||||
|
||||
def _check_x86_operands(self, i_operand, operand):
|
||||
"""Check if the types of operand ``i_operand`` and ``operand`` match."""
|
||||
if "class" in operand:
|
||||
# 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:
|
||||
if i_operand["class"] != "register":
|
||||
if isinstance(operand, RegisterOperand):
|
||||
if not isinstance(i_operand, RegisterOperand):
|
||||
return False
|
||||
return self._is_x86_reg_type(i_operand, operand["register"], consider_masking=False)
|
||||
return self._is_x86_reg_type(i_operand, operand, consider_masking=False)
|
||||
# memory
|
||||
if "memory" in operand:
|
||||
if i_operand["class"] != "memory":
|
||||
if isinstance(operand, MemoryOperand):
|
||||
if not isinstance(i_operand, MemoryOperand):
|
||||
return False
|
||||
return self._is_x86_mem_type(i_operand, operand["memory"])
|
||||
return self._is_x86_mem_type(i_operand, operand)
|
||||
# immediate
|
||||
if "immediate" in operand or "value" in operand:
|
||||
return i_operand["class"] == "immediate" and i_operand["imd"] == "int"
|
||||
if isinstance(operand, ImmediateOperand):
|
||||
# if "immediate" in operand.name or operand.value != None:
|
||||
return isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == "int"
|
||||
# identifier (e.g., labels)
|
||||
if "identifier" in operand:
|
||||
return i_operand["class"] == "identifier"
|
||||
if isinstance(operand, IdentifierOperand):
|
||||
return isinstance(i_operand, IdentifierOperand)
|
||||
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."""
|
||||
return True
|
||||
operand_attributes = list(
|
||||
filter(
|
||||
lambda x: True if x != "source" and x != "destination" else False,
|
||||
@@ -645,27 +850,26 @@ class MachineModel(object):
|
||||
def _is_AArch64_reg_type(self, i_reg, reg):
|
||||
"""Check if register type match."""
|
||||
# check for wildcards
|
||||
if reg["prefix"] == self.WILDCARD or i_reg["prefix"] == self.WILDCARD:
|
||||
if "shape" in reg:
|
||||
if "shape" in i_reg and (
|
||||
reg["shape"] == i_reg["shape"]
|
||||
or self.WILDCARD in (reg["shape"] + i_reg["shape"])
|
||||
if reg.prefix == self.WILDCARD or i_reg.prefix == self.WILDCARD:
|
||||
if reg.shape is not None:
|
||||
if i_reg.shape is not None and (
|
||||
reg.shape == i_reg.shape or self.WILDCARD in (reg.shape + i_reg.shape)
|
||||
):
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
# check for prefix and shape
|
||||
if reg["prefix"] != i_reg["prefix"]:
|
||||
if reg.prefix != i_reg.prefix:
|
||||
return False
|
||||
if "shape" in reg:
|
||||
if "shape" in i_reg and (
|
||||
reg["shape"] == i_reg["shape"] or self.WILDCARD in (reg["shape"] + i_reg["shape"])
|
||||
if reg.shape is not None:
|
||||
if i_reg.shape is not None and (
|
||||
reg.shape == i_reg.shape or self.WILDCARD in (reg.shape + i_reg.shape)
|
||||
):
|
||||
return True
|
||||
return False
|
||||
if "lanes" in reg:
|
||||
if "lanes" in i_reg and (
|
||||
reg["lanes"] == i_reg["lanes"] or self.WILDCARD in (reg["lanes"] + i_reg["lanes"])
|
||||
if reg.lanes is not None:
|
||||
if i_reg.lanes is not None and (
|
||||
reg.lanes == i_reg.lanes or self.WILDCARD in (reg.lanes + i_reg.lanes)
|
||||
):
|
||||
return True
|
||||
return False
|
||||
@@ -673,48 +877,52 @@ class MachineModel(object):
|
||||
|
||||
def _is_x86_reg_type(self, i_reg, reg, consider_masking=False):
|
||||
"""Check if register type match."""
|
||||
i_reg_name = i_reg["name"] if i_reg and "name" in i_reg else i_reg
|
||||
if reg is None:
|
||||
if i_reg is None:
|
||||
return True
|
||||
return False
|
||||
if isinstance(i_reg, RegisterOperand):
|
||||
i_reg_name = i_reg.name
|
||||
else:
|
||||
i_reg_name = i_reg
|
||||
# check for wildcards
|
||||
if i_reg_name == self.WILDCARD or reg["name"] == self.WILDCARD:
|
||||
if isinstance(reg, str):
|
||||
return False
|
||||
if i_reg_name is None and reg.name is None:
|
||||
return True
|
||||
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 is not None or i_reg.mask is not None:
|
||||
# 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 is not None
|
||||
and reg.mask.rstrip(string.digits).lower() == i_reg.mask
|
||||
)
|
||||
or reg.get("mask") == self.WILDCARD
|
||||
or i_reg.get("mask") == self.WILDCARD
|
||||
or reg.mask == self.WILDCARD
|
||||
or i_reg.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
|
||||
if (
|
||||
i_reg.get("zeroing") == self.WILDCARD
|
||||
or reg.get("zeroing") == self.WILDCARD
|
||||
):
|
||||
if i_reg.zeroing == self.WILDCARD or reg.zeroing == self.WILDCARD:
|
||||
zero_ok = True
|
||||
if not mask_ok or not zero_ok:
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
if reg["name"].rstrip(string.digits).lower() == i_reg_name:
|
||||
if reg.name.rstrip(string.digits).lower() == i_reg_name:
|
||||
return True
|
||||
if i_reg_name == "gpr":
|
||||
return True
|
||||
@@ -725,50 +933,48 @@ class MachineModel(object):
|
||||
if (
|
||||
# check base
|
||||
(
|
||||
(mem["base"] is None and i_mem["base"] is None)
|
||||
or i_mem["base"] == self.WILDCARD
|
||||
or mem["base"]["prefix"] == i_mem["base"]
|
||||
(mem.base is None and i_mem.base is None)
|
||||
or i_mem.base == self.WILDCARD
|
||||
or (isinstance(mem.base, RegisterOperand) and (mem.base.prefix == i_mem.base))
|
||||
)
|
||||
# check offset
|
||||
and (
|
||||
mem["offset"] == i_mem["offset"]
|
||||
or i_mem["offset"] == self.WILDCARD
|
||||
mem.offset == i_mem.offset
|
||||
or i_mem.offset == self.WILDCARD
|
||||
or (
|
||||
mem["offset"] is not None
|
||||
and "identifier" in mem["offset"]
|
||||
and i_mem["offset"] == "identifier"
|
||||
mem.offset is not None
|
||||
and isinstance(mem.offset, IdentifierOperand)
|
||||
and isinstance(i_mem.offset, IdentifierOperand)
|
||||
)
|
||||
or (
|
||||
mem["offset"] is not None
|
||||
and "value" in mem["offset"]
|
||||
and i_mem["offset"] == "imd"
|
||||
mem.offset is not None
|
||||
and isinstance(mem.offset, ImmediateOperand)
|
||||
and i_mem.offset == "imd"
|
||||
)
|
||||
)
|
||||
# check index
|
||||
and (
|
||||
mem["index"] == i_mem["index"]
|
||||
or i_mem["index"] == self.WILDCARD
|
||||
mem.index == i_mem.index
|
||||
or i_mem.index == self.WILDCARD
|
||||
or (
|
||||
mem["index"] is not None
|
||||
and "prefix" in mem["index"]
|
||||
and mem["index"]["prefix"] == i_mem["index"]
|
||||
mem.index is not None
|
||||
and mem.index.prefix is not None
|
||||
and mem.index.prefix == i_mem.index
|
||||
)
|
||||
)
|
||||
# check scale
|
||||
and (
|
||||
mem["scale"] == i_mem["scale"]
|
||||
or i_mem["scale"] == self.WILDCARD
|
||||
or (mem["scale"] != 1 and i_mem["scale"] != 1)
|
||||
mem.scale == i_mem.scale
|
||||
or i_mem.scale == self.WILDCARD
|
||||
or (mem.scale != 1 and i_mem.scale != 1)
|
||||
)
|
||||
# check pre-indexing
|
||||
and (
|
||||
i_mem["pre-indexed"] == self.WILDCARD
|
||||
or ("pre_indexed" in mem) == (i_mem["pre-indexed"])
|
||||
)
|
||||
and (i_mem.pre_indexed == self.WILDCARD or mem.pre_indexed == i_mem.pre_indexed)
|
||||
# check post-indexing
|
||||
and (
|
||||
i_mem["post-indexed"] == self.WILDCARD
|
||||
or ("post_indexed" in mem) == (i_mem["post-indexed"])
|
||||
i_mem.post_indexed == self.WILDCARD
|
||||
or mem.post_indexed == i_mem.post_indexed
|
||||
or (isinstance(mem.post_indexed, dict) and i_mem.post_indexed)
|
||||
)
|
||||
):
|
||||
return True
|
||||
@@ -779,48 +985,43 @@ class MachineModel(object):
|
||||
if (
|
||||
# check base
|
||||
(
|
||||
(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"])
|
||||
(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)
|
||||
)
|
||||
# check offset
|
||||
and (
|
||||
mem["offset"] == i_mem["offset"]
|
||||
or i_mem["offset"] == self.WILDCARD
|
||||
mem.offset == i_mem.offset
|
||||
or i_mem.offset == self.WILDCARD
|
||||
or (
|
||||
mem["offset"] is not None
|
||||
and "identifier" in mem["offset"]
|
||||
and i_mem["offset"] == "identifier"
|
||||
mem.offset is not None
|
||||
and isinstance(mem.offset, IdentifierOperand)
|
||||
and isinstance(i_mem.offset, IdentifierOperand)
|
||||
)
|
||||
or (
|
||||
mem["offset"] is not None
|
||||
and "value" in mem["offset"]
|
||||
mem.offset is not None
|
||||
and isinstance(mem.offset, ImmediateOperand)
|
||||
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"]
|
||||
and i_mem["offset"] == "id"
|
||||
)
|
||||
or (isinstance(mem.offset, IdentifierOperand) and i_mem.offset == "id")
|
||||
)
|
||||
# check index
|
||||
and (
|
||||
mem["index"] == i_mem["index"]
|
||||
or i_mem["index"] == self.WILDCARD
|
||||
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 mem.index.name != None
|
||||
and self._is_x86_reg_type(i_mem.index, mem.index)
|
||||
)
|
||||
)
|
||||
# check scale
|
||||
and (
|
||||
mem["scale"] == i_mem["scale"]
|
||||
or i_mem["scale"] == self.WILDCARD
|
||||
or (mem["scale"] != 1 and i_mem["scale"] != 1)
|
||||
mem.scale == i_mem.scale
|
||||
or i_mem.scale == self.WILDCARD
|
||||
or (mem.scale != 1 and i_mem.scale != 1)
|
||||
)
|
||||
):
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user