initial upload - not functional yet

This commit is contained in:
JanLJL
2019-07-05 17:11:18 +02:00
parent d4a4698106
commit b0af9008fa
6 changed files with 868 additions and 0 deletions

194
osaca/data/csl.yml Normal file
View File

@@ -0,0 +1,194 @@
osaca_version: 0.3.0
micro_architecture: "Cascade Lake SP"
isa: "x86"
port_model_scheme: |
┌------------------------------------------------------------------------┐
| 97 entry unified scheduler |
└------------------------------------------------------------------------┘
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
┌-------┐ ┌-------┐ ┌-----┐ ┌-----┐ ┌-----┐ ┌-------┐ ┌--------┐ ┌-----┐
| ALU | | ALU | | LD | | LD | | ST | | ALU | | ALU & | | AGU |
└-------┘ └-------┘ └-----┘ └-----┘ └-----┘ └-------┘ | Shift | └-----┘
┌-------┐ ┌-------┐ ┌-----┐ ┌-----┐ ┌-------┐ └--------┘
| 2ND | | Fast | | AGU | | AGU | | Fast |
| BRANCH| | LEA | └-----┘ └-----┘ | LEA |
└-------┘ └-------┘ └-------┘
┌-------┐ ┌-------┐ ┌-------┐
|AVX DIV| |AVX FMA| | AVX |
└-------┘ └-------┘ | SHUF |
┌-------┐ ┌-------┐ └-------┘
|AVX FMA| |AVX MUL| ┌-------┐
└-------┘ └-------┘ |AVX-512|
┌-------┐ ┌-------┐ | FMA |
|AVX MUL| |AVX ADD| └-------┘
└-------┘ └-------┘ ┌-------┐
┌-------┐ ┌-------┐ |AVX-512|
|AVX ADD| |AVX ALU| | ADD |
└-------┘ └-------┘ └-------┘
┌-------┐ ┌-------┐ ┌-------┐
|AVX ALU| | AVX | |AVX-512|
└-------┘ | Shift | | MUL |
┌-------┐ └-------┘ └-------┘
| AVX | ┌-------┐ ┌-------┐
| Shift | | Slow | |AVX-512|
└-------┘ | LEA | | ALU |
┌-------┐ └-------┘ └-------┘
| VNNI | ┌-------┐
└-------┘ | VNNI |
└-------┘
ports: ["0", "0DV", "1", "2", "3", "4", "5", "6", "7"]
instruction_forms:
- name: addsd
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 0.5
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: addss
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 0.5
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: mulsd
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 0.5
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: mulss
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 0.5
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: rcpss
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 1.0
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: sqrtsd
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 6.0
latency: 22.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: sqrtss
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 3.0
latency: 16.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: vaddsd
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 0.5
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: vaddss
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 0.5
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: vdivsd
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 4.0
latency: 14.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [1.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: vdivss
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 3.0
latency: 11.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: vmulsd
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 0.5
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: vmulss
operands:
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
- class: "register"
name: "xmm"
throughput: 0.5
latency: 4.0 # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: vmovapd
operands:
- class: "memory"
base: "gpr"
offset: ~
index: "gpr"
scale: 1
- class: "register"
name: "xmm"
throughput: 0.5
latency: ~ # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0]
- name: vmovapd
operands:
- class: "register"
name: "xmm"
- class: "memory"
base: "gpr"
offset: ~
index: "gpr"
scale: 1
throughput: 1.0
latency: ~ # 0 0DV 1 2 3 4 5 6 7
port_occupation: [0.0, 0.0, 0.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0]

117
osaca/data/isa/AArch64.yml Normal file
View File

@@ -0,0 +1,117 @@
osaca_version: 0.3.0
isa: "AArch64"
# Contains all operand-irregular instruction forms OSACA supports for AArch64.
# Operand-regular for a AArch64 instruction form with N operands in the shape of
# mnemonic op1 ... opN
# means that op1 is the only destination operand and op2 to op(N) are source operands.
instruction_forms:
- name: "fmla"
operands:
- class: "register"
prefix: "v"
shape: "s"
source: true
destination: true
- class: "register"
prefix: "v"
shape: "s"
source: true
destination: false
- class: "register"
prefix: "v"
shape: "s"
source: true
destination: false
- name: "fmla"
operands:
- class: "register"
prefix: "v"
shape: "d"
source: true
destination: true
- class: "register"
prefix: "v"
shape: "d"
source: true
destination: false
- class: "register"
prefix: "v"
shape: "d"
source: true
destination: false
- name: "ldp"
operands:
- class: "register"
prefix: "d"
source: false
destination: true
- class: "register"
prefix: "d"
source: false
destination: true
- class: "memory"
base: "x"
offset: "imd"
index: ~
scale: 1
pre-indexed: false
post-indexed: false
source: true
destination: false
- name: "ldp"
operands:
- class: "register"
prefix: "q"
source: false
destination: true
- class: "register"
prefix: "q"
source: false
destination: true
- class: "memory"
base: "x"
offset: "imd"
index: ~
scale: 1
pre-indexed: false
post-indexed: false
source: true
destination: false
- name: "stp"
operands:
- class: "register"
prefix: "d"
source: true
destination: false
- class: "register"
prefix: "d"
source: true
destination: false
- class: "memory"
base: "x"
offset: "imd"
index: ~
scale: 1
pre-indexed: false
post-indexed: false
source: false
destination: true
- name: "stp"
operands:
- class: "register"
prefix: "q"
source: true
destination: false
- class: "register"
prefix: "q"
source: true
destination: false
- class: "memory"
base: "x"
offset: "imd"
index: ~
scale: 1
pre-indexed: false
post-indexed: false
source: false
destination: true

57
osaca/data/isa/x86.yml Normal file
View File

@@ -0,0 +1,57 @@
osaca_version: 0.3.0
isa: "x86 AT&T"
# Contains all operand-irregular instruction forms OSACA supports for x86.
# Operand-regular for a x86 AT&T instruction form with N operands in the shape of
# mnemonic op1 ... opN
# means that opN is the only destination operand and op1 to op(N-1) are source operands.
instruction_forms:
- name: addsd
operands:
- class: "register"
name: "xmm"
source: true
destination: true
- class: "register"
name: "xmm"
source: true
destination: false
- name: addss
operands:
- class: "register"
name: "xmm"
source: true
destination: true
- class: "register"
name: "xmm"
source: true
destination: false
- name: mulsd
operands:
- class: "register"
name: "xmm"
source: true
destination: true
- class: "register"
name: "xmm"
source: true
destination: false
- name: mulss
operands:
- class: "register"
name: "xmm"
source: true
destination: true
- class: "register"
name: "xmm"
source: true
destination: false
- name: vaddsd
operands:
- class: "register"
name: "xmm"
source: true
destination: true
- class: "register"
name: "xmm"
source: true
destination: false

252
osaca/data/vulcan.yml Normal file
View File

@@ -0,0 +1,252 @@
osaca_version: 0.3.0
micro_architecture: "Vulcan"
isa: "AArch64"
port_model_scheme: |
┌---------------------------------------------------------------┐
| 60 entry unified scheduler |
└---------------------------------------------------------------┘
0 | 1 | 2 | 3 | 4 | 5 |
▼ ▼ ▼ ▼ ▼ ▼
┌------┐ ┌------┐ ┌------┐ ┌-------┐ ┌-------┐ ┌---------┐
| ALU | | ALU | | ALU/ | | LD/ST | | LD/ST | | ST Data |
└------┘ └------┘ | BR | └-------┘ └-------┘ └---------┘
┌------┐ ┌------┐ └------┘
| FP/ | | FP/ |
| NEON | | NEON |
└------┘ └------┘
┌------┐
| INT |
| MUL/ |
| DIV |
└------┘
┌------┐
|CRYPTO|
└------┘
ports: ["0", "0DV", "1", "1DV", "2", "3", "4", "5"]
instruction_forms:
- name: "add"
operands:
- class: "register"
prefix: "x"
- class: "register"
prefix: "x"
- class: "register"
prefix: "x"
throughput: 0.33333333
latency: 1.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.33333333, 0.0, 0.33333333, 0.0, 0.33333333, 0.0, 0.0, 0.0]
- name: "add"
operands:
- class: "register"
prefix: "x"
- class: "register"
prefix: "x"
- class: "immediate"
imd: "int"
throughput: 0.33333333
latency: 1.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.33333333, 0.0, 0.33333333, 0.0, 0.33333333, 0.0, 0.0, 0.0]
- name: "fadd"
operands:
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
throughput: 0.5
latency: 6.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: "fadd"
operands:
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
throughput: 0.5
latency: 6.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: "fdiv"
operands:
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
throughput: 8.5
latency: 16.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [1.0, 8.5, 1.0, 8.5, 0.0, 0.0, 0.0, 0.0]
- name: "fdiv"
operands:
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
throughput: 12.0
latency: 23.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [1.0, 12.5, 1.0, 12.0, 0.0, 0.0, 0.0, 0.0]
- name: "fmla"
operands:
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
throughput: 0.5
latency: 6.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: "fmla"
operands:
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
throughput: 0.5
latency: 6.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: "fmul"
operands:
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
throughput: 0.5
latency: 6.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: "fmul"
operands:
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
throughput: 0.5
latency: 6.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: "fsub"
operands:
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
- class: "register"
prefix: "v"
shape: "s"
throughput: 0.5
latency: 6.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: "fsub"
operands:
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
- class: "register"
prefix: "v"
shape: "d"
throughput: 0.5
latency: 6.0 # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: "ldp"
operands:
- class: "register"
prefix: "d"
- class: "register"
prefix: "d"
- class: "memory"
base: "x"
offset: "imd"
index: ~
scale: 1
pre-indexed: false
post-indexed: false
throughput: 1.0
latency: ~ # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0]
- name: "ldp"
operands:
- class: "register"
prefix: "q"
- class: "register"
prefix: "q"
- class: "memory"
base: "x"
offset: "imd"
index: ~
scale: 1
pre-indexed: false
post-indexed: false
throughput: 1.0
latency: ~ # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0]
- name: "stp"
operands:
- class: "register"
prefix: "d"
- class: "register"
prefix: "d"
- class: "memory"
base: "x"
offset: "imd"
index: ~
scale: 1
pre-indexed: false
post-indexed: false
throughput: 2.0
latency: ~ # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0]
- name: "stp"
operands:
- class: "register"
prefix: "q"
- class: "register"
prefix: "q"
- class: "memory"
base: "x"
offset: "imd"
index: ~
scale: 1
pre-indexed: false
post-indexed: false
throughput: 2.0
latency: ~ # 0 0DV 1 1DV 2 3 4 5
port_occupation: [0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0]

