Files
OSACA/osaca/semantics/semanticsAppender.py
2019-07-10 18:25:32 +02:00

156 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import warnings
from osaca.parser import AttrDict
from .hw_model import MachineModel
class SemanticsAppender(object):
class INSTR_FLAGS:
"""
Flags used for unknown or special instructions
"""
TP_UNKWN = 'tp_unkown'
LT_UNKWN = 'lt_unkown'
NOT_BOUND = 'not_bound'
HIDDEN_LD = 'hidden_load'
def __init__(self, machine_model: MachineModel, path_to_yaml=None):
self.machine_model = machine_model
self._isa = machine_model.get_ISA()
if path_to_yaml:
path = path_to_yaml
else:
path = self._find_file(self._isa)
self._isa_model = MachineModel(path_to_yaml=path)
def _find_file(self, isa):
data_dir = os.path.expanduser('~/.osaca/data/isa')
name = os.path.join(data_dir, isa + '.yml')
assert os.path.exists(name)
return name
# get parser result and assign throughput and latency value to instruction form
# mark instruction form with semantic flags
def assign_tp_lt(self, instruction_form):
flags = []
port_number = len(self.machine_model['ports'])
instruction_data = self.machine_model.get_instruction(
instruction_form['instruction'], instruction_form['operands']
)
if instruction_data:
# instruction form in DB
throughput = instruction_data['throughput']
port_pressure = instruction_data['port_pressure']
try:
assert isinstance(port_pressure, list)
assert len(port_pressure) == port_number
instruction_form['port_pressure'] = port_pressure
except AssertionError:
warnings.warn(
'Port pressure could not be imported correctly from database. '
+ 'Please check entry for:\n {}'.format(instruction_form)
)
instruction_form['port_pressure'] = [0.0 for i in range(port_number)]
flags.append(self.INSTR_FLAGS.TP_UNKWN)
if throughput is None:
# assume 0 cy and mark as unknown
throughput = 0.0
flags.append(self.INSTR_FLAGS.TP_UNKWN)
latency = instruction_data['latency']
if latency is None:
# assume 0 cy and mark as unknown
latency = 0.0
flags.append(self.INSTR_FLAGS.LT_UNKWN)
else:
# instruction could not be found in DB
# --> mark as unknown and assume 0 cy for latency/throughput
throughput = 0.0
latency = 0.0
instruction_form['port_pressure'] = [0.0 for i in range(port_number)]
flags += [self.INSTR_FLAGS.TP_UNKWN, self.INSTR_FLAGS.LT_UNKWN]
# flatten flag list
flags = list(set(flags))
if 'flags' not in instruction_form:
instruction_form['flags'] = flags
else:
instruction_form['flags'] += flags
instruction_form['throughput'] = throughput
instruction_form['latency'] = latency
# get parser result and assign operands to
# - source
# - destination
# - source/destination
def assign_src_dst(self, instruction_form):
# if the instruction form doesn't have operands, there's nothing to do
if instruction_form['operands'] is None:
return
# check if instruction form is in ISA yaml, otherwise apply standard operand assignment
# (one dest, others source)
isa_data = self._isa_model.get_instruction(
instruction_form['instruction'], instruction_form['operands']
)
operands = instruction_form['operands']
op_dict = {}
if isa_data is None:
# no irregular operand structure, apply default
op_dict['source'] = self._get_regular_source_operands(instruction_form)
op_dict['destination'] = self._get_regular_destination_operands(instruction_form)
op_dict['src_dst'] = []
else:
# load src/dst structure from isa_data
op_dict['source'] = []
op_dict['destination'] = []
op_dict['src_dst'] = []
for i, op in enumerate(isa_data['operands']):
if op['source'] and op['destination']:
op_dict['src_dst'].append(operands[i])
continue
if op['source']:
op_dict['source'].append(operands[i])
continue
if op['destination']:
op_dict['destination'].append(operands[i])
continue
# store operand list in dict and reassign operand key/value pair
op_dict['operand_list'] = operands
instruction_form['operands'] = AttrDict.convert_dict(op_dict)
def _get_regular_source_operands(self, instruction_form):
if self._isa == 'x86':
return self._get_regular_source_x86ATT(instruction_form)
if self._isa == 'AArch64':
return self._get_regular_source_AArch64(instruction_form)
def _get_regular_destination_operands(self, instruction_form):
if self._isa == 'x86':
return self._get_regular_destination_x86ATT(instruction_form)
if self._isa == 'AArch64':
return self._get_regular_destination_AArch64(instruction_form)
def _get_regular_source_x86ATT(self, instruction_form):
# return all but last operand
sources = [
op for op in instruction_form['operands'][0:len(instruction_form['operands']) - 1]
]
return sources
def _get_regular_source_AArch64(self, instruction_form):
# return all but first operand
sources = [
op for op in instruction_form['operands'][1:len(instruction_form['operands'])]
]
return sources
def _get_regular_destination_x86ATT(self, instruction_form):
# return last operand
return instruction_form['operands'][-1:]
def _get_regular_destination_AArch64(self, instruction_form):
# return first operand
return instruction_form['operands'][:1]