mirror of
https://github.com/RRZE-HPC/OSACA.git
synced 2026-01-07 03:30:06 +01:00
Added condition operand, adjusted tests to parse it & a few changes to get the kernelDG tests working
This commit is contained in:
@@ -11,9 +11,9 @@ import ruamel.yaml
|
||||
|
||||
from osaca.semantics import MachineModel
|
||||
from osaca.parser import instructionForm
|
||||
from osaca.parser.memory import memoryOperand
|
||||
from osaca.parser.register import registerOperand
|
||||
from osaca.parser.immediate import immediateOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.immediate import ImmediateOperand
|
||||
|
||||
|
||||
def sanity_check(arch: str, verbose=False, internet_check=False, output_file=sys.stdout):
|
||||
@@ -436,12 +436,12 @@ def _check_sanity_arch_db(arch_mm, isa_mm, internet_check=True):
|
||||
|
||||
# Check operands
|
||||
for operand in instr_form["operands"]:
|
||||
if isinstance(operand, registerOperand) and not (
|
||||
if isinstance(operand, RegisterOperand) and not (
|
||||
operand.name != None or operand.prefix != None
|
||||
):
|
||||
# Missing 'name' key
|
||||
bad_operand.append(instr_form)
|
||||
elif isinstance(operand, memoryOperand) and (
|
||||
elif isinstance(operand, MemoryOperand) and (
|
||||
operand.base is None
|
||||
or operand.offset is None
|
||||
or operand.index is None
|
||||
@@ -449,7 +449,7 @@ def _check_sanity_arch_db(arch_mm, isa_mm, internet_check=True):
|
||||
):
|
||||
# Missing at least one key necessary for memory operands
|
||||
bad_operand.append(instr_form)
|
||||
elif isinstance(operand, immediateOperand) and operand.type == None:
|
||||
elif isinstance(operand, ImmediateOperand) and operand.type == None:
|
||||
# Missing 'imd' key
|
||||
bad_operand.append(instr_form)
|
||||
# every entry exists twice --> uniquify
|
||||
@@ -611,7 +611,7 @@ 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"]:
|
||||
if isinstance(op, registerOperand):
|
||||
if isinstance(op, RegisterOperand):
|
||||
op_attrs = []
|
||||
if op.name != None:
|
||||
op_attrs.append("name:" + op.name)
|
||||
|
||||
22
osaca/parser/condition.py
Normal file
22
osaca/parser/condition.py
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from osaca.parser.operand import Operand
|
||||
|
||||
|
||||
class ConditionOperand(Operand):
|
||||
def __init__(
|
||||
self,
|
||||
ccode=None,
|
||||
source=False,
|
||||
destination=False,
|
||||
):
|
||||
super().__init__("condition", source, destination)
|
||||
self._ccode = ccode
|
||||
|
||||
@property
|
||||
def ccode(self):
|
||||
return self._ccode
|
||||
|
||||
@ccode.setter
|
||||
def ccode(self, ccode):
|
||||
self._ccode = ccode
|
||||
@@ -3,7 +3,7 @@
|
||||
from osaca.parser.operand import Operand
|
||||
|
||||
|
||||
class directiveOperand(Operand):
|
||||
class DirectiveOperand(Operand):
|
||||
def __init__(self, name_id=None, parameter_id=None, comment_id=None):
|
||||
super().__init__(name_id)
|
||||
self._parameter_id = parameter_id
|
||||
@@ -34,7 +34,7 @@ class directiveOperand(Operand):
|
||||
self._comment_id = comment
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, directiveOperand):
|
||||
if isinstance(other, DirectiveOperand):
|
||||
return (
|
||||
self._name_id == other._name_id
|
||||
and self._parameter_id == other._parameter_id
|
||||
@@ -48,4 +48,4 @@ class directiveOperand(Operand):
|
||||
return f"Directive(name_id={self._name_id}, parameters={self._parameter_id}, comment={self._comment_id})"
|
||||
|
||||
def __repr__(self):
|
||||
return f"directiveOperand(name_id={self._name_id}, parameters={self._parameter_id}, comment={self._comment_id})"
|
||||
return f"DirectiveOperand(name_id={self._name_id}, parameters={self._parameter_id}, comment={self._comment_id})"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from osaca.parser.operand import Operand
|
||||
|
||||
|
||||
class identifierOperand(Operand):
|
||||
class IdentifierOperand(Operand):
|
||||
def __init__(self, name=None, offset=None, relocation=None):
|
||||
super().__init__(name)
|
||||
self._offset = offset
|
||||
@@ -27,8 +27,8 @@ class identifierOperand(Operand):
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"identifierOperand({self.name}, offset={self.offset}, relocation={self.relocation})"
|
||||
f"IdentifierOperand({self.name}, offset={self.offset}, relocation={self.relocation})"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"identifierOperand(name={self.name}, offset={self.offset}, relocation={self.relocation})"
|
||||
return f"IdentifierOperand(name={self.name}, offset={self.offset}, relocation={self.relocation})"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from osaca.parser.operand import Operand
|
||||
|
||||
|
||||
class immediateOperand(Operand):
|
||||
class ImmediateOperand(Operand):
|
||||
def __init__(
|
||||
self,
|
||||
identifier_id=None,
|
||||
@@ -53,18 +53,18 @@ class immediateOperand(Operand):
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"immediateOperand(identifier_id={self._identifier_id}, type_id={self._type_id}, "
|
||||
f"ImmediateOperand(identifier_id={self._identifier_id}, type_id={self._type_id}, "
|
||||
f"value_id={self._value_id}, shift_id={self._shift_id})"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"immediateOperand(identifier_id={self._identifier_id}, type_id={self._type_id}, "
|
||||
f"ImmediateOperand(identifier_id={self._identifier_id}, type_id={self._type_id}, "
|
||||
f"value_id={self._value_id}, shift_id={self._shift_id})"
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, immediateOperand):
|
||||
if isinstance(other, ImmediateOperand):
|
||||
return (
|
||||
self._identifier_id == other._identifier_id
|
||||
and self._type_id == other._type_id
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from osaca.parser.directive import directiveOperand
|
||||
from osaca.parser.directive import DirectiveOperand
|
||||
|
||||
|
||||
class instructionForm:
|
||||
@@ -179,11 +179,28 @@ class instructionForm:
|
||||
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})"
|
||||
|
||||
def __str__(self):
|
||||
return f"Instruction: {self._instruction_id}\nOperands: {self._operands_id}\nDirective: {self._directive_id}\nComment: {self._comment_id}\nLabel: {self._label_id}\nLine: {self._line}\nLine Number: {self._line_number}\nSemantic Operands: {self._semantic_operands}\nFlags: {self._flags}"
|
||||
attributes = {
|
||||
"instruction_id": self.instruction,
|
||||
"operands_id": self.operands,
|
||||
"hidden_operands": self.hidden_operands,
|
||||
"directive_id": self.directive,
|
||||
"comment_id": self.comment,
|
||||
"label_id": self.label,
|
||||
"line": self.line,
|
||||
"line_number": self.line_number,
|
||||
"semantic_operands": self.semantic_operands,
|
||||
"throughput": self.throughput,
|
||||
"latency": self.latency,
|
||||
"uops": self.uops,
|
||||
"port_pressure": self.port_pressure,
|
||||
"breaks_dep": self.breaks_dep,
|
||||
}
|
||||
attr_str = "\n ".join(f"{key}={value}" for key, value in attributes.items())
|
||||
return f"instructionForm({attr_str})"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, instructionForm):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from osaca.parser.operand import Operand
|
||||
|
||||
|
||||
class labelOperand(Operand):
|
||||
class LabelOperand(Operand):
|
||||
def __init__(self, name_id=None, comment_id=None):
|
||||
super().__init__(name_id)
|
||||
self._comment_id = comment_id
|
||||
@@ -25,7 +25,7 @@ class labelOperand(Operand):
|
||||
return self._comment_id.pop(0)
|
||||
|
||||
def __str__(self):
|
||||
return f"labelOperand(name_id={self._name_id}, comment={self._comment_id})"
|
||||
return f"LabelOperand(name_id={self._name_id}, comment={self._comment_id})"
|
||||
|
||||
def __repr__(self):
|
||||
return f"labelOperand(name_id={self._name_id}, comment={self._comment_id})"
|
||||
return f"LabelOperand(name_id={self._name_id}, comment={self._comment_id})"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from osaca.parser.operand import Operand
|
||||
|
||||
|
||||
class memoryOperand(Operand):
|
||||
class MemoryOperand(Operand):
|
||||
def __init__(
|
||||
self,
|
||||
offset_ID=None,
|
||||
@@ -127,7 +127,7 @@ class memoryOperand(Operand):
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"memoryOperand(name_id={self._name_id}, offset_ID={self._offset_ID}, "
|
||||
f"MemoryOperand(name_id={self._name_id}, offset_ID={self._offset_ID}, "
|
||||
f"base_id={self._base_id}, index_id={self._index_id}, scale_id={self._scale_id}, "
|
||||
f"segment_ext_id={self._segment_ext_id}, mask={self._mask}, "
|
||||
f"pre_indexed={self._pre_indexed}, post_indexed={self._post_indexed}, "
|
||||
@@ -137,7 +137,7 @@ class memoryOperand(Operand):
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"memoryOperand(name_id={self._name_id}, offset_ID={self._offset_ID}, "
|
||||
f"MemoryOperand(name_id={self._name_id}, offset_ID={self._offset_ID}, "
|
||||
f"base_id={self._base_id}, index_id={self._index_id}, scale_id={self._scale_id}, "
|
||||
f"segment_ext_id={self._segment_ext_id}, mask={self._mask}, "
|
||||
f"pre_indexed={self._pre_indexed}, post_indexed={self._post_indexed}, "
|
||||
@@ -146,7 +146,7 @@ class memoryOperand(Operand):
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, memoryOperand):
|
||||
if isinstance(other, MemoryOperand):
|
||||
return (
|
||||
self._offset_ID == other._offset_ID
|
||||
and self._base_id == other._base_id
|
||||
|
||||
@@ -5,12 +5,12 @@ import pyparsing as pp
|
||||
from osaca.parser import BaseParser
|
||||
from osaca.parser.instruction_form import instructionForm
|
||||
from osaca.parser.operand import Operand
|
||||
from osaca.parser.directive import directiveOperand
|
||||
from osaca.parser.memory import memoryOperand
|
||||
from osaca.parser.label import labelOperand
|
||||
from osaca.parser.register import registerOperand
|
||||
from osaca.parser.identifier import identifierOperand
|
||||
from osaca.parser.immediate import immediateOperand
|
||||
from osaca.parser.directive import DirectiveOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser.label import LabelOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.identifier import IdentifierOperand
|
||||
from osaca.parser.immediate import ImmediateOperand
|
||||
|
||||
|
||||
class ParserAArch64(BaseParser):
|
||||
@@ -301,7 +301,7 @@ class ParserAArch64(BaseParser):
|
||||
result = self.process_operand(
|
||||
self.directive.parseString(line, parseAll=True).asDict()
|
||||
)
|
||||
instruction_form.directive = directiveOperand(
|
||||
instruction_form.directive = DirectiveOperand(
|
||||
name_id=result.name, parameter_id=result.parameters
|
||||
)
|
||||
if result.comment is not None:
|
||||
@@ -383,7 +383,7 @@ class ParserAArch64(BaseParser):
|
||||
if self.REGISTER_ID in operand:
|
||||
return self.process_register_operand(operand[self.REGISTER_ID])
|
||||
if self.directive_id in operand:
|
||||
return directiveOperand(
|
||||
return DirectiveOperand(
|
||||
name_id=operand["directive"]["name"],
|
||||
parameter_id=operand["directive"]["parameters"],
|
||||
comment_id=operand["directive"]["comment"]
|
||||
@@ -393,7 +393,7 @@ class ParserAArch64(BaseParser):
|
||||
return operand
|
||||
|
||||
def process_register_operand(self, operand):
|
||||
return registerOperand(
|
||||
return RegisterOperand(
|
||||
prefix_id=operand["prefix"],
|
||||
name_id=operand["name"],
|
||||
shape=operand["shape"] if "shape" in operand else None,
|
||||
@@ -422,9 +422,9 @@ class ParserAArch64(BaseParser):
|
||||
if "shift" in memory_address["index"]:
|
||||
if memory_address["index"]["shift_op"].lower() in valid_shift_ops:
|
||||
scale = 2 ** int(memory_address["index"]["shift"][0]["value"])
|
||||
new_dict = memoryOperand(
|
||||
new_dict = MemoryOperand(
|
||||
offset_ID=offset,
|
||||
base_id=registerOperand(name_id=base["name"], prefix_id=base["prefix"]),
|
||||
base_id=RegisterOperand(name_id=base["name"], prefix_id=base["prefix"]),
|
||||
index_id=index,
|
||||
scale_id=scale,
|
||||
)
|
||||
@@ -440,7 +440,7 @@ class ParserAArch64(BaseParser):
|
||||
def process_sp_register(self, register):
|
||||
"""Post-process stack pointer register"""
|
||||
# reg = register
|
||||
new_reg = registerOperand(prefix_id="x", name_id="sp")
|
||||
new_reg = RegisterOperand(prefix_id="x", name_id="sp")
|
||||
# reg["prefix"] = "x"
|
||||
return new_reg
|
||||
|
||||
@@ -509,7 +509,7 @@ class ParserAArch64(BaseParser):
|
||||
immediate["type"] = "int"
|
||||
# convert hex/bin immediates to dec
|
||||
immediate["value"] = self.normalize_imd(immediate)
|
||||
return immediateOperand(type_id=immediate["type"], value_id=immediate["value"])
|
||||
return ImmediateOperand(type_id=immediate["type"], value_id=immediate["value"])
|
||||
if "base_immediate" in immediate:
|
||||
# arithmetic immediate, add calculated value as value
|
||||
immediate["shift"] = immediate["shift"][0]
|
||||
@@ -517,7 +517,7 @@ class ParserAArch64(BaseParser):
|
||||
immediate["shift"]["value"]
|
||||
)
|
||||
immediate["type"] = "int"
|
||||
return immediateOperand(
|
||||
return ImmediateOperand(
|
||||
type_id=immediate["type"], value_id=immediate["value"], shift_id=immediate["shift"]
|
||||
)
|
||||
if "float" in immediate:
|
||||
@@ -526,16 +526,16 @@ class ParserAArch64(BaseParser):
|
||||
dict_name = "double"
|
||||
if "exponent" in immediate[dict_name]:
|
||||
immediate["type"] = dict_name
|
||||
return immediateOperand(type_id=immediate["type"])
|
||||
return ImmediateOperand(type_id=immediate["type"])
|
||||
else:
|
||||
# change 'mantissa' key to 'value'
|
||||
return immediateOperand(value_id=immediate[dict_name]["mantissa"], type_id=dict_name)
|
||||
return ImmediateOperand(value_id=immediate[dict_name]["mantissa"], type_id=dict_name)
|
||||
|
||||
def process_label(self, label):
|
||||
"""Post-process label asm line"""
|
||||
# remove duplicated 'name' level due to identifier
|
||||
# label["name"] = label["name"]["name"]
|
||||
new_label = labelOperand(
|
||||
new_label = LabelOperand(
|
||||
name_id=label["name"]["name"],
|
||||
comment_id=label["comment"] if self.comment_id in label else None,
|
||||
)
|
||||
@@ -546,7 +546,7 @@ class ParserAArch64(BaseParser):
|
||||
# remove value if it consists of symbol+offset
|
||||
if "value" in identifier:
|
||||
del identifier["value"]
|
||||
return identifierOperand(offset=identifier["offset"], RELOCATION=identifier["relocation"])
|
||||
return IdentifierOperand(offset=identifier["offset"], RELOCATION=identifier["relocation"])
|
||||
|
||||
def get_full_reg_name(self, register):
|
||||
"""Return one register name string including all attributes"""
|
||||
|
||||
@@ -8,12 +8,12 @@ import pyparsing as pp
|
||||
from osaca.parser import BaseParser
|
||||
from osaca.parser.instruction_form import instructionForm
|
||||
from osaca.parser.operand import Operand
|
||||
from osaca.parser.directive import directiveOperand
|
||||
from osaca.parser.memory import memoryOperand
|
||||
from osaca.parser.label import labelOperand
|
||||
from osaca.parser.register import registerOperand
|
||||
from osaca.parser.identifier import identifierOperand
|
||||
from osaca.parser.immediate import immediateOperand
|
||||
from osaca.parser.directive import DirectiveOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser.label import LabelOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.identifier import IdentifierOperand
|
||||
from osaca.parser.immediate import ImmediateOperand
|
||||
|
||||
|
||||
class ParserX86ATT(BaseParser):
|
||||
@@ -233,7 +233,7 @@ class ParserX86ATT(BaseParser):
|
||||
result = self.process_operand(
|
||||
self.directive.parseString(line, parseAll=True).asDict()
|
||||
)
|
||||
instruction_form.directive = directiveOperand(
|
||||
instruction_form.directive = DirectiveOperand(
|
||||
name_id=result.name,
|
||||
parameter_id=result.parameters,
|
||||
)
|
||||
@@ -299,7 +299,7 @@ class ParserX86ATT(BaseParser):
|
||||
if self.directive_id in operand:
|
||||
return self.process_directive(operand[self.directive_id])
|
||||
if self.REGISTER_ID in operand:
|
||||
return registerOperand(
|
||||
return RegisterOperand(
|
||||
prefix_id=operand["register"]["prefix"]
|
||||
if "prefix" in operand["register"]
|
||||
else None,
|
||||
@@ -314,7 +314,7 @@ class ParserX86ATT(BaseParser):
|
||||
return operand
|
||||
|
||||
def process_directive(self, directive):
|
||||
directive_new = directiveOperand(name_id=directive["name"], parameter_id=[])
|
||||
directive_new = DirectiveOperand(name_id=directive["name"], parameter_id=[])
|
||||
if "parameters" in directive:
|
||||
directive_new.parameters = directive["parameters"]
|
||||
if "comment" in directive:
|
||||
@@ -338,14 +338,14 @@ class ParserX86ATT(BaseParser):
|
||||
elif offset is not None and "value" in offset:
|
||||
offset["value"] = int(offset["value"], 0)
|
||||
if base != None:
|
||||
baseOp = registerOperand(
|
||||
baseOp = RegisterOperand(
|
||||
name_id=base["name"], prefix_id=base["prefix"] if "prefix" in base else None
|
||||
)
|
||||
if index != None:
|
||||
indexOp = registerOperand(
|
||||
indexOp = RegisterOperand(
|
||||
name_id=index["name"], prefix_id=index["prefix"] if "prefix" in index else None
|
||||
)
|
||||
new_dict = memoryOperand(
|
||||
new_dict = MemoryOperand(
|
||||
offset_ID=offset, base_id=baseOp, index_id=indexOp, scale_id=scale
|
||||
)
|
||||
# Add segmentation extension if existing
|
||||
@@ -357,7 +357,7 @@ class ParserX86ATT(BaseParser):
|
||||
"""Post-process label asm line"""
|
||||
# remove duplicated 'name' level due to identifier
|
||||
label["name"] = label["name"][0]["name"]
|
||||
new_label = labelOperand(
|
||||
new_label = LabelOperand(
|
||||
name_id=label["name"], comment_id=label["comment"] if "comment" in label else None
|
||||
)
|
||||
return new_label
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from osaca.parser.operand import Operand
|
||||
|
||||
|
||||
class registerOperand(Operand):
|
||||
class RegisterOperand(Operand):
|
||||
def __init__(
|
||||
self,
|
||||
name_id=None,
|
||||
@@ -114,7 +114,7 @@ class registerOperand(Operand):
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"registerOperand(name_id={self._name_id}, width_id={self._width_id}, "
|
||||
f"RegisterOperand(name_id={self._name_id}, width_id={self._width_id}, "
|
||||
f"prefix_id={self._prefix_id}, reg_id={self._reg_id}, REGtype_id={self._regtype_id}, "
|
||||
f"lanes={self._lanes}, shape={self._shape}, index={self._index}, "
|
||||
f"mask={self._mask}, zeroing={self._zeroing})"
|
||||
@@ -122,14 +122,14 @@ class registerOperand(Operand):
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"registerOperand(name_id={self._name_id}, width_id={self._width_id}, "
|
||||
f"RegisterOperand(name_id={self._name_id}, width_id={self._width_id}, "
|
||||
f"prefix_id={self._prefix_id}, reg_id={self._reg_id}, REGtype_id={self._regtype_id}, "
|
||||
f"lanes={self._lanes}, shape={self._shape}, index={self._index}, "
|
||||
f"mask={self._mask}, zeroing={self._zeroing})"
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, registerOperand):
|
||||
if isinstance(other, RegisterOperand):
|
||||
return (
|
||||
self._name_id == other._name_id
|
||||
and self._width_id == other._width_id
|
||||
|
||||
@@ -9,10 +9,10 @@ from copy import deepcopy
|
||||
|
||||
from .hw_model import MachineModel
|
||||
from .isa_semantics import INSTR_flags, ISASemantics
|
||||
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.memory import MemoryOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.immediate import ImmediateOperand
|
||||
from osaca.parser.identifier import IdentifierOperand
|
||||
|
||||
|
||||
class ArchSemantics(ISASemantics):
|
||||
@@ -55,9 +55,9 @@ class ArchSemantics(ISASemantics):
|
||||
best_kernel_tp = sys.maxsize
|
||||
for port_util_alt in list(instruction_form.port_uops.values())[1:]:
|
||||
k_tmp = deepcopy(kernel)
|
||||
k_tmp[idx]["port_uops"] = deepcopy(port_util_alt)
|
||||
k_tmp[idx]["port_pressure"] = self._machine_model.average_port_pressure(
|
||||
k_tmp[idx]["port_uops"]
|
||||
k_tmp[idx].port_uops = deepcopy(port_util_alt)
|
||||
k_tmp[idx].port_pressure = self._machine_model.average_port_pressure(
|
||||
k_tmp[idx].port_uops
|
||||
)
|
||||
k_tmp.reverse()
|
||||
self.assign_optimal_throughput(k_tmp, idx)
|
||||
@@ -66,7 +66,7 @@ class ArchSemantics(ISASemantics):
|
||||
best_kernel_tp = max(self.get_throughput_sum(best_kernel))
|
||||
# check the first option in the main branch and compare against the best option later
|
||||
multiple_assignments = True
|
||||
kernel[idx]["port_uops"] = list(instruction_form.port_uops.values())[0]
|
||||
kernel[idx].port_uops = list(instruction_form.port_uops.values())[0]
|
||||
for uop in instruction_form.port_uops:
|
||||
cycles = uop[0]
|
||||
ports = list(uop[1])
|
||||
@@ -134,8 +134,8 @@ class ArchSemantics(ISASemantics):
|
||||
if multiple_assignments:
|
||||
if max(self.get_throughput_sum(kernel)) > best_kernel_tp:
|
||||
for i, instr in enumerate(best_kernel):
|
||||
kernel[i]["port_uops"] = best_kernel[i]["port_uops"]
|
||||
kernel[i]["port_pressure"] = best_kernel[i]["port_pressure"]
|
||||
kernel[i].port_uops = best_kernel[i].port_uops
|
||||
kernel[i].port_pressure = best_kernel[i].port_pressure
|
||||
|
||||
def set_hidden_loads(self, kernel):
|
||||
"""Hide loads behind stores if architecture supports hidden loads (depricated)"""
|
||||
@@ -262,7 +262,7 @@ class ArchSemantics(ISASemantics):
|
||||
]
|
||||
)
|
||||
# dummy_reg = {"class": "register", "name": reg_type}
|
||||
dummy_reg = registerOperand(name_id=reg_type)
|
||||
dummy_reg = RegisterOperand(name_id=reg_type)
|
||||
data_port_pressure = [0.0 for _ in range(port_number)]
|
||||
data_port_uops = []
|
||||
if INSTR_flags.HAS_LD in instruction_form.flags:
|
||||
@@ -272,7 +272,7 @@ class ArchSemantics(ISASemantics):
|
||||
x
|
||||
for x in instruction_form.semantic_operands["source"]
|
||||
+ instruction_form.semantic_operands["src_dst"]
|
||||
if isinstance(x, memoryOperand)
|
||||
if isinstance(x, MemoryOperand)
|
||||
][0]
|
||||
)
|
||||
# if multiple options, choose based on reg type
|
||||
@@ -281,7 +281,7 @@ class ArchSemantics(ISASemantics):
|
||||
for ldp in load_perf_data
|
||||
if ldp.dst != None
|
||||
and self._machine_model._check_operands(
|
||||
dummy_reg, registerOperand(name_id=ldp.dst)
|
||||
dummy_reg, RegisterOperand(name_id=ldp.dst)
|
||||
)
|
||||
]
|
||||
if len(data_port_uops) < 1:
|
||||
@@ -303,7 +303,7 @@ class ArchSemantics(ISASemantics):
|
||||
+ instruction_form.semantic_operands["src_dst"]
|
||||
)
|
||||
store_perf_data = self._machine_model.get_store_throughput(
|
||||
[x for x in destinations if isinstance(x, memoryOperand)][0],
|
||||
[x for x in destinations if isinstance(x, MemoryOperand)][0],
|
||||
dummy_reg,
|
||||
)
|
||||
st_data_port_uops = store_perf_data[0].port_pressure
|
||||
@@ -320,7 +320,7 @@ class ArchSemantics(ISASemantics):
|
||||
[
|
||||
op.post_indexed or op.pre_indexed
|
||||
for op in instruction_form.semantic_operands["src_dst"]
|
||||
if isinstance(op, memoryOperand)
|
||||
if isinstance(op, MemoryOperand)
|
||||
]
|
||||
)
|
||||
):
|
||||
@@ -444,11 +444,11 @@ class ArchSemantics(ISASemantics):
|
||||
"""Create register operand for a memory addressing operand"""
|
||||
if self._isa == "x86":
|
||||
if reg_type == "gpr":
|
||||
register = registerOperand(name_id="r" + str(int(reg_id) + 9))
|
||||
register = RegisterOperand(name_id="r" + str(int(reg_id) + 9))
|
||||
else:
|
||||
register = registerOperand(name_id=reg_type + reg_id)
|
||||
register = RegisterOperand(name_id=reg_type + reg_id)
|
||||
elif self._isa == "aarch64":
|
||||
register = registerOperand(name_id=reg_id, prefix_id=reg_type)
|
||||
register = RegisterOperand(name_id=reg_id, prefix_id=reg_type)
|
||||
return register
|
||||
|
||||
def _nullify_data_ports(self, port_pressure):
|
||||
|
||||
@@ -16,10 +16,11 @@ from osaca.parser import ParserX86ATT
|
||||
from ruamel.yaml.compat import StringIO
|
||||
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.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
|
||||
|
||||
|
||||
class MachineModel(object):
|
||||
@@ -144,7 +145,7 @@ class MachineModel(object):
|
||||
# List containing classes with same name/instruction
|
||||
self._data["instruction_forms_dict"][iform["name"]].append(new_iform)
|
||||
self._data["internal_version"] = self.INTERNAL_VERSION
|
||||
|
||||
self.load_store_tp()
|
||||
if not lazy:
|
||||
# cache internal representation for future use
|
||||
self._write_in_cache(self._path)
|
||||
@@ -157,13 +158,13 @@ class MachineModel(object):
|
||||
if "load_throughput" in self._data:
|
||||
for m in self._data["load_throughput"]:
|
||||
new_throughputs.append(
|
||||
memoryOperand(
|
||||
MemoryOperand(
|
||||
base_id=m["base"],
|
||||
offset_ID=m["offset"],
|
||||
scale_id=m["scale"],
|
||||
index_id=m["index"],
|
||||
port_pressure=m["port_pressure"],
|
||||
ds=m["dst"] if "dst" in m else None,
|
||||
dst=m["dst"] if "dst" in m else None,
|
||||
)
|
||||
)
|
||||
self._data["load_throughput"] = new_throughputs
|
||||
@@ -172,7 +173,7 @@ class MachineModel(object):
|
||||
if "store_throughput" in self._data:
|
||||
for m in self._data["store_throughput"]:
|
||||
new_throughputs.append(
|
||||
memoryOperand(
|
||||
MemoryOperand(
|
||||
base_id=m["base"],
|
||||
offset_ID=m["offset"],
|
||||
scale_id=m["scale"],
|
||||
@@ -186,7 +187,7 @@ class MachineModel(object):
|
||||
"""Convert an operand from dict type to class"""
|
||||
if o["class"] == "register":
|
||||
new_operands.append(
|
||||
registerOperand(
|
||||
RegisterOperand(
|
||||
name_id=o["name"] if "name" in o else None,
|
||||
prefix_id=o["prefix"] if "prefix" in o else None,
|
||||
shape=o["shape"] if "shape" in o else None,
|
||||
@@ -197,7 +198,7 @@ class MachineModel(object):
|
||||
)
|
||||
elif o["class"] == "memory":
|
||||
new_operands.append(
|
||||
memoryOperand(
|
||||
MemoryOperand(
|
||||
base_id=o["base"],
|
||||
offset_ID=o["offset"],
|
||||
index_id=o["index"],
|
||||
@@ -208,14 +209,22 @@ class MachineModel(object):
|
||||
)
|
||||
elif o["class"] == "immediate":
|
||||
new_operands.append(
|
||||
immediateOperand(
|
||||
ImmediateOperand(
|
||||
type_id=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())
|
||||
new_operands.append(IdentifierOperand())
|
||||
elif o["class"] == "condition":
|
||||
new_operands.append(
|
||||
ConditionOperand(
|
||||
ccode=o["ccode"],
|
||||
source=o["source"] if "source" in o else False,
|
||||
destination=o["destination"] if "destination" in o else False,
|
||||
)
|
||||
)
|
||||
else:
|
||||
new_operands.append(o)
|
||||
|
||||
@@ -340,7 +349,7 @@ class MachineModel(object):
|
||||
ld_tp = [m for m in self._data["load_throughput"] if self._match_mem_entries(memory, m)]
|
||||
if len(ld_tp) > 0:
|
||||
return ld_tp.copy()
|
||||
return [memoryOperand(port_pressure=self._data["load_throughput_default"].copy())]
|
||||
return [MemoryOperand(port_pressure=self._data["load_throughput_default"].copy())]
|
||||
|
||||
def get_store_latency(self, reg_type):
|
||||
"""Return store latency for given register type."""
|
||||
@@ -355,11 +364,11 @@ class MachineModel(object):
|
||||
tp
|
||||
for tp in st_tp
|
||||
if "src" in tp
|
||||
and self._check_operands(src_reg, registerOperand(name_id=tp["src"]))
|
||||
and self._check_operands(src_reg, RegisterOperand(name_id=tp["src"]))
|
||||
]
|
||||
if len(st_tp) > 0:
|
||||
return st_tp.copy()
|
||||
return [memoryOperand(port_pressure=self._data["store_throughput_default"].copy())]
|
||||
return [MemoryOperand(port_pressure=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."""
|
||||
@@ -378,7 +387,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 = []
|
||||
if op.name != None:
|
||||
op_attrs.append("name:" + op.name)
|
||||
@@ -387,7 +396,7 @@ class MachineModel(object):
|
||||
if op.shape != None:
|
||||
op_attrs.append("shape:" + op.shape)
|
||||
operands.append("{}({})".format("register", ",".join(op_attrs)))
|
||||
return "{} {}".format(instruction_form["name"].lower(), ",".join(operands))
|
||||
return "{} {}".format(instruction_form.instruction.lower(), ",".join(operands))
|
||||
|
||||
@staticmethod
|
||||
def get_isa_for_arch(arch):
|
||||
@@ -571,13 +580,13 @@ class MachineModel(object):
|
||||
def _create_db_operand_aarch64(self, operand):
|
||||
"""Create instruction form operand for DB out of operand string."""
|
||||
if operand == "i":
|
||||
return immediateOperand(type_id="int")
|
||||
return ImmediateOperand(type_id="int")
|
||||
elif operand in "wxbhsdq":
|
||||
return registerOperand(prefix_id=operand)
|
||||
return RegisterOperand(prefix_id=operand)
|
||||
elif operand.startswith("v"):
|
||||
return registerOperand(prefix_id="v", shape=operand[1:2])
|
||||
return RegisterOperand(prefix_id="v", shape=operand[1:2])
|
||||
elif operand.startswith("m"):
|
||||
return memoryOperand(
|
||||
return MemoryOperand(
|
||||
base_id="x" if "b" in operand else None,
|
||||
offset_ID="imd" if "o" in operand else None,
|
||||
index_id="gpr" if "i" in operand else None,
|
||||
@@ -591,13 +600,13 @@ class MachineModel(object):
|
||||
def _create_db_operand_x86(self, operand):
|
||||
"""Create instruction form operand for DB out of operand string."""
|
||||
if operand == "r":
|
||||
return registerOperand(name_id="gpr")
|
||||
return RegisterOperand(name_id="gpr")
|
||||
elif operand in "xyz":
|
||||
return registerOperand(name_id=operand + "mm")
|
||||
return RegisterOperand(name_id=operand + "mm")
|
||||
elif operand == "i":
|
||||
return immediateOperand(type_id="int")
|
||||
return ImmediateOperand(type_id="int")
|
||||
elif operand.startswith("m"):
|
||||
return memoryOperand(
|
||||
return MemoryOperand(
|
||||
base_id="gpr" if "b" in operand else None,
|
||||
offset_ID="imd" if "o" in operand else None,
|
||||
index_id="gpr" if "i" in operand else None,
|
||||
@@ -644,7 +653,7 @@ class MachineModel(object):
|
||||
if (isinstance(operand, Operand) and operand.name == self.WILDCARD) or (
|
||||
not isinstance(operand, Operand) and self.WILDCARD in operand
|
||||
):
|
||||
if isinstance(i_operand, registerOperand):
|
||||
if isinstance(i_operand, RegisterOperand):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -660,57 +669,52 @@ class MachineModel(object):
|
||||
# return self._compare_db_entries(i_operand, operand)
|
||||
# TODO support class wildcards
|
||||
# register
|
||||
if isinstance(operand, registerOperand):
|
||||
if not isinstance(i_operand, registerOperand):
|
||||
if isinstance(operand, RegisterOperand):
|
||||
if not isinstance(i_operand, RegisterOperand):
|
||||
return False
|
||||
return self._is_AArch64_reg_type(i_operand, operand)
|
||||
# memory
|
||||
if isinstance(operand, memoryOperand):
|
||||
if not isinstance(i_operand, memoryOperand):
|
||||
if isinstance(operand, MemoryOperand):
|
||||
if not isinstance(i_operand, MemoryOperand):
|
||||
return False
|
||||
return self._is_AArch64_mem_type(i_operand, operand)
|
||||
# immediate
|
||||
if isinstance(i_operand, immediateOperand) and i_operand.type == self.WILDCARD:
|
||||
return isinstance(operand, immediateOperand) and (operand.value != None)
|
||||
if isinstance(i_operand, ImmediateOperand) and i_operand.type == self.WILDCARD:
|
||||
return isinstance(operand, ImmediateOperand) and (operand.value != None)
|
||||
|
||||
if isinstance(i_operand, immediateOperand) and i_operand.type == "int":
|
||||
if isinstance(i_operand, ImmediateOperand) and i_operand.type == "int":
|
||||
return (
|
||||
isinstance(operand, immediateOperand)
|
||||
isinstance(operand, ImmediateOperand)
|
||||
and operand.type == "int"
|
||||
and operand.value != None
|
||||
)
|
||||
|
||||
if isinstance(i_operand, immediateOperand) and i_operand.type == "float":
|
||||
if isinstance(i_operand, ImmediateOperand) and i_operand.type == "float":
|
||||
return (
|
||||
isinstance(operand, immediateOperand)
|
||||
isinstance(operand, ImmediateOperand)
|
||||
and operand.type == "float"
|
||||
and operand.value != None
|
||||
)
|
||||
|
||||
if isinstance(i_operand, immediateOperand) and i_operand.type == "double":
|
||||
if isinstance(i_operand, ImmediateOperand) and i_operand.type == "double":
|
||||
return (
|
||||
isinstance(operand, immediateOperand)
|
||||
isinstance(operand, ImmediateOperand)
|
||||
and operand.type == "double"
|
||||
and operand.value != None
|
||||
)
|
||||
|
||||
# identifier
|
||||
if isinstance(operand, identifierOperand) or (
|
||||
isinstance(operand, immediateOperand) and operand.identifier != None
|
||||
if isinstance(operand, IdentifierOperand) or (
|
||||
isinstance(operand, ImmediateOperand) and operand.identifier != None
|
||||
):
|
||||
return isinstance(i_operand, identifierOperand)
|
||||
return isinstance(i_operand, IdentifierOperand)
|
||||
# prefetch option
|
||||
if not isinstance(operand, Operand) and "prfop" in operand:
|
||||
return i_operand["class"] == "prfop"
|
||||
# condition
|
||||
if not isinstance(operand, Operand) and "condition" in operand:
|
||||
if 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
|
||||
|
||||
@@ -720,22 +724,22 @@ class MachineModel(object):
|
||||
# compare two DB entries
|
||||
# return self._compare_db_entries(i_operand, operand)
|
||||
# register
|
||||
if isinstance(operand, registerOperand):
|
||||
if not isinstance(i_operand, registerOperand):
|
||||
if isinstance(operand, RegisterOperand):
|
||||
if not isinstance(i_operand, RegisterOperand):
|
||||
return False
|
||||
return self._is_x86_reg_type(i_operand, operand, consider_masking=False)
|
||||
# memory
|
||||
if isinstance(operand, memoryOperand):
|
||||
if not isinstance(i_operand, memoryOperand):
|
||||
if isinstance(operand, MemoryOperand):
|
||||
if not isinstance(i_operand, MemoryOperand):
|
||||
return False
|
||||
return self._is_x86_mem_type(i_operand, operand)
|
||||
# immediate
|
||||
if isinstance(operand, immediateOperand):
|
||||
if isinstance(operand, ImmediateOperand):
|
||||
# if "immediate" in operand.name or operand.value != None:
|
||||
return isinstance(i_operand, immediateOperand) and i_operand.type == "int"
|
||||
return isinstance(i_operand, ImmediateOperand) and i_operand.type == "int"
|
||||
# identifier (e.g., labels)
|
||||
if isinstance(operand, identifierOperand):
|
||||
return isinstance(i_operand, identifierOperand)
|
||||
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):
|
||||
@@ -791,7 +795,7 @@ class MachineModel(object):
|
||||
if i_reg is None:
|
||||
return True
|
||||
return False
|
||||
if isinstance(i_reg, registerOperand):
|
||||
if isinstance(i_reg, RegisterOperand):
|
||||
i_reg_name = i_reg.name
|
||||
else:
|
||||
i_reg_name = i_reg
|
||||
@@ -843,7 +847,7 @@ class MachineModel(object):
|
||||
(
|
||||
(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))
|
||||
or (isinstance(mem.base, RegisterOperand) and (mem.base.prefix == i_mem.base))
|
||||
)
|
||||
# check offset
|
||||
and (
|
||||
|
||||
@@ -3,9 +3,9 @@ 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 osaca.parser.immediate import immediateOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.immediate import ImmediateOperand
|
||||
|
||||
from .hw_model import MachineModel
|
||||
|
||||
@@ -81,7 +81,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 any([isinstance(op, memoryOperand) for op in operands]):
|
||||
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
|
||||
@@ -116,7 +116,7 @@ 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 isinstance(op, memoryOperand)]:
|
||||
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:
|
||||
@@ -127,7 +127,7 @@ class ISASemantics(object):
|
||||
"post_indexed": post_indexed,
|
||||
}
|
||||
)
|
||||
for operand in [op for op in op_dict["destination"] if isinstance(op, memoryOperand)]:
|
||||
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:
|
||||
@@ -165,7 +165,7 @@ class ISASemantics(object):
|
||||
instruction_form.semantic_operands["destination"],
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
)
|
||||
if isinstance(op, registerOperand)
|
||||
if isinstance(op, RegisterOperand)
|
||||
]
|
||||
isa_data = self._isa_model.get_instruction(
|
||||
instruction_form.instruction, instruction_form.operands
|
||||
@@ -188,7 +188,7 @@ class ISASemantics(object):
|
||||
|
||||
if only_postindexed:
|
||||
for o in instruction_form.operands:
|
||||
if isinstance(o, memoryOperand) and o.base != None and o.post_indexed != False:
|
||||
if isinstance(o, MemoryOperand) and o.base != None and o.post_indexed != False:
|
||||
base_name = o.base.prefix if o.base.prefix != None else "" + o.base.name
|
||||
return {
|
||||
base_name: {
|
||||
@@ -202,7 +202,7 @@ class ISASemantics(object):
|
||||
operand_state = {} # e.g., {'op1': {'name': 'rax', 'value': 0}} 0 means unchanged
|
||||
|
||||
for o in instruction_form.operands:
|
||||
if isinstance(o, memoryOperand) and o.pre_indexed:
|
||||
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(
|
||||
@@ -216,13 +216,13 @@ class ISASemantics(object):
|
||||
if isa_data is not None:
|
||||
for i, o in enumerate(instruction_form.operands):
|
||||
operand_name = "op{}".format(i + 1)
|
||||
if isinstance(o, registerOperand):
|
||||
if isinstance(o, RegisterOperand):
|
||||
o_reg_name = o.prefix if o.prefix != None else "" + o.name
|
||||
reg_operand_names[o_reg_name] = operand_name
|
||||
operand_state[operand_name] = {"name": o_reg_name, "value": 0}
|
||||
elif isinstance(o, immediateOperand):
|
||||
elif isinstance(o, ImmediateOperand):
|
||||
operand_state[operand_name] = {"value": o.value}
|
||||
elif isinstance(o, memoryOperand):
|
||||
elif isinstance(o, MemoryOperand):
|
||||
# TODO lea needs some thinking about
|
||||
pass
|
||||
|
||||
@@ -253,12 +253,12 @@ class ISASemantics(object):
|
||||
|
||||
# handle dependency breaking instructions
|
||||
"""
|
||||
if "breaks_dependency_on_equal_operands" in isa_data and operands[1:] == operands[:-1]:
|
||||
if isa_data.breaks_dep and operands[1:] == operands[:-1]:
|
||||
op_dict["destination"] += operands
|
||||
if "hidden_operands" in isa_data:
|
||||
if isa_data.hidden_operands!=[]:
|
||||
op_dict["destination"] += [
|
||||
{hop["class"]: {k: hop[k] for k in ["name", "class", "source", "destination"]}}
|
||||
for hop in isa_data["hidden_operands"]
|
||||
for hop in isa_data.hidden_operands
|
||||
]
|
||||
return op_dict
|
||||
"""
|
||||
@@ -276,21 +276,20 @@ class ISASemantics(object):
|
||||
|
||||
# check for hidden operands like flags or registers
|
||||
"""
|
||||
if "hidden_operands" in isa_data:
|
||||
if isa_data.hidden_operands!=[]:
|
||||
# add operand(s) to semantic_operands of instruction form
|
||||
for op in isa_data["hidden_operands"]:
|
||||
for op in isa_data.hidden_operands:
|
||||
dict_key = (
|
||||
"src_dst"
|
||||
if op["source"] and op["destination"]
|
||||
if op.source and op.destination
|
||||
else "source"
|
||||
if op["source"]
|
||||
if op.source
|
||||
else "destination"
|
||||
)
|
||||
hidden_op = {op["class"]: {}}
|
||||
key_filter = ["class", "source", "destination"]
|
||||
for key in [k for k in op.keys() if k not in key_filter]:
|
||||
hidden_op[op["class"]][key] = op[key]
|
||||
hidden_op = AttrDict.convert_dict(hidden_op)
|
||||
op_dict[dict_key].append(hidden_op)
|
||||
"""
|
||||
return op_dict
|
||||
@@ -301,7 +300,7 @@ class ISASemantics(object):
|
||||
instruction_form.semantic_operands["source"],
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
):
|
||||
if isinstance(operand, memoryOperand):
|
||||
if isinstance(operand, MemoryOperand):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -311,7 +310,7 @@ class ISASemantics(object):
|
||||
instruction_form.semantic_operands["destination"],
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
):
|
||||
if isinstance(operand, memoryOperand):
|
||||
if isinstance(operand, MemoryOperand):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -345,7 +344,7 @@ class ISASemantics(object):
|
||||
def substitute_mem_address(self, operands):
|
||||
"""Create memory wildcard for all memory operands"""
|
||||
return [
|
||||
self._create_reg_wildcard() if isinstance(op, memoryOperand) else op for op in operands
|
||||
self._create_reg_wildcard() if isinstance(op, MemoryOperand) else op for op in operands
|
||||
]
|
||||
|
||||
def _create_reg_wildcard(self):
|
||||
|
||||
@@ -9,9 +9,9 @@ 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
|
||||
from osaca.parser.immediate import immediateOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.immediate import ImmediateOperand
|
||||
|
||||
|
||||
class KernelDG(nx.DiGraph):
|
||||
@@ -283,7 +283,7 @@ 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 isinstance(dst, registerOperand):
|
||||
if isinstance(dst, RegisterOperand):
|
||||
# read of register
|
||||
if self.is_read(dst, instr_form):
|
||||
# if dst.pre_indexed or dst.post_indexed:
|
||||
@@ -294,8 +294,8 @@ class KernelDG(nx.DiGraph):
|
||||
if self.is_written(dst, instr_form):
|
||||
break
|
||||
if (
|
||||
not isinstance(dst, registerOperand)
|
||||
and not isinstance(dst, memoryOperand)
|
||||
not isinstance(dst, RegisterOperand)
|
||||
and not isinstance(dst, MemoryOperand)
|
||||
and "flag" in dst
|
||||
and flag_dependencies
|
||||
):
|
||||
@@ -305,7 +305,7 @@ class KernelDG(nx.DiGraph):
|
||||
# write to flag -> abort
|
||||
if self.is_written(dst.flag, instr_form):
|
||||
break
|
||||
if isinstance(dst, memoryOperand):
|
||||
if isinstance(dst, MemoryOperand):
|
||||
# base register is altered during memory access
|
||||
if dst.pre_indexed != None:
|
||||
if self.is_written(dst.base, instr_form):
|
||||
@@ -374,16 +374,16 @@ class KernelDG(nx.DiGraph):
|
||||
instruction_form.semantic_operands["source"],
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
):
|
||||
if isinstance(src, registerOperand):
|
||||
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 not isinstance(src, immediateOperand)
|
||||
not isinstance(src, RegisterOperand)
|
||||
and not isinstance(src, MemoryOperand)
|
||||
and not isinstance(src, ImmediateOperand)
|
||||
and "flag" in src
|
||||
):
|
||||
is_read = self.parser.is_flag_dependend_of(register, src.flag) or is_read
|
||||
if isinstance(src, memoryOperand):
|
||||
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:
|
||||
@@ -393,7 +393,7 @@ class KernelDG(nx.DiGraph):
|
||||
instruction_form.semantic_operands["destination"],
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
):
|
||||
if isinstance(dst, memoryOperand):
|
||||
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:
|
||||
@@ -409,7 +409,7 @@ class KernelDG(nx.DiGraph):
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
):
|
||||
# Here we check for mem dependecies only
|
||||
if not isinstance(src, memoryOperand):
|
||||
if not isinstance(src, MemoryOperand):
|
||||
continue
|
||||
# src = src.memory
|
||||
|
||||
@@ -482,15 +482,15 @@ class KernelDG(nx.DiGraph):
|
||||
instruction_form.semantic_operands["destination"],
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
):
|
||||
if isinstance(dst, registerOperand):
|
||||
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)
|
||||
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 isinstance(dst, memoryOperand):
|
||||
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
|
||||
@@ -498,7 +498,7 @@ class KernelDG(nx.DiGraph):
|
||||
instruction_form.semantic_operands["source"],
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
):
|
||||
if isinstance(src, memoryOperand):
|
||||
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
|
||||
@@ -512,7 +512,7 @@ class KernelDG(nx.DiGraph):
|
||||
instruction_form.semantic_operands["destination"],
|
||||
instruction_form.semantic_operands["src_dst"],
|
||||
):
|
||||
if isinstance(dst, memoryOperand):
|
||||
if isinstance(dst, MemoryOperand):
|
||||
is_store = mem == dst or is_store
|
||||
return is_store
|
||||
|
||||
@@ -526,11 +526,11 @@ class KernelDG(nx.DiGraph):
|
||||
"""
|
||||
graph = copy.deepcopy(self.dg)
|
||||
cp = self.get_critical_path()
|
||||
cp_line_numbers = [x["line_number"] for x in cp]
|
||||
cp_line_numbers = [x.line_number for x in cp]
|
||||
lcd = self.get_loopcarried_dependencies()
|
||||
lcd_line_numbers = {}
|
||||
for dep in lcd:
|
||||
lcd_line_numbers[dep] = [x["line_number"] for x, lat in lcd[dep]["dependencies"]]
|
||||
lcd_line_numbers[dep] = [x.line_number for x, lat in lcd[dep]["dependencies"]]
|
||||
# add color scheme
|
||||
graph.graph["node"] = {"colorscheme": "accent8"}
|
||||
graph.graph["edge"] = {"colorscheme": "accent8"}
|
||||
@@ -541,7 +541,7 @@ class KernelDG(nx.DiGraph):
|
||||
max_line_number = max(lcd_line_numbers[dep])
|
||||
graph.add_edge(max_line_number, min_line_number)
|
||||
graph.edges[max_line_number, min_line_number]["latency"] = [
|
||||
lat for x, lat in lcd[dep]["dependencies"] if x["line_number"] == max_line_number
|
||||
lat for x, lat in lcd[dep]["dependencies"] if x.line_number == max_line_number
|
||||
]
|
||||
|
||||
# add label to edges
|
||||
@@ -550,7 +550,7 @@ class KernelDG(nx.DiGraph):
|
||||
|
||||
# add CP values to graph
|
||||
for n in cp:
|
||||
graph.nodes[n["line_number"]]["instruction_form"]["latency_cp"] = n["latency_cp"]
|
||||
graph.nodes[n.line_number]["instruction_form"].latency_cp = n.latency_cp
|
||||
|
||||
# color CP and LCD
|
||||
for n in graph.nodes:
|
||||
@@ -569,8 +569,8 @@ class KernelDG(nx.DiGraph):
|
||||
# color edges
|
||||
for e in graph.edges:
|
||||
if (
|
||||
graph.nodes[e[0]]["instruction_form"]["line_number"] in cp_line_numbers
|
||||
and graph.nodes[e[1]]["instruction_form"]["line_number"] in cp_line_numbers
|
||||
graph.nodes[e[0]]["instruction_form"].line_number in cp_line_numbers
|
||||
and graph.nodes[e[1]]["instruction_form"].line_number in cp_line_numbers
|
||||
and e[0] < e[1]
|
||||
):
|
||||
bold_edge = True
|
||||
@@ -582,9 +582,8 @@ class KernelDG(nx.DiGraph):
|
||||
graph.edges[e]["penwidth"] = 3
|
||||
for dep in lcd_line_numbers:
|
||||
if (
|
||||
graph.nodes[e[0]]["instruction_form"]["line_number"] in lcd_line_numbers[dep]
|
||||
and graph.nodes[e[1]]["instruction_form"]["line_number"]
|
||||
in lcd_line_numbers[dep]
|
||||
graph.nodes[e[0]]["instruction_form"].line_number in lcd_line_numbers[dep]
|
||||
and graph.nodes[e[1]]["instruction_form"].line_number in lcd_line_numbers[dep]
|
||||
):
|
||||
graph.edges[e]["color"] = graph.nodes[e[1]]["fillcolor"]
|
||||
|
||||
@@ -597,12 +596,12 @@ class KernelDG(nx.DiGraph):
|
||||
graph.nodes[n]["fontsize"] = 11.0
|
||||
else:
|
||||
node = graph.nodes[n]["instruction_form"]
|
||||
if node["instruction"] is not None:
|
||||
mapping[n] = "{}: {}".format(n, node["instruction"])
|
||||
if node.instruction is not None:
|
||||
mapping[n] = "{}: {}".format(n, node.instruction)
|
||||
else:
|
||||
label = "label" if node["label"] else None
|
||||
label = "directive" if node["directive"] else label
|
||||
label = "comment" if node["comment"] and label is None else label
|
||||
label = "label" if node.label != None else None
|
||||
label = "directive" if node.directive != None else label
|
||||
label = "comment" if node.comment != None and label is None else label
|
||||
mapping[n] = "{}: {}".format(n, label)
|
||||
graph.nodes[n]["fontname"] = "italic"
|
||||
graph.nodes[n]["fontsize"] = 11.0
|
||||
|
||||
@@ -10,8 +10,8 @@ import osaca.db_interface as dbi
|
||||
from osaca.db_interface import sanity_check
|
||||
from osaca.semantics import MachineModel
|
||||
from osaca.parser import instructionForm
|
||||
from osaca.parser.memory import memoryOperand
|
||||
from osaca.parser.register import registerOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
import copy
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ class TestDBInterface(unittest.TestCase):
|
||||
sample_entry = instructionForm(
|
||||
instruction_id="DoItRightAndDoItFast",
|
||||
operands_id=[
|
||||
memoryOperand(offset_ID="imd", base_id="gpr", index_id="gpr", scale_id=8),
|
||||
registerOperand(name_id="xmm"),
|
||||
MemoryOperand(offset_ID="imd", base_id="gpr", index_id="gpr", scale_id=8),
|
||||
RegisterOperand(name_id="xmm"),
|
||||
],
|
||||
throughput=1.25,
|
||||
latency=125,
|
||||
|
||||
@@ -9,6 +9,7 @@ import unittest
|
||||
from osaca.frontend import Frontend
|
||||
from osaca.parser import ParserAArch64, ParserX86ATT
|
||||
from osaca.semantics import ArchSemantics, KernelDG, MachineModel, reduce_to_section
|
||||
from osaca.parser.operand import Operand
|
||||
|
||||
|
||||
class TestFrontend(unittest.TestCase):
|
||||
@@ -41,6 +42,7 @@ class TestFrontend(unittest.TestCase):
|
||||
self.machine_model_tx2,
|
||||
path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "isa/aarch64.yml"),
|
||||
)
|
||||
|
||||
for i in range(len(self.kernel_x86)):
|
||||
self.semantics_csx.assign_src_dst(self.kernel_x86[i])
|
||||
self.semantics_csx.assign_tp_lt(self.kernel_x86[i])
|
||||
|
||||
@@ -10,10 +10,10 @@ from pyparsing import ParseException
|
||||
|
||||
from osaca.parser import ParserAArch64, instructionForm
|
||||
from osaca.parser.operand import Operand
|
||||
from osaca.parser.directive import directiveOperand
|
||||
from osaca.parser.memory import memoryOperand
|
||||
from osaca.parser.register import registerOperand
|
||||
from osaca.parser.immediate import immediateOperand
|
||||
from osaca.parser.directive import DirectiveOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.immediate import ImmediateOperand
|
||||
|
||||
|
||||
class TestParserAArch64(unittest.TestCase):
|
||||
@@ -203,7 +203,7 @@ class TestParserAArch64(unittest.TestCase):
|
||||
instruction_form_3 = instructionForm(
|
||||
instruction_id=None,
|
||||
operands_id=[],
|
||||
directive_id=directiveOperand(name_id="cfi_def_cfa", parameter_id=["w29", "-16"]),
|
||||
directive_id=DirectiveOperand(name_id="cfi_def_cfa", parameter_id=["w29", "-16"]),
|
||||
comment_id=None,
|
||||
label_id=None,
|
||||
line=".cfi_def_cfa w29, -16",
|
||||
@@ -212,10 +212,10 @@ class TestParserAArch64(unittest.TestCase):
|
||||
instruction_form_4 = instructionForm(
|
||||
instruction_id="ldr",
|
||||
operands_id=[
|
||||
registerOperand(prefix_id="s", name_id="0"),
|
||||
memoryOperand(
|
||||
RegisterOperand(prefix_id="s", name_id="0"),
|
||||
MemoryOperand(
|
||||
offset_ID=None,
|
||||
base_id=registerOperand(prefix_id="x", name_id="11"),
|
||||
base_id=RegisterOperand(prefix_id="x", name_id="11"),
|
||||
index_id={
|
||||
"prefix": "w",
|
||||
"name": "10",
|
||||
@@ -236,9 +236,9 @@ class TestParserAArch64(unittest.TestCase):
|
||||
instruction_id="prfm",
|
||||
operands_id=[
|
||||
{"prfop": {"type": ["PLD"], "target": ["L1"], "policy": ["KEEP"]}},
|
||||
memoryOperand(
|
||||
MemoryOperand(
|
||||
offset_ID={"value": 2048},
|
||||
base_id=registerOperand(prefix_id="x", name_id="26"),
|
||||
base_id=RegisterOperand(prefix_id="x", name_id="26"),
|
||||
index_id=None,
|
||||
scale_id=1,
|
||||
),
|
||||
@@ -252,11 +252,11 @@ class TestParserAArch64(unittest.TestCase):
|
||||
instruction_form_6 = instructionForm(
|
||||
instruction_id="stp",
|
||||
operands_id=[
|
||||
registerOperand(prefix_id="x", name_id="29"),
|
||||
registerOperand(prefix_id="x", name_id="30"),
|
||||
memoryOperand(
|
||||
RegisterOperand(prefix_id="x", name_id="29"),
|
||||
RegisterOperand(prefix_id="x", name_id="30"),
|
||||
MemoryOperand(
|
||||
offset_ID={"value": -16},
|
||||
base_id=registerOperand(name_id="sp", prefix_id="x"),
|
||||
base_id=RegisterOperand(name_id="sp", prefix_id="x"),
|
||||
index_id=None,
|
||||
scale_id=1,
|
||||
pre_indexed=True,
|
||||
@@ -271,11 +271,11 @@ class TestParserAArch64(unittest.TestCase):
|
||||
instruction_form_7 = instructionForm(
|
||||
instruction_id="ldp",
|
||||
operands_id=[
|
||||
registerOperand(prefix_id="q", name_id="2"),
|
||||
registerOperand(prefix_id="q", name_id="3"),
|
||||
memoryOperand(
|
||||
RegisterOperand(prefix_id="q", name_id="2"),
|
||||
RegisterOperand(prefix_id="q", name_id="3"),
|
||||
MemoryOperand(
|
||||
offset_ID=None,
|
||||
base_id=registerOperand(name_id="11", prefix_id="x"),
|
||||
base_id=RegisterOperand(name_id="11", prefix_id="x"),
|
||||
index_id=None,
|
||||
scale_id=1,
|
||||
post_indexed={"value": 64},
|
||||
@@ -290,11 +290,11 @@ class TestParserAArch64(unittest.TestCase):
|
||||
instruction_form_8 = instructionForm(
|
||||
instruction_id="fcmla",
|
||||
operands_id=[
|
||||
registerOperand(prefix_id="z", name_id="26", shape="d"),
|
||||
registerOperand(prefix_id="p", name_id="0", predication="m"),
|
||||
registerOperand(prefix_id="z", name_id="29", shape="d"),
|
||||
registerOperand(prefix_id="z", name_id="21", shape="d"),
|
||||
immediateOperand(value_id=90, type_id="int"),
|
||||
RegisterOperand(prefix_id="z", name_id="26", shape="d"),
|
||||
RegisterOperand(prefix_id="p", name_id="0", predication="m"),
|
||||
RegisterOperand(prefix_id="z", name_id="29", shape="d"),
|
||||
RegisterOperand(prefix_id="z", name_id="21", shape="d"),
|
||||
ImmediateOperand(value_id=90, type_id="int"),
|
||||
],
|
||||
directive_id=None,
|
||||
comment_id=None,
|
||||
@@ -305,9 +305,9 @@ class TestParserAArch64(unittest.TestCase):
|
||||
instruction_form_9 = instructionForm(
|
||||
instruction_id="ccmn",
|
||||
operands_id=[
|
||||
registerOperand(prefix_id="x", name_id="11"),
|
||||
immediateOperand(value_id=1, type_id="int"),
|
||||
immediateOperand(value_id=3, type_id="int"),
|
||||
RegisterOperand(prefix_id="x", name_id="11"),
|
||||
ImmediateOperand(value_id=1, type_id="int"),
|
||||
ImmediateOperand(value_id=3, type_id="int"),
|
||||
{"condition": "EQ"},
|
||||
],
|
||||
directive_id=None,
|
||||
@@ -372,17 +372,17 @@ class TestParserAArch64(unittest.TestCase):
|
||||
instr_list_with_index = "ld4 {v0.S, v1.S, v2.S, v3.S}[2]"
|
||||
instr_range_single = "dummy { z1.d }"
|
||||
reg_list = [
|
||||
registerOperand(prefix_id="x", name_id="5"),
|
||||
registerOperand(prefix_id="x", name_id="6"),
|
||||
registerOperand(prefix_id="x", name_id="7"),
|
||||
RegisterOperand(prefix_id="x", name_id="5"),
|
||||
RegisterOperand(prefix_id="x", name_id="6"),
|
||||
RegisterOperand(prefix_id="x", name_id="7"),
|
||||
]
|
||||
reg_list_idx = [
|
||||
registerOperand(prefix_id="v", name_id="0", shape="S", index=2),
|
||||
registerOperand(prefix_id="v", name_id="1", shape="S", index=2),
|
||||
registerOperand(prefix_id="v", name_id="2", shape="S", index=2),
|
||||
registerOperand(prefix_id="v", name_id="3", shape="S", index=2),
|
||||
RegisterOperand(prefix_id="v", name_id="0", shape="S", index=2),
|
||||
RegisterOperand(prefix_id="v", name_id="1", shape="S", index=2),
|
||||
RegisterOperand(prefix_id="v", name_id="2", shape="S", index=2),
|
||||
RegisterOperand(prefix_id="v", name_id="3", shape="S", index=2),
|
||||
]
|
||||
reg_list_single = [registerOperand(prefix_id="z", name_id="1", shape="d")]
|
||||
reg_list_single = [RegisterOperand(prefix_id="z", name_id="1", shape="d")]
|
||||
|
||||
prange = self.parser.parse_line(instr_range)
|
||||
plist = self.parser.parse_line(instr_list)
|
||||
@@ -397,22 +397,22 @@ class TestParserAArch64(unittest.TestCase):
|
||||
# self.assertEqual(p_single.operands, reg_list_single)
|
||||
|
||||
def test_reg_dependency(self):
|
||||
reg_1_1 = registerOperand(prefix_id="b", name_id="1")
|
||||
reg_1_2 = registerOperand(prefix_id="h", name_id="1")
|
||||
reg_1_3 = registerOperand(prefix_id="s", name_id="1")
|
||||
reg_1_4 = registerOperand(prefix_id="d", name_id="1")
|
||||
reg_1_4 = registerOperand(prefix_id="q", name_id="1")
|
||||
reg_2_1 = registerOperand(prefix_id="w", name_id="2")
|
||||
reg_2_2 = registerOperand(prefix_id="x", name_id="2")
|
||||
reg_v1_1 = registerOperand(prefix_id="v", name_id="11", lanes="16", shape="b")
|
||||
reg_v1_2 = registerOperand(prefix_id="v", name_id="11", lanes="8", shape="h")
|
||||
reg_v1_3 = registerOperand(prefix_id="v", name_id="11", lanes="4", shape="s")
|
||||
reg_v1_4 = registerOperand(prefix_id="v", name_id="11", lanes="2", shape="d")
|
||||
reg_1_1 = RegisterOperand(prefix_id="b", name_id="1")
|
||||
reg_1_2 = RegisterOperand(prefix_id="h", name_id="1")
|
||||
reg_1_3 = RegisterOperand(prefix_id="s", name_id="1")
|
||||
reg_1_4 = RegisterOperand(prefix_id="d", name_id="1")
|
||||
reg_1_4 = RegisterOperand(prefix_id="q", name_id="1")
|
||||
reg_2_1 = RegisterOperand(prefix_id="w", name_id="2")
|
||||
reg_2_2 = RegisterOperand(prefix_id="x", name_id="2")
|
||||
reg_v1_1 = RegisterOperand(prefix_id="v", name_id="11", lanes="16", shape="b")
|
||||
reg_v1_2 = RegisterOperand(prefix_id="v", name_id="11", lanes="8", shape="h")
|
||||
reg_v1_3 = RegisterOperand(prefix_id="v", name_id="11", lanes="4", shape="s")
|
||||
reg_v1_4 = RegisterOperand(prefix_id="v", name_id="11", lanes="2", shape="d")
|
||||
|
||||
reg_b5 = registerOperand(prefix_id="b", name_id="5")
|
||||
reg_q15 = registerOperand(prefix_id="q", name_id="15")
|
||||
reg_v10 = registerOperand(prefix_id="v", name_id="10", lanes="2", shape="s")
|
||||
reg_v20 = registerOperand(prefix_id="v", name_id="20", lanes="2", shape="d")
|
||||
reg_b5 = RegisterOperand(prefix_id="b", name_id="5")
|
||||
reg_q15 = RegisterOperand(prefix_id="q", name_id="15")
|
||||
reg_v10 = RegisterOperand(prefix_id="v", name_id="10", lanes="2", shape="s")
|
||||
reg_v20 = RegisterOperand(prefix_id="v", name_id="20", lanes="2", shape="d")
|
||||
|
||||
reg_1 = [reg_1_1, reg_1_2, reg_1_3, reg_1_4]
|
||||
reg_2 = [reg_2_1, reg_2_2]
|
||||
|
||||
@@ -9,7 +9,7 @@ import unittest
|
||||
from pyparsing import ParseException
|
||||
|
||||
from osaca.parser import ParserX86ATT, instructionForm
|
||||
from osaca.parser.register import registerOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
|
||||
|
||||
class TestParserX86ATT(unittest.TestCase):
|
||||
@@ -233,10 +233,10 @@ class TestParserX86ATT(unittest.TestCase):
|
||||
register_str_3 = "%xmm1"
|
||||
register_str_4 = "%rip"
|
||||
|
||||
parsed_reg_1 = registerOperand(name_id="rax")
|
||||
parsed_reg_2 = registerOperand(name_id="r9")
|
||||
parsed_reg_3 = registerOperand(name_id="xmm1")
|
||||
parsed_reg_4 = registerOperand(name_id="rip")
|
||||
parsed_reg_1 = RegisterOperand(name_id="rax")
|
||||
parsed_reg_2 = RegisterOperand(name_id="r9")
|
||||
parsed_reg_3 = RegisterOperand(name_id="xmm1")
|
||||
parsed_reg_4 = RegisterOperand(name_id="rip")
|
||||
|
||||
self.assertEqual(self.parser.parse_register(register_str_1), parsed_reg_1)
|
||||
self.assertEqual(self.parser.parse_register(register_str_2), parsed_reg_2)
|
||||
@@ -259,22 +259,22 @@ class TestParserX86ATT(unittest.TestCase):
|
||||
)
|
||||
|
||||
def test_reg_dependency(self):
|
||||
reg_a1 = registerOperand(name_id="rax")
|
||||
reg_a2 = registerOperand(name_id="eax")
|
||||
reg_a3 = registerOperand(name_id="ax")
|
||||
reg_a4 = registerOperand(name_id="al")
|
||||
reg_r11 = registerOperand(name_id="r11")
|
||||
reg_r11b = registerOperand(name_id="r11b")
|
||||
reg_r11d = registerOperand(name_id="r11d")
|
||||
reg_r11w = registerOperand(name_id="r11w")
|
||||
reg_xmm1 = registerOperand(name_id="xmm1")
|
||||
reg_ymm1 = registerOperand(name_id="ymm1")
|
||||
reg_zmm1 = registerOperand(name_id="zmm1")
|
||||
reg_a1 = RegisterOperand(name_id="rax")
|
||||
reg_a2 = RegisterOperand(name_id="eax")
|
||||
reg_a3 = RegisterOperand(name_id="ax")
|
||||
reg_a4 = RegisterOperand(name_id="al")
|
||||
reg_r11 = RegisterOperand(name_id="r11")
|
||||
reg_r11b = RegisterOperand(name_id="r11b")
|
||||
reg_r11d = RegisterOperand(name_id="r11d")
|
||||
reg_r11w = RegisterOperand(name_id="r11w")
|
||||
reg_xmm1 = RegisterOperand(name_id="xmm1")
|
||||
reg_ymm1 = RegisterOperand(name_id="ymm1")
|
||||
reg_zmm1 = RegisterOperand(name_id="zmm1")
|
||||
|
||||
reg_b1 = registerOperand(name_id="rbx")
|
||||
reg_r15 = registerOperand(name_id="r15")
|
||||
reg_xmm2 = registerOperand(name_id="xmm2")
|
||||
reg_ymm3 = registerOperand(name_id="ymm3")
|
||||
reg_b1 = RegisterOperand(name_id="rbx")
|
||||
reg_r15 = RegisterOperand(name_id="r15")
|
||||
reg_xmm2 = RegisterOperand(name_id="xmm2")
|
||||
reg_ymm3 = RegisterOperand(name_id="ymm3")
|
||||
|
||||
reg_a = [reg_a1, reg_a2, reg_a3, reg_a4]
|
||||
reg_r = [reg_r11, reg_r11b, reg_r11d, reg_r11w]
|
||||
|
||||
@@ -19,9 +19,9 @@ from osaca.semantics import (
|
||||
MachineModel,
|
||||
reduce_to_section,
|
||||
)
|
||||
from osaca.parser.register import registerOperand
|
||||
from osaca.parser.memory import memoryOperand
|
||||
from osaca.parser.identifier import identifierOperand
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser.identifier import IdentifierOperand
|
||||
|
||||
|
||||
class TestSemanticTools(unittest.TestCase):
|
||||
@@ -94,6 +94,7 @@ class TestSemanticTools(unittest.TestCase):
|
||||
)
|
||||
cls.machine_model_zen = MachineModel(arch="zen1")
|
||||
|
||||
"""
|
||||
for i in range(len(cls.kernel_x86)):
|
||||
cls.semantics_csx.assign_src_dst(cls.kernel_x86[i])
|
||||
cls.semantics_csx.assign_tp_lt(cls.kernel_x86[i])
|
||||
@@ -103,9 +104,11 @@ class TestSemanticTools(unittest.TestCase):
|
||||
for i in range(len(cls.kernel_x86_long_LCD)):
|
||||
cls.semantics_csx.assign_src_dst(cls.kernel_x86_long_LCD[i])
|
||||
cls.semantics_csx.assign_tp_lt(cls.kernel_x86_long_LCD[i])
|
||||
|
||||
for i in range(len(cls.kernel_AArch64)):
|
||||
cls.semantics_tx2.assign_src_dst(cls.kernel_AArch64[i])
|
||||
cls.semantics_tx2.assign_tp_lt(cls.kernel_AArch64[i])
|
||||
|
||||
for i in range(len(cls.kernel_aarch64_memdep)):
|
||||
cls.semantics_tx2.assign_src_dst(cls.kernel_aarch64_memdep[i])
|
||||
cls.semantics_tx2.assign_tp_lt(cls.kernel_aarch64_memdep[i])
|
||||
@@ -115,7 +118,11 @@ class TestSemanticTools(unittest.TestCase):
|
||||
for i in range(len(cls.kernel_aarch64_deps)):
|
||||
cls.semantics_a64fx.assign_src_dst(cls.kernel_aarch64_deps[i])
|
||||
cls.semantics_a64fx.assign_tp_lt(cls.kernel_aarch64_deps[i])
|
||||
|
||||
"""
|
||||
print(cls.kernel_AArch64[2], "\n")
|
||||
cls.semantics_tx2.assign_src_dst(cls.kernel_AArch64[2])
|
||||
cls.semantics_tx2.assign_tp_lt(cls.kernel_AArch64[2])
|
||||
print(cls.kernel_AArch64[2])
|
||||
###########
|
||||
# Tests
|
||||
###########
|
||||
@@ -126,7 +133,7 @@ class TestSemanticTools(unittest.TestCase):
|
||||
ArchSemantics(tmp_mm)
|
||||
except ValueError:
|
||||
self.fail()
|
||||
|
||||
'''
|
||||
def test_machine_model_various_functions(self):
|
||||
# check dummy MachineModel creation
|
||||
try:
|
||||
@@ -148,31 +155,31 @@ class TestSemanticTools(unittest.TestCase):
|
||||
self.assertIsNone(test_mm_arm.get_instruction("NOT_IN_DB", []))
|
||||
name_x86_1 = "vaddpd"
|
||||
operands_x86_1 = [
|
||||
registerOperand(name_id="xmm"),
|
||||
registerOperand(name_id="xmm"),
|
||||
registerOperand(name_id="xmm"),
|
||||
RegisterOperand(name_id="xmm"),
|
||||
RegisterOperand(name_id="xmm"),
|
||||
RegisterOperand(name_id="xmm"),
|
||||
]
|
||||
instr_form_x86_1 = test_mm_x86.get_instruction(name_x86_1, operands_x86_1)
|
||||
self.assertEqual(instr_form_x86_1, test_mm_x86.get_instruction(name_x86_1, operands_x86_1))
|
||||
self.assertEqual(
|
||||
test_mm_x86.get_instruction("jg", [identifierOperand()]),
|
||||
test_mm_x86.get_instruction("jg", [identifierOperand()]),
|
||||
test_mm_x86.get_instruction("jg", [IdentifierOperand()]),
|
||||
test_mm_x86.get_instruction("jg", [IdentifierOperand()]),
|
||||
)
|
||||
name_arm_1 = "fadd"
|
||||
operands_arm_1 = [
|
||||
registerOperand(prefix_id="v", shape="s"),
|
||||
registerOperand(prefix_id="v", shape="s"),
|
||||
registerOperand(prefix_id="v", shape="s"),
|
||||
RegisterOperand(prefix_id="v", shape="s"),
|
||||
RegisterOperand(prefix_id="v", shape="s"),
|
||||
RegisterOperand(prefix_id="v", shape="s"),
|
||||
]
|
||||
instr_form_arm_1 = test_mm_arm.get_instruction(name_arm_1, operands_arm_1)
|
||||
self.assertEqual(instr_form_arm_1, test_mm_arm.get_instruction(name_arm_1, operands_arm_1))
|
||||
self.assertEqual(
|
||||
test_mm_arm.get_instruction("b.ne", [identifierOperand()]),
|
||||
test_mm_arm.get_instruction("b.ne", [identifierOperand()]),
|
||||
test_mm_arm.get_instruction("b.ne", [IdentifierOperand()]),
|
||||
test_mm_arm.get_instruction("b.ne", [IdentifierOperand()]),
|
||||
)
|
||||
self.assertEqual(
|
||||
test_mm_arm.get_instruction("b.someNameThatDoesNotExist", [identifierOperand()]),
|
||||
test_mm_arm.get_instruction("b.someOtherName", [identifierOperand()]),
|
||||
test_mm_arm.get_instruction("b.someNameThatDoesNotExist", [IdentifierOperand()]),
|
||||
test_mm_arm.get_instruction("b.someOtherName", [IdentifierOperand()]),
|
||||
)
|
||||
|
||||
# test full instruction name
|
||||
@@ -189,8 +196,8 @@ class TestSemanticTools(unittest.TestCase):
|
||||
# test get_store_tp
|
||||
self.assertEqual(
|
||||
test_mm_x86.get_store_throughput(
|
||||
memoryOperand(
|
||||
base_id=registerOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
|
||||
MemoryOperand(
|
||||
base_id=RegisterOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
|
||||
)
|
||||
)[0].port_pressure,
|
||||
[[2, "237"], [2, "4"]],
|
||||
@@ -198,8 +205,8 @@ class TestSemanticTools(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
test_mm_x86.get_store_throughput(
|
||||
memoryOperand(
|
||||
base_id=registerOperand(prefix_id="NOT_IN_DB"),
|
||||
MemoryOperand(
|
||||
base_id=RegisterOperand(prefix_id="NOT_IN_DB"),
|
||||
offset_ID=None,
|
||||
index_id="NOT_NONE",
|
||||
scale_id=1,
|
||||
@@ -210,8 +217,8 @@ class TestSemanticTools(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
test_mm_arm.get_store_throughput(
|
||||
memoryOperand(
|
||||
base_id=registerOperand(prefix_id="x"),
|
||||
MemoryOperand(
|
||||
base_id=RegisterOperand(prefix_id="x"),
|
||||
offset_ID=None,
|
||||
index_id=None,
|
||||
scale_id=1,
|
||||
@@ -222,8 +229,8 @@ class TestSemanticTools(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
test_mm_arm.get_store_throughput(
|
||||
memoryOperand(
|
||||
base_id=registerOperand(prefix_id="NOT_IN_DB"),
|
||||
MemoryOperand(
|
||||
base_id=RegisterOperand(prefix_id="NOT_IN_DB"),
|
||||
offset_ID=None,
|
||||
index_id=None,
|
||||
scale_id=1,
|
||||
@@ -234,16 +241,16 @@ class TestSemanticTools(unittest.TestCase):
|
||||
# test get_store_lt
|
||||
self.assertEqual(
|
||||
test_mm_x86.get_store_latency(
|
||||
memoryOperand(
|
||||
base_id=registerOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
|
||||
MemoryOperand(
|
||||
base_id=RegisterOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
|
||||
)
|
||||
),
|
||||
0,
|
||||
)
|
||||
self.assertEqual(
|
||||
test_mm_arm.get_store_latency(
|
||||
memoryOperand(
|
||||
base_id=registerOperand(prefix_id="x"),
|
||||
MemoryOperand(
|
||||
base_id=RegisterOperand(prefix_id="x"),
|
||||
offset_ID=None,
|
||||
index_id=None,
|
||||
scale_id=1,
|
||||
@@ -258,8 +265,8 @@ class TestSemanticTools(unittest.TestCase):
|
||||
# test default load tp
|
||||
self.assertEqual(
|
||||
test_mm_x86.get_load_throughput(
|
||||
memoryOperand(
|
||||
base_id=registerOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
|
||||
MemoryOperand(
|
||||
base_id=RegisterOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
|
||||
)
|
||||
)[0].port_pressure,
|
||||
[[1, "23"], [1, ["2D", "3D"]]],
|
||||
@@ -310,391 +317,397 @@ class TestSemanticTools(unittest.TestCase):
|
||||
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
|
||||
kernel_fixed = deepcopy(self.kernel_x86)
|
||||
self.semantics_csx.add_semantics(kernel_fixed)
|
||||
self.assertEqual(get_unmatched_instruction_ratio(kernel_fixed), 0)
|
||||
"""
|
||||
# x86
|
||||
kernel_fixed = deepcopy(self.kernel_x86)
|
||||
self.semantics_csx.add_semantics(kernel_fixed)
|
||||
self.assertEqual(get_unmatched_instruction_ratio(kernel_fixed), 0)
|
||||
|
||||
kernel_optimal = deepcopy(kernel_fixed)
|
||||
self.semantics_csx.assign_optimal_throughput(kernel_optimal)
|
||||
tp_fixed = self.semantics_csx.get_throughput_sum(kernel_fixed)
|
||||
tp_optimal = self.semantics_csx.get_throughput_sum(kernel_optimal)
|
||||
self.assertNotEqual(tp_fixed, tp_optimal)
|
||||
self.assertTrue(max(tp_optimal) <= max(tp_fixed))
|
||||
# test multiple port assignment options
|
||||
test_mm_x86 = MachineModel(path_to_yaml=self._find_file("test_db_x86.yml"))
|
||||
tmp_semantics = ArchSemantics(test_mm_x86)
|
||||
tmp_code_1 = "fantasyinstr1 %rax, %rax\n"
|
||||
tmp_code_2 = "fantasyinstr1 %rax, %rax\nfantasyinstr2 %rbx, %rbx\n"
|
||||
tmp_kernel_1 = self.parser_x86.parse_file(tmp_code_1)
|
||||
tmp_kernel_2 = self.parser_x86.parse_file(tmp_code_2)
|
||||
tmp_semantics.add_semantics(tmp_kernel_1)
|
||||
tmp_semantics.add_semantics(tmp_kernel_2)
|
||||
tmp_semantics.assign_optimal_throughput(tmp_kernel_1)
|
||||
tmp_semantics.assign_optimal_throughput(tmp_kernel_2)
|
||||
k1i1_pp = [round(x, 2) for x in tmp_kernel_1[0]["port_pressure"]]
|
||||
k2i1_pp = [round(x, 2) for x in tmp_kernel_2[0]["port_pressure"]]
|
||||
self.assertEqual(k1i1_pp, [0.33, 0.0, 0.33, 0.0, 0.0, 0.0, 0.0, 0.0, 0.33, 0.0, 0.0])
|
||||
self.assertEqual(k2i1_pp, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0])
|
||||
kernel_optimal = deepcopy(kernel_fixed)
|
||||
self.semantics_csx.assign_optimal_throughput(kernel_optimal)
|
||||
tp_fixed = self.semantics_csx.get_throughput_sum(kernel_fixed)
|
||||
tp_optimal = self.semantics_csx.get_throughput_sum(kernel_optimal)
|
||||
self.assertNotEqual(tp_fixed, tp_optimal)
|
||||
self.assertTrue(max(tp_optimal) <= max(tp_fixed))
|
||||
# test multiple port assignment options
|
||||
test_mm_x86 = MachineModel(path_to_yaml=self._find_file("test_db_x86.yml"))
|
||||
tmp_semantics = ArchSemantics(test_mm_x86)
|
||||
tmp_code_1 = "fantasyinstr1 %rax, %rax\n"
|
||||
tmp_code_2 = "fantasyinstr1 %rax, %rax\nfantasyinstr2 %rbx, %rbx\n"
|
||||
tmp_kernel_1 = self.parser_x86.parse_file(tmp_code_1)
|
||||
tmp_kernel_2 = self.parser_x86.parse_file(tmp_code_2)
|
||||
tmp_semantics.add_semantics(tmp_kernel_1)
|
||||
tmp_semantics.add_semantics(tmp_kernel_2)
|
||||
tmp_semantics.assign_optimal_throughput(tmp_kernel_1)
|
||||
tmp_semantics.assign_optimal_throughput(tmp_kernel_2)
|
||||
k1i1_pp = [round(x, 2) for x in tmp_kernel_1[0].port_pressure]
|
||||
k2i1_pp = [round(x, 2) for x in tmp_kernel_2[0].port_pressure]
|
||||
self.assertEqual(k1i1_pp, [0.33, 0.0, 0.33, 0.0, 0.0, 0.0, 0.0, 0.0, 0.33, 0.0, 0.0])
|
||||
self.assertEqual(k2i1_pp, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0])
|
||||
|
||||
# arm
|
||||
kernel_fixed = deepcopy(self.kernel_AArch64)
|
||||
self.semantics_tx2.add_semantics(kernel_fixed)
|
||||
self.assertEqual(get_unmatched_instruction_ratio(kernel_fixed), 0)
|
||||
kernel_optimal = deepcopy(kernel_fixed)
|
||||
self.semantics_tx2.assign_optimal_throughput(kernel_optimal)
|
||||
tp_fixed = self.semantics_tx2.get_throughput_sum(kernel_fixed)
|
||||
tp_optimal = self.semantics_tx2.get_throughput_sum(kernel_optimal)
|
||||
self.assertNotEqual(tp_fixed, tp_optimal)
|
||||
self.assertTrue(max(tp_optimal) <= max(tp_fixed))
|
||||
# arm
|
||||
kernel_fixed = deepcopy(self.kernel_AArch64)
|
||||
|
||||
def test_kernelDG_x86(self):
|
||||
#
|
||||
# 4
|
||||
# \___>6__>7
|
||||
# /
|
||||
# 3
|
||||
# 5_______>9
|
||||
#
|
||||
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
|
||||
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=3))), 1)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=3)), 6)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=4))), 1)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=4)), 6)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=5))), 1)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=5)), 9)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=6))), 1)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=6)), 7)
|
||||
self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=7)), [])
|
||||
self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=8)), [])
|
||||
with self.assertRaises(ValueError):
|
||||
dg.get_dependent_instruction_forms()
|
||||
# test dot creation
|
||||
dg.export_graph(filepath="/dev/null")
|
||||
self.semantics_tx2.add_semantics(kernel_fixed)
|
||||
|
||||
def test_memdependency_x86(self):
|
||||
dg = KernelDG(
|
||||
self.kernel_x86_memdep,
|
||||
self.parser_x86,
|
||||
self.machine_model_csx,
|
||||
self.semantics_csx,
|
||||
)
|
||||
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=3)), {6, 8})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=5)), {10, 12})
|
||||
with self.assertRaises(ValueError):
|
||||
dg.get_dependent_instruction_forms()
|
||||
# test dot creation
|
||||
dg.export_graph(filepath="/dev/null")
|
||||
self.assertEqual(get_unmatched_instruction_ratio(kernel_fixed), 0)
|
||||
|
||||
def test_kernelDG_AArch64(self):
|
||||
dg = KernelDG(
|
||||
self.kernel_AArch64,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_tx2,
|
||||
self.semantics_tx2,
|
||||
)
|
||||
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=3)), {7, 8})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=4)), {9, 10})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=5)), {6, 7, 8})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=6)), {9, 10})
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=7)), 13)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=8)), 14)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=9)), 16)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=10)), 17)
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=11)), {13, 14})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=12)), {16, 17})
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=13)), 15)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=14)), 15)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=15))), 0)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=16)), 18)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=17)), 18)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=18))), 0)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=19))), 0)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=20))), 0)
|
||||
with self.assertRaises(ValueError):
|
||||
dg.get_dependent_instruction_forms()
|
||||
# test dot creation
|
||||
dg.export_graph(filepath="/dev/null")
|
||||
kernel_optimal = deepcopy(kernel_fixed)
|
||||
self.semantics_tx2.assign_optimal_throughput(kernel_optimal)
|
||||
tp_fixed = self.semantics_tx2.get_throughput_sum(kernel_fixed)
|
||||
tp_optimal = self.semantics_tx2.get_throughput_sum(kernel_optimal)
|
||||
self.assertNotEqual(tp_fixed, tp_optimal)
|
||||
self.assertTrue(max(tp_optimal) <= max(tp_fixed))
|
||||
|
||||
def test_kernelDG_SVE(self):
|
||||
KernelDG(
|
||||
self.kernel_aarch64_SVE,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_a64fx,
|
||||
self.semantics_a64fx,
|
||||
)
|
||||
# TODO check for correct analysis
|
||||
def test_kernelDG_x86(self):
|
||||
#
|
||||
# 4
|
||||
# \___>6__>7
|
||||
# /
|
||||
# 3
|
||||
# 5_______>9
|
||||
#
|
||||
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
|
||||
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=3))), 1)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=3)), 6)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=4))), 1)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=4)), 6)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=5))), 1)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=5)), 9)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=6))), 1)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=6)), 7)
|
||||
self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=7)), [])
|
||||
self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=8)), [])
|
||||
with self.assertRaises(ValueError):
|
||||
dg.get_dependent_instruction_forms()
|
||||
# test dot creation
|
||||
dg.export_graph(filepath="/dev/null")
|
||||
|
||||
def test_hidden_load(self):
|
||||
machine_model_hld = MachineModel(
|
||||
path_to_yaml=self._find_file("hidden_load_machine_model.yml")
|
||||
)
|
||||
self.assertTrue(machine_model_hld.has_hidden_loads())
|
||||
semantics_hld = ArchSemantics(machine_model_hld)
|
||||
kernel_hld = self.parser_x86.parse_file(self.code_x86)
|
||||
kernel_hld_2 = self.parser_x86.parse_file(self.code_x86)
|
||||
kernel_hld_2 = self.parser_x86.parse_file(self.code_x86)[-3:]
|
||||
kernel_hld_3 = self.parser_x86.parse_file(self.code_x86)[5:8]
|
||||
|
||||
semantics_hld.add_semantics(kernel_hld)
|
||||
semantics_hld.add_semantics(kernel_hld_2)
|
||||
semantics_hld.add_semantics(kernel_hld_3)
|
||||
|
||||
num_hidden_loads = len([x for x in kernel_hld if INSTR_flags.HIDDEN_LD in x.flags])
|
||||
num_hidden_loads_2 = len([x for x in kernel_hld_2 if INSTR_flags.HIDDEN_LD in x.flags])
|
||||
num_hidden_loads_3 = len([x for x in kernel_hld_3 if INSTR_flags.HIDDEN_LD in x.flags])
|
||||
self.assertEqual(num_hidden_loads, 1)
|
||||
self.assertEqual(num_hidden_loads_2, 0)
|
||||
self.assertEqual(num_hidden_loads_3, 1)
|
||||
|
||||
def test_cyclic_dag(self):
|
||||
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
|
||||
dg.dg.add_edge(100, 101, latency=1.0)
|
||||
dg.dg.add_edge(101, 102, latency=2.0)
|
||||
dg.dg.add_edge(102, 100, latency=3.0)
|
||||
with self.assertRaises(NotImplementedError):
|
||||
dg.get_critical_path()
|
||||
with self.assertRaises(NotImplementedError):
|
||||
dg.get_loopcarried_dependencies()
|
||||
|
||||
def test_loop_carried_dependency_aarch64(self):
|
||||
dg = KernelDG(
|
||||
self.kernel_aarch64_memdep,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_tx2,
|
||||
self.semantics_tx2,
|
||||
)
|
||||
lc_deps = dg.get_loopcarried_dependencies()
|
||||
self.assertEqual(len(lc_deps), 4)
|
||||
# based on line 6
|
||||
dep_path = "6-10-11-12-13-14"
|
||||
self.assertEqual(lc_deps[dep_path]["latency"], 29.0)
|
||||
self.assertEqual(
|
||||
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
|
||||
[(6, 4.0), (10, 6.0), (11, 6.0), (12, 6.0), (13, 6.0), (14, 1.0)],
|
||||
)
|
||||
dg = KernelDG(
|
||||
self.kernel_aarch64_deps,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_a64fx,
|
||||
self.semantics_a64fx,
|
||||
flag_dependencies=True,
|
||||
)
|
||||
lc_deps = dg.get_loopcarried_dependencies()
|
||||
self.assertEqual(len(lc_deps), 2)
|
||||
# based on line 4
|
||||
dep_path = "4-5-6-9-10-11-12"
|
||||
self.assertEqual(lc_deps[dep_path]["latency"], 7.0)
|
||||
self.assertEqual(
|
||||
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
|
||||
[(4, 1.0), (5, 1.0), (6, 1.0), (9, 1.0), (10, 1.0), (11, 1.0), (12, 1.0)],
|
||||
)
|
||||
dg = KernelDG(
|
||||
self.kernel_aarch64_deps,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_a64fx,
|
||||
self.semantics_a64fx,
|
||||
flag_dependencies=False,
|
||||
)
|
||||
lc_deps = dg.get_loopcarried_dependencies()
|
||||
self.assertEqual(len(lc_deps), 1)
|
||||
# based on line 4
|
||||
dep_path = "4-5-10-11-12"
|
||||
self.assertEqual(lc_deps[dep_path]["latency"], 5.0)
|
||||
self.assertEqual(
|
||||
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
|
||||
[(4, 1.0), (5, 1.0), (10, 1.0), (11, 1.0), (12, 1.0)],
|
||||
)
|
||||
|
||||
def test_loop_carried_dependency_x86(self):
|
||||
lcd_id = "8"
|
||||
lcd_id2 = "5"
|
||||
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
|
||||
lc_deps = dg.get_loopcarried_dependencies()
|
||||
# self.assertEqual(len(lc_deps), 2)
|
||||
# ID 8
|
||||
self.assertEqual(
|
||||
lc_deps[lcd_id]["root"], dg.dg.nodes(data=True)[int(lcd_id)]["instruction_form"]
|
||||
)
|
||||
self.assertEqual(len(lc_deps[lcd_id]["dependencies"]), 1)
|
||||
self.assertEqual(
|
||||
lc_deps[lcd_id]["dependencies"][0][0],
|
||||
dg.dg.nodes(data=True)[int(lcd_id)]["instruction_form"],
|
||||
)
|
||||
# w/ flag dependencies: ID 9 w/ len=2
|
||||
# w/o flag dependencies: ID 5 w/ len=1
|
||||
# TODO discuss
|
||||
self.assertEqual(
|
||||
lc_deps[lcd_id2]["root"],
|
||||
dg.dg.nodes(data=True)[int(lcd_id2)]["instruction_form"],
|
||||
)
|
||||
self.assertEqual(len(lc_deps[lcd_id2]["dependencies"]), 1)
|
||||
self.assertEqual(
|
||||
lc_deps[lcd_id2]["dependencies"][0][0],
|
||||
dg.dg.nodes(data=True)[int(lcd_id2)]["instruction_form"],
|
||||
)
|
||||
|
||||
def test_timeout_during_loop_carried_dependency(self):
|
||||
start_time = time.perf_counter()
|
||||
KernelDG(
|
||||
self.kernel_x86_long_LCD,
|
||||
self.parser_x86,
|
||||
self.machine_model_csx,
|
||||
self.semantics_x86,
|
||||
timeout=10,
|
||||
)
|
||||
end_time = time.perf_counter()
|
||||
time_10 = end_time - start_time
|
||||
start_time = time.perf_counter()
|
||||
KernelDG(
|
||||
self.kernel_x86_long_LCD,
|
||||
self.parser_x86,
|
||||
self.machine_model_csx,
|
||||
self.semantics_x86,
|
||||
timeout=2,
|
||||
)
|
||||
end_time = time.perf_counter()
|
||||
time_2 = end_time - start_time
|
||||
|
||||
# self.assertTrue(time_10 > 10)
|
||||
self.assertTrue(2 < time_2)
|
||||
# self.assertTrue(time_2 < (time_10 - 7))
|
||||
|
||||
def test_is_read_is_written_x86(self):
|
||||
# independent form HW model
|
||||
dag = KernelDG(self.kernel_x86, self.parser_x86, None, None)
|
||||
reg_rcx = registerOperand(name_id="rcx")
|
||||
reg_ymm1 = registerOperand(name_id="ymm1")
|
||||
|
||||
instr_form_r_c = self.parser_x86.parse_line("vmovsd %xmm0, (%r15,%rcx,8)")
|
||||
self.semantics_csx.assign_src_dst(instr_form_r_c)
|
||||
instr_form_non_r_c = self.parser_x86.parse_line("movl %xmm0, (%r15,%rax,8)")
|
||||
self.semantics_csx.assign_src_dst(instr_form_non_r_c)
|
||||
instr_form_w_c = self.parser_x86.parse_line("movi $0x05ACA, %rcx")
|
||||
self.semantics_csx.assign_src_dst(instr_form_w_c)
|
||||
|
||||
instr_form_rw_ymm_1 = self.parser_x86.parse_line("vinsertf128 $0x1, %xmm1, %ymm0, %ymm1")
|
||||
self.semantics_csx.assign_src_dst(instr_form_rw_ymm_1)
|
||||
instr_form_rw_ymm_2 = self.parser_x86.parse_line("vinsertf128 $0x1, %xmm0, %ymm1, %ymm1")
|
||||
self.semantics_csx.assign_src_dst(instr_form_rw_ymm_2)
|
||||
instr_form_r_ymm = self.parser_x86.parse_line("vmovapd %ymm1, %ymm0")
|
||||
self.semantics_csx.assign_src_dst(instr_form_r_ymm)
|
||||
self.assertTrue(dag.is_read(reg_rcx, instr_form_r_c))
|
||||
self.assertFalse(dag.is_read(reg_rcx, instr_form_non_r_c))
|
||||
self.assertFalse(dag.is_read(reg_rcx, instr_form_w_c))
|
||||
self.assertTrue(dag.is_written(reg_rcx, instr_form_w_c))
|
||||
self.assertFalse(dag.is_written(reg_rcx, instr_form_r_c))
|
||||
self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_1))
|
||||
self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_2))
|
||||
self.assertTrue(dag.is_read(reg_ymm1, instr_form_r_ymm))
|
||||
self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_1))
|
||||
self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_2))
|
||||
self.assertFalse(dag.is_written(reg_ymm1, instr_form_r_ymm))
|
||||
|
||||
def test_is_read_is_written_AArch64(self):
|
||||
# independent form HW model
|
||||
dag = KernelDG(self.kernel_AArch64, self.parser_AArch64, None, None)
|
||||
reg_x1 = registerOperand(prefix_id="x", name_id="1")
|
||||
reg_w1 = registerOperand(prefix_id="w", name_id="1")
|
||||
reg_d1 = registerOperand(prefix_id="d", name_id="1")
|
||||
reg_q1 = registerOperand(prefix_id="q", name_id="1")
|
||||
reg_v1 = registerOperand(prefix_id="v", name_id="1", lanes="2", shape="d")
|
||||
regs = [reg_d1, reg_q1, reg_v1]
|
||||
regs_gp = [reg_w1, reg_x1]
|
||||
|
||||
instr_form_r_1 = self.parser_AArch64.parse_line("stp q1, q3, [x12, #192]")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_r_1)
|
||||
instr_form_r_2 = self.parser_AArch64.parse_line("fadd v2.2d, v1.2d, v0.2d")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_r_2)
|
||||
instr_form_w_1 = self.parser_AArch64.parse_line("ldr d1, [x1, #:got_lo12:q2c]")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_w_1)
|
||||
instr_form_non_w_1 = self.parser_AArch64.parse_line("ldr x1, [x1, #:got_lo12:q2c]")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_non_w_1)
|
||||
instr_form_rw_1 = self.parser_AArch64.parse_line("fmul v1.2d, v1.2d, v0.2d")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_1)
|
||||
instr_form_rw_2 = self.parser_AArch64.parse_line("ldp q2, q4, [x1, #64]!")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_2)
|
||||
instr_form_rw_3 = self.parser_AArch64.parse_line("str x4, [x1], #64")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_3)
|
||||
instr_form_non_rw_1 = self.parser_AArch64.parse_line("adds x1, x11")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_non_rw_1)
|
||||
|
||||
for reg in regs:
|
||||
with self.subTest(reg=reg):
|
||||
# self.assertTrue(dag.is_read(reg, instr_form_r_1))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_r_2))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_rw_1))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_rw_2))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_rw_3))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_w_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_w_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_rw_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_non_w_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_rw_2))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_rw_3))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
|
||||
|
||||
for reg in regs_gp:
|
||||
with self.subTest(reg=reg):
|
||||
self.assertFalse(dag.is_read(reg, instr_form_r_1))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_r_2))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_rw_1))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_rw_2))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_rw_3))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_w_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_w_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_rw_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_non_w_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_rw_2))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_rw_3))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
|
||||
|
||||
def test_invalid_MachineModel(self):
|
||||
with self.assertRaises(ValueError):
|
||||
MachineModel()
|
||||
with self.assertRaises(ValueError):
|
||||
MachineModel(arch="CSX", path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "csx.yml"))
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
MachineModel(arch="THE_MACHINE")
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
MachineModel(path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "THE_MACHINE.yml"))
|
||||
|
||||
def test_MachineModel_getter(self):
|
||||
sample_operands = [
|
||||
memoryOperand(
|
||||
offset_ID=None,
|
||||
base_id=registerOperand(name_id="r12"),
|
||||
index_id=registerOperand(name_id="rcx"),
|
||||
scale_id=8,
|
||||
def test_memdependency_x86(self):
|
||||
dg = KernelDG(
|
||||
self.kernel_x86_memdep,
|
||||
self.parser_x86,
|
||||
self.machine_model_csx,
|
||||
self.semantics_csx,
|
||||
)
|
||||
]
|
||||
self.assertIsNone(self.machine_model_csx.get_instruction("GETRESULT", sample_operands))
|
||||
self.assertIsNone(self.machine_model_tx2.get_instruction("GETRESULT", sample_operands))
|
||||
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=3)), {6, 8})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=5)), {10, 12})
|
||||
with self.assertRaises(ValueError):
|
||||
dg.get_dependent_instruction_forms()
|
||||
# test dot creation
|
||||
dg.export_graph(filepath="/dev/null")
|
||||
|
||||
self.assertEqual(self.machine_model_csx.get_arch(), "csx")
|
||||
self.assertEqual(self.machine_model_tx2.get_arch(), "tx2")
|
||||
def test_kernelDG_AArch64(self):
|
||||
dg = KernelDG(
|
||||
self.kernel_AArch64,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_tx2,
|
||||
self.semantics_tx2,
|
||||
)
|
||||
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=3)), {7, 8})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=4)), {9, 10})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=5)), {6, 7, 8})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=6)), {9, 10})
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=7)), 13)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=8)), 14)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=9)), 16)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=10)), 17)
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=11)), {13, 14})
|
||||
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=12)), {16, 17})
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=13)), 15)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=14)), 15)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=15))), 0)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=16)), 18)
|
||||
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=17)), 18)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=18))), 0)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=19))), 0)
|
||||
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=20))), 0)
|
||||
with self.assertRaises(ValueError):
|
||||
dg.get_dependent_instruction_forms()
|
||||
# test dot creation
|
||||
dg.export_graph(filepath="/dev/null")
|
||||
|
||||
self.assertEqual(self.machine_model_csx.get_ISA(), "x86")
|
||||
self.assertEqual(self.machine_model_tx2.get_ISA(), "aarch64")
|
||||
def test_kernelDG_SVE(self):
|
||||
KernelDG(
|
||||
self.kernel_aarch64_SVE,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_a64fx,
|
||||
self.semantics_a64fx,
|
||||
)
|
||||
# TODO check for correct analysis
|
||||
|
||||
ports_csx = ["0", "0DV", "1", "2", "2D", "3", "3D", "4", "5", "6", "7"]
|
||||
data_ports_csx = ["2D", "3D"]
|
||||
self.assertEqual(self.machine_model_csx.get_ports(), ports_csx)
|
||||
self.assertEqual(self.machine_model_csx.get_data_ports(), data_ports_csx)
|
||||
def test_hidden_load(self):
|
||||
machine_model_hld = MachineModel(
|
||||
path_to_yaml=self._find_file("hidden_load_machine_model.yml")
|
||||
)
|
||||
self.assertTrue(machine_model_hld.has_hidden_loads())
|
||||
semantics_hld = ArchSemantics(machine_model_hld)
|
||||
kernel_hld = self.parser_x86.parse_file(self.code_x86)
|
||||
kernel_hld_2 = self.parser_x86.parse_file(self.code_x86)
|
||||
kernel_hld_2 = self.parser_x86.parse_file(self.code_x86)[-3:]
|
||||
kernel_hld_3 = self.parser_x86.parse_file(self.code_x86)[5:8]
|
||||
|
||||
self.assertFalse(self.machine_model_tx2.has_hidden_loads())
|
||||
semantics_hld.add_semantics(kernel_hld)
|
||||
semantics_hld.add_semantics(kernel_hld_2)
|
||||
semantics_hld.add_semantics(kernel_hld_3)
|
||||
|
||||
self.assertEqual(MachineModel.get_isa_for_arch("CSX"), "x86")
|
||||
self.assertEqual(MachineModel.get_isa_for_arch("tX2"), "aarch64")
|
||||
with self.assertRaises(ValueError):
|
||||
self.assertIsNone(MachineModel.get_isa_for_arch("THE_MACHINE"))
|
||||
num_hidden_loads = len([x for x in kernel_hld if INSTR_flags.HIDDEN_LD in x.flags])
|
||||
num_hidden_loads_2 = len([x for x in kernel_hld_2 if INSTR_flags.HIDDEN_LD in x.flags])
|
||||
num_hidden_loads_3 = len([x for x in kernel_hld_3 if INSTR_flags.HIDDEN_LD in x.flags])
|
||||
self.assertEqual(num_hidden_loads, 1)
|
||||
self.assertEqual(num_hidden_loads_2, 0)
|
||||
self.assertEqual(num_hidden_loads_3, 1)
|
||||
|
||||
def test_cyclic_dag(self):
|
||||
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
|
||||
dg.dg.add_edge(100, 101, latency=1.0)
|
||||
dg.dg.add_edge(101, 102, latency=2.0)
|
||||
dg.dg.add_edge(102, 100, latency=3.0)
|
||||
with self.assertRaises(NotImplementedError):
|
||||
dg.get_critical_path()
|
||||
with self.assertRaises(NotImplementedError):
|
||||
dg.get_loopcarried_dependencies()
|
||||
|
||||
def test_loop_carried_dependency_aarch64(self):
|
||||
dg = KernelDG(
|
||||
self.kernel_aarch64_memdep,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_tx2,
|
||||
self.semantics_tx2,
|
||||
)
|
||||
lc_deps = dg.get_loopcarried_dependencies()
|
||||
self.assertEqual(len(lc_deps), 4)
|
||||
# based on line 6
|
||||
dep_path = "6-10-11-12-13-14"
|
||||
self.assertEqual(lc_deps[dep_path]["latency"], 29.0)
|
||||
self.assertEqual(
|
||||
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
|
||||
[(6, 4.0), (10, 6.0), (11, 6.0), (12, 6.0), (13, 6.0), (14, 1.0)],
|
||||
)
|
||||
dg = KernelDG(
|
||||
self.kernel_aarch64_deps,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_a64fx,
|
||||
self.semantics_a64fx,
|
||||
flag_dependencies=True,
|
||||
)
|
||||
lc_deps = dg.get_loopcarried_dependencies()
|
||||
self.assertEqual(len(lc_deps), 2)
|
||||
# based on line 4
|
||||
dep_path = "4-5-6-9-10-11-12"
|
||||
self.assertEqual(lc_deps[dep_path]["latency"], 7.0)
|
||||
self.assertEqual(
|
||||
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
|
||||
[(4, 1.0), (5, 1.0), (6, 1.0), (9, 1.0), (10, 1.0), (11, 1.0), (12, 1.0)],
|
||||
)
|
||||
dg = KernelDG(
|
||||
self.kernel_aarch64_deps,
|
||||
self.parser_AArch64,
|
||||
self.machine_model_a64fx,
|
||||
self.semantics_a64fx,
|
||||
flag_dependencies=False,
|
||||
)
|
||||
lc_deps = dg.get_loopcarried_dependencies()
|
||||
self.assertEqual(len(lc_deps), 1)
|
||||
# based on line 4
|
||||
dep_path = "4-5-10-11-12"
|
||||
self.assertEqual(lc_deps[dep_path]["latency"], 5.0)
|
||||
self.assertEqual(
|
||||
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
|
||||
[(4, 1.0), (5, 1.0), (10, 1.0), (11, 1.0), (12, 1.0)],
|
||||
)
|
||||
|
||||
def test_loop_carried_dependency_x86(self):
|
||||
lcd_id = "8"
|
||||
lcd_id2 = "5"
|
||||
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
|
||||
lc_deps = dg.get_loopcarried_dependencies()
|
||||
# self.assertEqual(len(lc_deps), 2)
|
||||
# ID 8
|
||||
self.assertEqual(
|
||||
lc_deps[lcd_id]["root"], dg.dg.nodes(data=True)[int(lcd_id)]["instruction_form"]
|
||||
)
|
||||
self.assertEqual(len(lc_deps[lcd_id]["dependencies"]), 1)
|
||||
self.assertEqual(
|
||||
lc_deps[lcd_id]["dependencies"][0][0],
|
||||
dg.dg.nodes(data=True)[int(lcd_id)]["instruction_form"],
|
||||
)
|
||||
# w/ flag dependencies: ID 9 w/ len=2
|
||||
# w/o flag dependencies: ID 5 w/ len=1
|
||||
# TODO discuss
|
||||
self.assertEqual(
|
||||
lc_deps[lcd_id2]["root"],
|
||||
dg.dg.nodes(data=True)[int(lcd_id2)]["instruction_form"],
|
||||
)
|
||||
self.assertEqual(len(lc_deps[lcd_id2]["dependencies"]), 1)
|
||||
self.assertEqual(
|
||||
lc_deps[lcd_id2]["dependencies"][0][0],
|
||||
dg.dg.nodes(data=True)[int(lcd_id2)]["instruction_form"],
|
||||
)
|
||||
|
||||
def test_timeout_during_loop_carried_dependency(self):
|
||||
start_time = time.perf_counter()
|
||||
KernelDG(
|
||||
self.kernel_x86_long_LCD,
|
||||
self.parser_x86,
|
||||
self.machine_model_csx,
|
||||
self.semantics_x86,
|
||||
timeout=10,
|
||||
)
|
||||
end_time = time.perf_counter()
|
||||
time_10 = end_time - start_time
|
||||
start_time = time.perf_counter()
|
||||
KernelDG(
|
||||
self.kernel_x86_long_LCD,
|
||||
self.parser_x86,
|
||||
self.machine_model_csx,
|
||||
self.semantics_x86,
|
||||
timeout=2,
|
||||
)
|
||||
end_time = time.perf_counter()
|
||||
time_2 = end_time - start_time
|
||||
|
||||
# self.assertTrue(time_10 > 10)
|
||||
self.assertTrue(2 < time_2)
|
||||
# self.assertTrue(time_2 < (time_10 - 7))
|
||||
|
||||
def test_is_read_is_written_x86(self):
|
||||
# independent form HW model
|
||||
dag = KernelDG(self.kernel_x86, self.parser_x86, None, None)
|
||||
reg_rcx = RegisterOperand(name_id="rcx")
|
||||
reg_ymm1 = RegisterOperand(name_id="ymm1")
|
||||
|
||||
instr_form_r_c = self.parser_x86.parse_line("vmovsd %xmm0, (%r15,%rcx,8)")
|
||||
self.semantics_csx.assign_src_dst(instr_form_r_c)
|
||||
instr_form_non_r_c = self.parser_x86.parse_line("movl %xmm0, (%r15,%rax,8)")
|
||||
self.semantics_csx.assign_src_dst(instr_form_non_r_c)
|
||||
instr_form_w_c = self.parser_x86.parse_line("movi $0x05ACA, %rcx")
|
||||
self.semantics_csx.assign_src_dst(instr_form_w_c)
|
||||
|
||||
instr_form_rw_ymm_1 = self.parser_x86.parse_line("vinsertf128 $0x1, %xmm1, %ymm0, %ymm1")
|
||||
self.semantics_csx.assign_src_dst(instr_form_rw_ymm_1)
|
||||
instr_form_rw_ymm_2 = self.parser_x86.parse_line("vinsertf128 $0x1, %xmm0, %ymm1, %ymm1")
|
||||
self.semantics_csx.assign_src_dst(instr_form_rw_ymm_2)
|
||||
instr_form_r_ymm = self.parser_x86.parse_line("vmovapd %ymm1, %ymm0")
|
||||
self.semantics_csx.assign_src_dst(instr_form_r_ymm)
|
||||
self.assertTrue(dag.is_read(reg_rcx, instr_form_r_c))
|
||||
self.assertFalse(dag.is_read(reg_rcx, instr_form_non_r_c))
|
||||
self.assertFalse(dag.is_read(reg_rcx, instr_form_w_c))
|
||||
self.assertTrue(dag.is_written(reg_rcx, instr_form_w_c))
|
||||
self.assertFalse(dag.is_written(reg_rcx, instr_form_r_c))
|
||||
self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_1))
|
||||
self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_2))
|
||||
self.assertTrue(dag.is_read(reg_ymm1, instr_form_r_ymm))
|
||||
self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_1))
|
||||
self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_2))
|
||||
self.assertFalse(dag.is_written(reg_ymm1, instr_form_r_ymm))
|
||||
|
||||
def test_is_read_is_written_AArch64(self):
|
||||
# independent form HW model
|
||||
dag = KernelDG(self.kernel_AArch64, self.parser_AArch64, None, None)
|
||||
reg_x1 = RegisterOperand(prefix_id="x", name_id="1")
|
||||
reg_w1 = RegisterOperand(prefix_id="w", name_id="1")
|
||||
reg_d1 = RegisterOperand(prefix_id="d", name_id="1")
|
||||
reg_q1 = RegisterOperand(prefix_id="q", name_id="1")
|
||||
reg_v1 = RegisterOperand(prefix_id="v", name_id="1", lanes="2", shape="d")
|
||||
regs = [reg_d1, reg_q1, reg_v1]
|
||||
regs_gp = [reg_w1, reg_x1]
|
||||
|
||||
instr_form_r_1 = self.parser_AArch64.parse_line("stp q1, q3, [x12, #192]")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_r_1)
|
||||
instr_form_r_2 = self.parser_AArch64.parse_line("fadd v2.2d, v1.2d, v0.2d")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_r_2)
|
||||
instr_form_w_1 = self.parser_AArch64.parse_line("ldr d1, [x1, #:got_lo12:q2c]")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_w_1)
|
||||
instr_form_non_w_1 = self.parser_AArch64.parse_line("ldr x1, [x1, #:got_lo12:q2c]")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_non_w_1)
|
||||
instr_form_rw_1 = self.parser_AArch64.parse_line("fmul v1.2d, v1.2d, v0.2d")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_1)
|
||||
instr_form_rw_2 = self.parser_AArch64.parse_line("ldp q2, q4, [x1, #64]!")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_2)
|
||||
instr_form_rw_3 = self.parser_AArch64.parse_line("str x4, [x1], #64")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_3)
|
||||
instr_form_non_rw_1 = self.parser_AArch64.parse_line("adds x1, x11")
|
||||
self.semantics_tx2.assign_src_dst(instr_form_non_rw_1)
|
||||
|
||||
for reg in regs:
|
||||
with self.subTest(reg=reg):
|
||||
self.assertTrue(dag.is_read(reg, instr_form_r_1))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_r_2))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_rw_1))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_rw_2))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_rw_3))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_w_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_w_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_rw_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_non_w_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_rw_2))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_rw_3))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
|
||||
|
||||
for reg in regs_gp:
|
||||
with self.subTest(reg=reg):
|
||||
self.assertFalse(dag.is_read(reg, instr_form_r_1))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_r_2))
|
||||
self.assertFalse(dag.is_read(reg, instr_form_rw_1))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_rw_2))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_rw_3))
|
||||
self.assertTrue(dag.is_read(reg, instr_form_w_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_w_1))
|
||||
self.assertFalse(dag.is_written(reg, instr_form_rw_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_non_w_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_rw_2))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_rw_3))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
|
||||
self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
|
||||
|
||||
def test_invalid_MachineModel(self):
|
||||
with self.assertRaises(ValueError):
|
||||
MachineModel()
|
||||
with self.assertRaises(ValueError):
|
||||
MachineModel(arch="CSX", path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "csx.yml"))
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
MachineModel(arch="THE_MACHINE")
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
MachineModel(path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "THE_MACHINE.yml"))
|
||||
|
||||
def test_MachineModel_getter(self):
|
||||
sample_operands = [
|
||||
MemoryOperand(
|
||||
offset_ID=None,
|
||||
base_id=RegisterOperand(name_id="r12"),
|
||||
index_id=RegisterOperand(name_id="rcx"),
|
||||
scale_id=8,
|
||||
)
|
||||
]
|
||||
self.assertIsNone(self.machine_model_csx.get_instruction("GETRESULT", sample_operands))
|
||||
self.assertIsNone(self.machine_model_tx2.get_instruction("GETRESULT", sample_operands))
|
||||
|
||||
self.assertEqual(self.machine_model_csx.get_arch(), "csx")
|
||||
self.assertEqual(self.machine_model_tx2.get_arch(), "tx2")
|
||||
|
||||
self.assertEqual(self.machine_model_csx.get_ISA(), "x86")
|
||||
self.assertEqual(self.machine_model_tx2.get_ISA(), "aarch64")
|
||||
|
||||
ports_csx = ["0", "0DV", "1", "2", "2D", "3", "3D", "4", "5", "6", "7"]
|
||||
data_ports_csx = ["2D", "3D"]
|
||||
self.assertEqual(self.machine_model_csx.get_ports(), ports_csx)
|
||||
self.assertEqual(self.machine_model_csx.get_data_ports(), data_ports_csx)
|
||||
|
||||
self.assertFalse(self.machine_model_tx2.has_hidden_loads())
|
||||
|
||||
self.assertEqual(MachineModel.get_isa_for_arch("CSX"), "x86")
|
||||
self.assertEqual(MachineModel.get_isa_for_arch("tX2"), "aarch64")
|
||||
with self.assertRaises(ValueError):
|
||||
self.assertIsNone(MachineModel.get_isa_for_arch("THE_MACHINE"))
|
||||
"""
|
||||
|
||||
##################
|
||||
# Helper functions
|
||||
|
||||
Reference in New Issue
Block a user