208
osaca/semantics/hw_model.py Executable file
View File

@@ -0,0 +1,208 @@
#!/usr/bin/env python3
import os
from osaca.parser.parser_x86att import ParserX86ATT
from ruamel import yaml
class MachineModel(object):
def __init__(self, arch=None, path_to_yaml=None):
if not arch and not path_to_yaml:
raise ValueError('Either arch or path_to_yaml required.')
if arch and path_to_yaml:
raise ValueError('Only one of arch and path_to_yaml is allowed.')
self._path = path_to_yaml
self._arch = arch
if arch:
self._arch = arch.lower()
try:
with open(self._find_file(self._arch), 'r') as f:
self._data = yaml.load(f, Loader=yaml.Loader)
except AssertionError:
raise ValueError(
'Cannot find specified architecture. Make sure the machine file exists.'
)
elif path_to_yaml:
try:
with open(self._path, 'r') as f:
self._data = yaml.load(f, Loader=yaml.Loader)
except AssertionError:
raise ValueError(
'Cannot find specified path to YAML file. Make sure the machine file exists.'
)
def _find_file(self, name):
data_dir = os.path.expanduser('~/.osaca/data')
name = os.path.join(data_dir, name)
assert os.path.exists(name)
return name
def __getitem__(self, key):
"""Return configuration entry."""
return self._data[key]
def __contains__(self, key):
"""Return true if configuration key is present."""
return key in self._data
######################################################
def get_instruction(self, name, operands):
try:
return next(
instruction_form
for instruction_form in self._data['instruction_forms']
if instruction_form['name'] == name
and self._match_operands(instruction_form['operands'], operands)
)
except StopIteration:
return None
def get_ISA(self):
return self._data['isa']
######################################################
def _match_operands(self, i_operands, operands):
operands_ok = True
if len(operands) != len(i_operands):
return False
for idx, operand in enumerate(operands):
i_operand = i_operands[idx]
operands_ok = operands_ok and self._check_operands(i_operand, operand)
if operands_ok:
return True
else:
return False
def _check_operands(self, i_operands, operands):
if self._data['isa'] == 'AArch64':
return self._check_AArch64_operands(i_operands, operands)
if self._data['isa'] == 'x86':
return self._check_x86_operands(i_operands, operands)
def _check_AArch64_operands(self, i_operand, operand):
# register
if 'register' in operand:
if i_operand['class'] != 'register':
return False
return self._is_AArch64_reg_type(i_operand, operand['register'])
# memory
if 'memory' in operand:
if i_operand['class'] != 'memory':
return False
return self._is_AArch64_mem_type(i_operand['memory'], operand['memory'])
# immediate
if 'value' in operand:
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'int'
if 'float' in operand:
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'float'
if 'double' in operand:
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'double'
# prefetch option
if 'prfop' in operand:
return i_operand['class'] == 'prfop'
# no match
return False
def _check_x86_operands(self, i_operand, operand):
# register
if 'register' in operand:
if i_operand['class'] != 'register':
return False
return self._is_x86_reg_type(i_operand['name'], operand['register'])
# memory
if 'memory' in operand:
if i_operand['class'] != 'memory':
return False
return self._is_x86_mem_type(i_operand['memory'], operand['memory'])
# immediate
if 'value' in operand:
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'int'
def _is_AArch64_reg_type(self, i_reg, reg):
if reg['prefix'] != i_reg['prefix']:
return False
if 'shape' in reg:
if 'shape' in i_reg and reg['shape'] == i_reg['shape']:
return True
return False
return True
def _is_x86_reg_type(self, i_reg_name, reg):
# differentiate between vector registers (xmm, ymm, zmm) and others (gpr)
parser_x86 = ParserX86ATT()
if parser_x86.is_vector_register(reg):
if reg['name'][0:3] == i_reg_name:
return True
else:
if i_reg_name == 'gpr':
return True
return False
def _is_AArch64_mem_type(self, i_mem, mem):
if (
# check base
mem['base']['prefix'] == i_mem['base']
# check offset
and (
mem['offset'] == i_mem['offset']
or (
mem['offset'] is not None
and 'identifier' in mem['offset']
and i_mem['offset'] == 'identifier'
)
or (
mem['offset'] is not None
and 'value' in mem['offset']
and i_mem['offset'] == 'imd'
)
)
# check index
and (
mem['index'] == i_mem['index']
or (
mem['index'] is not None
and 'prefix' in mem['index']
and mem['index']['prefix'] == i_mem['index']
)
)
and mem['scale'] == i_mem['scale']
and (('pre_indexed' in mem) == (i_mem['pre-indexed']))
and (('post_indexed' in mem) == (i_mem['post-indexed']))
):
return True
return False
def _is_x86_mem_type(self, i_mem, mem):
if (
# check base
self._is_x86_reg_type(i_mem['base'], mem['base'])
# check offset
and (
mem['offset'] == i_mem['offset']
or (
mem['offset'] is not None
and 'identifier' in mem['offset']
and i_mem['offset'] == 'identifier'
)
or (
mem['offset'] is not None
and 'value' in mem['offset']
and i_mem['offset'] == 'imd'
)
)
# check index
and (
mem['index'] == i_mem['index']
or (
mem['index'] is not None
and 'name' in mem['index']
and self._is_x86_reg_type(i_mem['index'], mem['index'])
)
)
and mem['scale'] == i_mem['scale']
):
return True
return False

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env python3
import os
from .hw_model import MachineModel
class SemanticsAppender(object):
def __init__(self, machine_model: MachineModel):
self.machine_model = machine_model
self._isa = machine_model.get_ISA()
self._isa_model = MachineModel(path_to_yaml=self._find_file(self._isa))
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 operands to
# - source
# - destination
# - source/destination
# for this, have a default implementation and get exceptions from generic x86/AArch64 ISA file
def assign_src_dst(self, instruction_form):
# 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['name'], instruction_form['operands']
)
if isa_data is None:
# no irregular operand structure, apply default
# TODO
pass
else:
# load src/dst structure from isa_data
# TODO
pass
raise NotImplementedError