mirror of
https://github.com/RRZE-HPC/OSACA.git
synced 2026-01-06 19:20:07 +01:00
Merge branch 'master' into A64FX
This commit is contained in:
@@ -57,8 +57,12 @@ Additional requirements are:
|
|||||||
|
|
||||||
- `Python3 <https://www.python.org/>`__
|
- `Python3 <https://www.python.org/>`__
|
||||||
- `Graphviz <https://www.graphviz.org/>`__ for dependency graph creation (minimal dependency is `libgraphviz-dev` on Ubuntu)
|
- `Graphviz <https://www.graphviz.org/>`__ for dependency graph creation (minimal dependency is `libgraphviz-dev` on Ubuntu)
|
||||||
|
|
||||||
|
Optional requirements are:
|
||||||
|
|
||||||
- `Kerncraft <https://github.com/RRZE-HPC/kerncraft>`__ >=v0.8.4 for marker insertion
|
- `Kerncraft <https://github.com/RRZE-HPC/kerncraft>`__ >=v0.8.4 for marker insertion
|
||||||
- `ibench <https://github.com/RRZE-HPC/ibench>`__ or `asmbench <https://github.com/RRZE-HPC/asmbench/>`__ for throughput/latency measurements
|
- `ibench <https://github.com/RRZE-HPC/ibench>`__ or `asmbench <https://github.com/RRZE-HPC/asmbench/>`__ for throughput/latency measurements
|
||||||
|
- `BeautifulSoup4 <https://www.crummy.com/software/BeautifulSoup/bs4/doc/>`__ for scraping instruction form information for the x86 ISA (experimental)
|
||||||
|
|
||||||
Design
|
Design
|
||||||
======
|
======
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"""Open Source Architecture Code Analyzer"""
|
"""Open Source Architecture Code Analyzer"""
|
||||||
name = 'osaca'
|
name = 'osaca'
|
||||||
__version__ = '0.3.3.dev0'
|
__version__ = '0.3.7'
|
||||||
|
|
||||||
# To trigger travis deployment to pypi, do the following:
|
# To trigger travis deployment to pypi, do the following:
|
||||||
# 1. Increment __version___
|
# 1. Increment __version___
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.2
|
osaca_version: 0.3.4
|
||||||
micro_architecture: Intel Broadwell
|
micro_architecture: Intel Broadwell
|
||||||
arch_code: BDW
|
arch_code: BDW
|
||||||
isa: x86
|
isa: x86
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.2
|
osaca_version: 0.3.4
|
||||||
micro_architecture: Cascade Lake SP
|
micro_architecture: Cascade Lake SP
|
||||||
arch_code: CSX
|
arch_code: CSX
|
||||||
isa: x86
|
isa: x86
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.2
|
osaca_version: 0.3.4
|
||||||
micro_architecture: Intel Haswell
|
micro_architecture: Intel Haswell
|
||||||
arch_code: HSW
|
arch_code: HSW
|
||||||
isa: x86
|
isa: x86
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.0
|
osaca_version: 0.3.4
|
||||||
isa: "AArch64"
|
isa: "AArch64"
|
||||||
# Contains all operand-irregular instruction forms OSACA supports for 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
|
# Operand-regular for a AArch64 instruction form with N operands in the shape of
|
||||||
@@ -191,3 +191,73 @@ instruction_forms:
|
|||||||
post-indexed: "*"
|
post-indexed: "*"
|
||||||
source: false
|
source: false
|
||||||
destination: true
|
destination: true
|
||||||
|
- name: cmp
|
||||||
|
operands:
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- name: cmp
|
||||||
|
operands:
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- class: "immediate"
|
||||||
|
imd: "int"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- name: cmn
|
||||||
|
operands:
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- name: cmn
|
||||||
|
operands:
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- class: "immediate"
|
||||||
|
imd: "int"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- name: fcmp
|
||||||
|
operands:
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- name: fcmp
|
||||||
|
operands:
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- class: "immediate"
|
||||||
|
imd: "double"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- name: fcmp
|
||||||
|
operands:
|
||||||
|
- class: "register"
|
||||||
|
prefix: "*"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- class: "immediate"
|
||||||
|
imd: "float"
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.0
|
osaca_version: 0.3.4
|
||||||
isa: "x86"
|
isa: "x86"
|
||||||
# Contains all operand-irregular instruction forms OSACA supports for x86.
|
# 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
|
# Operand-regular for a x86 AT&T instruction form with N operands in the shape of
|
||||||
@@ -3167,7 +3167,7 @@ instruction_forms:
|
|||||||
destination: false
|
destination: false
|
||||||
hidden_operands:
|
hidden_operands:
|
||||||
- class: "memory"
|
- class: "memory"
|
||||||
base: "gpr"
|
base: {name: 'rsp'}
|
||||||
offset: ~
|
offset: ~
|
||||||
index: ~
|
index: ~
|
||||||
scale: 1
|
scale: 1
|
||||||
@@ -3177,11 +3177,29 @@ instruction_forms:
|
|||||||
name: "rsp"
|
name: "rsp"
|
||||||
source: true
|
source: true
|
||||||
destination: true
|
destination: true
|
||||||
|
- name: pop
|
||||||
|
operands:
|
||||||
|
- class: "register"
|
||||||
|
name: "gpr"
|
||||||
|
source: false
|
||||||
|
destination: true
|
||||||
|
hidden_operands:
|
||||||
|
- class: "memory"
|
||||||
|
base: {name: 'rsp'}
|
||||||
|
offset: ~
|
||||||
|
index: ~
|
||||||
|
scale: 1
|
||||||
|
source: true
|
||||||
|
destination: false
|
||||||
|
- class: "register"
|
||||||
|
name: "rsp"
|
||||||
|
source: true
|
||||||
|
destination: true
|
||||||
- name: pushfq
|
- name: pushfq
|
||||||
operands: []
|
operands: []
|
||||||
hidden_operands:
|
hidden_operands:
|
||||||
- class: "memory"
|
- class: "memory"
|
||||||
base: "gpr"
|
base: {name: 'rsp'}
|
||||||
offset: ~
|
offset: ~
|
||||||
index: ~
|
index: ~
|
||||||
scale: 1
|
scale: 1
|
||||||
@@ -3971,4 +3989,3 @@ instruction_forms:
|
|||||||
name: "gpr"
|
name: "gpr"
|
||||||
source: true
|
source: true
|
||||||
destination: true
|
destination: true
|
||||||
|
|
||||||
|
|||||||
48968
osaca/data/ivb.yml
48968
osaca/data/ivb.yml
File diff suppressed because it is too large
Load Diff
@@ -219,9 +219,15 @@ def extract_model(tree, arch, skip_mem=True):
|
|||||||
port_23 = True
|
port_23 = True
|
||||||
if '4' in pp[1]:
|
if '4' in pp[1]:
|
||||||
port_4 = True
|
port_4 = True
|
||||||
# Add (1, ['2D', '3D']) if load ports (2 & 3) are used, but not the store port (4)
|
# Add (X, ['2D', '3D']) if load ports (2 & 3) are used, but not the store port (4)
|
||||||
|
# X = 2 on SNB and IVB IFF used in combination with ymm register, otherwise X = 1
|
||||||
|
if arch.upper() in ['SNB', 'IVB'] and \
|
||||||
|
any([p['class'] == 'register' and p['name'] == 'ymm' for p in parameters]):
|
||||||
|
data_port_throughput = 2
|
||||||
|
else:
|
||||||
|
data_port_throughput = 1
|
||||||
if port_23 and not port_4:
|
if port_23 and not port_4:
|
||||||
port_pressure.append((1, ['2D', '3D']))
|
port_pressure.append((data_port_throughput, ['2D', '3D']))
|
||||||
|
|
||||||
# Add missing ports:
|
# Add missing ports:
|
||||||
for ports in [pp[1] for pp in port_pressure]:
|
for ports in [pp[1] for pp in port_pressure]:
|
||||||
@@ -275,7 +281,7 @@ def main():
|
|||||||
if model is not None:
|
if model is not None:
|
||||||
print(
|
print(
|
||||||
rhs_comment(
|
rhs_comment(
|
||||||
model.dump(), basename + " " + args.xml.split('/')[-1] + " " + args.arch
|
model.dump(), "uops.info import"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.3
|
osaca_version: 0.3.4
|
||||||
micro_architecture: Arm Neoverse N1
|
micro_architecture: Arm Neoverse N1
|
||||||
arch_code: n1
|
arch_code: n1
|
||||||
isa: AArch64
|
isa: AArch64
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.2
|
osaca_version: 0.3.4
|
||||||
micro_architecture: Intel Skylake SP
|
micro_architecture: Intel Skylake SP
|
||||||
arch_code: SKX
|
arch_code: SKX
|
||||||
isa: x86
|
isa: x86
|
||||||
|
|||||||
37064
osaca/data/snb.yml
37064
osaca/data/snb.yml
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.2
|
osaca_version: 0.3.4
|
||||||
micro_architecture: Thunder X2
|
micro_architecture: Thunder X2
|
||||||
arch_code: tx2
|
arch_code: tx2
|
||||||
isa: AArch64
|
isa: AArch64
|
||||||
@@ -403,6 +403,22 @@ instruction_forms:
|
|||||||
throughput: 1.0
|
throughput: 1.0
|
||||||
latency: 4.0 # 2*p34
|
latency: 4.0 # 2*p34
|
||||||
port_pressure: [[2.0, '34']]
|
port_pressure: [[2.0, '34']]
|
||||||
|
- name: ldp
|
||||||
|
operands:
|
||||||
|
- class: register
|
||||||
|
prefix: d
|
||||||
|
- class: register
|
||||||
|
prefix: d
|
||||||
|
- class: memory
|
||||||
|
base: x
|
||||||
|
offset: '*'
|
||||||
|
index: '*'
|
||||||
|
scale: '*'
|
||||||
|
pre-indexed: false
|
||||||
|
post-indexed: false
|
||||||
|
throughput: 1.0
|
||||||
|
latency: 4.0 # 2*p34
|
||||||
|
port_pressure: [[2.0, '34']]
|
||||||
- name: ldp
|
- name: ldp
|
||||||
operands:
|
operands:
|
||||||
- class: register
|
- class: register
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.2
|
osaca_version: 0.3.4
|
||||||
micro_architecture: AMD Zen (family 17h)
|
micro_architecture: AMD Zen (family 17h)
|
||||||
arch_code: ZEN1
|
arch_code: ZEN1
|
||||||
isa: x86
|
isa: x86
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
osaca_version: 0.3.2
|
osaca_version: 0.3.4
|
||||||
micro_architecture: AMD Zen2
|
micro_architecture: AMD Zen2
|
||||||
arch_code: ZEN2
|
arch_code: ZEN2
|
||||||
isa: x86
|
isa: x86
|
||||||
|
|||||||
@@ -142,6 +142,12 @@ def create_parser(parser=None):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--verbose', '-v', action='count', default=0, help='Increases verbosity level.'
|
'--verbose', '-v', action='count', default=0, help='Increases verbosity level.'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--out', '-o',
|
||||||
|
default=sys.stdout,
|
||||||
|
type=argparse.FileType('w'),
|
||||||
|
help='Write analysis to this file (default to stdout).'
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'file', type=argparse.FileType('r'), help='Path to object (ASM or instruction file).'
|
'file', type=argparse.FileType('r'), help='Path to object (ASM or instruction file).'
|
||||||
)
|
)
|
||||||
@@ -326,7 +332,7 @@ def main():
|
|||||||
parser = create_parser()
|
parser = create_parser()
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
check_arguments(args, parser)
|
check_arguments(args, parser)
|
||||||
run(args)
|
run(args, output_file=args.out)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ class BaseParser(object):
|
|||||||
DIRECTIVE_ID = 'directive'
|
DIRECTIVE_ID = 'directive'
|
||||||
IMMEDIATE_ID = 'immediate'
|
IMMEDIATE_ID = 'immediate'
|
||||||
LABEL_ID = 'label'
|
LABEL_ID = 'label'
|
||||||
|
IDENTIFIER_ID = 'identifier'
|
||||||
MEMORY_ID = 'memory'
|
MEMORY_ID = 'memory'
|
||||||
REGISTER_ID = 'register'
|
REGISTER_ID = 'register'
|
||||||
SEGMENT_EXT_ID = 'segment_extension'
|
SEGMENT_EXT_ID = 'segment_extension'
|
||||||
|
|||||||
@@ -19,22 +19,23 @@ class ParserAArch64(BaseParser):
|
|||||||
pp.ZeroOrMore(pp.Word(pp.printables))
|
pp.ZeroOrMore(pp.Word(pp.printables))
|
||||||
).setResultsName(self.COMMENT_ID)
|
).setResultsName(self.COMMENT_ID)
|
||||||
# Define ARM assembly identifier
|
# Define ARM assembly identifier
|
||||||
|
decimal_number = pp.Combine(
|
||||||
|
pp.Optional(pp.Literal('-')) + pp.Word(pp.nums)
|
||||||
|
).setResultsName('value')
|
||||||
|
hex_number = pp.Combine(pp.Literal('0x') + pp.Word(pp.hexnums)).setResultsName('value')
|
||||||
relocation = pp.Combine(pp.Literal(':') + pp.Word(pp.alphanums + '_') + pp.Literal(':'))
|
relocation = pp.Combine(pp.Literal(':') + pp.Word(pp.alphanums + '_') + pp.Literal(':'))
|
||||||
first = pp.Word(pp.alphas + '_.', exact=1)
|
first = pp.Word(pp.alphas + '_.', exact=1)
|
||||||
rest = pp.Word(pp.alphanums + '_.')
|
rest = pp.Word(pp.alphanums + '_.')
|
||||||
identifier = pp.Group(
|
identifier = pp.Group(
|
||||||
pp.Optional(relocation).setResultsName('relocation')
|
pp.Optional(relocation).setResultsName('relocation')
|
||||||
+ pp.Combine(first + pp.Optional(rest)).setResultsName('name')
|
+ pp.Combine(first + pp.Optional(rest)).setResultsName('name')
|
||||||
).setResultsName('identifier')
|
+ pp.Optional(pp.Suppress(pp.Literal('+')) + (hex_number | decimal_number).setResultsName('offset'))
|
||||||
|
).setResultsName(self.IDENTIFIER_ID)
|
||||||
# Label
|
# Label
|
||||||
self.label = pp.Group(
|
self.label = pp.Group(
|
||||||
identifier.setResultsName('name') + pp.Literal(':') + pp.Optional(self.comment)
|
identifier.setResultsName('name') + pp.Literal(':') + pp.Optional(self.comment)
|
||||||
).setResultsName(self.LABEL_ID)
|
).setResultsName(self.LABEL_ID)
|
||||||
# Directive
|
# Directive
|
||||||
decimal_number = pp.Combine(
|
|
||||||
pp.Optional(pp.Literal('-')) + pp.Word(pp.nums)
|
|
||||||
).setResultsName('value')
|
|
||||||
hex_number = pp.Combine(pp.Literal('0x') + pp.Word(pp.hexnums)).setResultsName('value')
|
|
||||||
directive_option = pp.Combine(
|
directive_option = pp.Combine(
|
||||||
pp.Word(pp.alphas + '#@.%', exact=1)
|
pp.Word(pp.alphas + '#@.%', exact=1)
|
||||||
+ pp.Optional(pp.Word(pp.printables + ' ', excludeChars=','))
|
+ pp.Optional(pp.Word(pp.printables + ' ', excludeChars=','))
|
||||||
@@ -341,6 +342,8 @@ class ParserAArch64(BaseParser):
|
|||||||
return self.process_immediate(operand[self.IMMEDIATE_ID])
|
return self.process_immediate(operand[self.IMMEDIATE_ID])
|
||||||
if self.LABEL_ID in operand:
|
if self.LABEL_ID in operand:
|
||||||
return self.process_label(operand[self.LABEL_ID])
|
return self.process_label(operand[self.LABEL_ID])
|
||||||
|
if self.IDENTIFIER_ID in operand:
|
||||||
|
return self.process_identifier(operand[self.IDENTIFIER_ID])
|
||||||
return operand
|
return operand
|
||||||
|
|
||||||
def process_memory_address(self, memory_address):
|
def process_memory_address(self, memory_address):
|
||||||
@@ -424,6 +427,13 @@ class ParserAArch64(BaseParser):
|
|||||||
label['name'] = label['name']['name']
|
label['name'] = label['name']['name']
|
||||||
return AttrDict({self.LABEL_ID: label})
|
return AttrDict({self.LABEL_ID: label})
|
||||||
|
|
||||||
|
def process_identifier(self, identifier):
|
||||||
|
"""Post-process identifier operand"""
|
||||||
|
# remove value if it consists of symbol+offset
|
||||||
|
if 'value' in identifier:
|
||||||
|
del identifier['value']
|
||||||
|
return AttrDict({self.IDENTIFIER_ID: identifier})
|
||||||
|
|
||||||
def get_full_reg_name(self, register):
|
def get_full_reg_name(self, register):
|
||||||
"""Return one register name string including all attributes"""
|
"""Return one register name string including all attributes"""
|
||||||
if 'lanes' in register:
|
if 'lanes' in register:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import re
|
|
||||||
import string
|
import string
|
||||||
|
|
||||||
import pyparsing as pp
|
import pyparsing as pp
|
||||||
@@ -34,8 +33,20 @@ class ParserX86ATT(BaseParser):
|
|||||||
+ pp.Optional(relocation).setResultsName('relocation')
|
+ pp.Optional(relocation).setResultsName('relocation')
|
||||||
).setResultsName('identifier')
|
).setResultsName('identifier')
|
||||||
# Label
|
# Label
|
||||||
|
rest = pp.Word(pp.alphanums + '$_.+-()')
|
||||||
|
label_identifier = pp.Group(
|
||||||
|
pp.Optional(id_offset).setResultsName('offset')
|
||||||
|
+ pp.Combine(first + pp.Optional(rest)).setResultsName('name')
|
||||||
|
+ pp.Optional(relocation).setResultsName('relocation')
|
||||||
|
).setResultsName('identifier')
|
||||||
|
numeric_identifier = pp.Group(
|
||||||
|
pp.Word(pp.nums).setResultsName('name')
|
||||||
|
+ pp.Optional(pp.oneOf('b f', caseless=True).setResultsName('suffix'))
|
||||||
|
).setResultsName('identifier')
|
||||||
self.label = pp.Group(
|
self.label = pp.Group(
|
||||||
identifier.setResultsName('name') + pp.Literal(':') + pp.Optional(self.comment)
|
(label_identifier | numeric_identifier).setResultsName('name')
|
||||||
|
+ pp.Literal(':')
|
||||||
|
+ pp.Optional(self.comment)
|
||||||
).setResultsName(self.LABEL_ID)
|
).setResultsName(self.LABEL_ID)
|
||||||
# Register: pp.Regex('^%[0-9a-zA-Z]+{}{z},?')
|
# Register: pp.Regex('^%[0-9a-zA-Z]+{}{z},?')
|
||||||
self.register = pp.Group(
|
self.register = pp.Group(
|
||||||
@@ -44,7 +55,7 @@ class ParserX86ATT(BaseParser):
|
|||||||
+ pp.Optional(pp.Literal('(') + pp.Word(pp.nums) + pp.Literal(')'))
|
+ pp.Optional(pp.Literal('(') + pp.Word(pp.nums) + pp.Literal(')'))
|
||||||
+ pp.Optional(
|
+ pp.Optional(
|
||||||
pp.Literal('{')
|
pp.Literal('{')
|
||||||
+ pp.Literal('%')
|
+ pp.Optional(pp.Suppress(pp.Literal('%')))
|
||||||
+ pp.Word(pp.alphanums).setResultsName('mask')
|
+ pp.Word(pp.alphanums).setResultsName('mask')
|
||||||
+ pp.Literal('}')
|
+ pp.Literal('}')
|
||||||
+ pp.Optional(
|
+ pp.Optional(
|
||||||
@@ -99,7 +110,7 @@ class ParserX86ATT(BaseParser):
|
|||||||
+ pp.Literal(')')
|
+ pp.Literal(')')
|
||||||
+ pp.Optional(
|
+ pp.Optional(
|
||||||
pp.Literal('{')
|
pp.Literal('{')
|
||||||
+ pp.Literal('%')
|
+ pp.Optional(pp.Suppress(pp.Literal('%')))
|
||||||
+ pp.Word(pp.alphanums).setResultsName('mask')
|
+ pp.Word(pp.alphanums).setResultsName('mask')
|
||||||
+ pp.Literal('}')
|
+ pp.Literal('}')
|
||||||
)
|
)
|
||||||
@@ -132,7 +143,9 @@ class ParserX86ATT(BaseParser):
|
|||||||
pp.alphanums
|
pp.alphanums
|
||||||
).setResultsName('mnemonic')
|
).setResultsName('mnemonic')
|
||||||
# Combine to instruction form
|
# Combine to instruction form
|
||||||
operand_first = pp.Group(self.register ^ immediate ^ memory ^ identifier)
|
operand_first = pp.Group(
|
||||||
|
self.register ^ immediate ^ memory ^ identifier ^ numeric_identifier
|
||||||
|
)
|
||||||
operand_rest = pp.Group(self.register ^ immediate ^ memory)
|
operand_rest = pp.Group(self.register ^ immediate ^ memory)
|
||||||
self.instruction_parser = (
|
self.instruction_parser = (
|
||||||
mnemonic
|
mnemonic
|
||||||
@@ -305,7 +318,7 @@ class ParserX86ATT(BaseParser):
|
|||||||
def process_label(self, label):
|
def process_label(self, label):
|
||||||
"""Post-process label asm line"""
|
"""Post-process label asm line"""
|
||||||
# remove duplicated 'name' level due to identifier
|
# remove duplicated 'name' level due to identifier
|
||||||
label['name'] = label['name']['name']
|
label['name'] = label['name'][0]['name']
|
||||||
return AttrDict({self.LABEL_ID: label})
|
return AttrDict({self.LABEL_ID: label})
|
||||||
|
|
||||||
def process_immediate(self, immediate):
|
def process_immediate(self, immediate):
|
||||||
|
|||||||
@@ -494,6 +494,7 @@ class MachineModel(object):
|
|||||||
if 'class' in operand:
|
if 'class' in operand:
|
||||||
# compare two DB entries
|
# compare two DB entries
|
||||||
return self._compare_db_entries(i_operand, operand)
|
return self._compare_db_entries(i_operand, operand)
|
||||||
|
# TODO support class wildcards
|
||||||
# register
|
# register
|
||||||
if 'register' in operand:
|
if 'register' in operand:
|
||||||
if i_operand['class'] != 'register':
|
if i_operand['class'] != 'register':
|
||||||
@@ -505,12 +506,14 @@ class MachineModel(object):
|
|||||||
return False
|
return False
|
||||||
return self._is_AArch64_mem_type(i_operand, operand['memory'])
|
return self._is_AArch64_mem_type(i_operand, operand['memory'])
|
||||||
# immediate
|
# immediate
|
||||||
|
# TODO support wildcards
|
||||||
if 'value' in operand or ('immediate' in operand and 'value' in operand['immediate']):
|
if 'value' in operand or ('immediate' in operand and 'value' in operand['immediate']):
|
||||||
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'int'
|
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'int'
|
||||||
if 'float' in operand or ('immediate' in operand and 'float' in operand['immediate']):
|
if 'float' in operand or ('immediate' in operand and 'float' in operand['immediate']):
|
||||||
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'float'
|
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'float'
|
||||||
if 'double' in operand or ('immediate' in operand and 'double' in operand['immediate']):
|
if 'double' in operand or ('immediate' in operand and 'double' in operand['immediate']):
|
||||||
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'double'
|
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'double'
|
||||||
|
# identifier
|
||||||
if 'identifier' in operand or (
|
if 'identifier' in operand or (
|
||||||
'immediate' in operand and 'identifier' in operand['immediate']
|
'immediate' in operand and 'identifier' in operand['immediate']
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ def reduce_to_section(kernel, isa):
|
|||||||
else:
|
else:
|
||||||
raise ValueError('ISA not supported.')
|
raise ValueError('ISA not supported.')
|
||||||
if start == -1:
|
if start == -1:
|
||||||
raise LookupError('Could not find START MARKER. Make sure it is inserted!')
|
start = 0
|
||||||
if end == -1:
|
if end == -1:
|
||||||
raise LookupError('Could not find END MARKER. Make sure it is inserted!')
|
end = len(kernel)
|
||||||
return kernel[start:end]
|
return kernel[start:end]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -178,120 +178,115 @@ class TestMarkerUtils(unittest.TestCase):
|
|||||||
|
|
||||||
def test_marker_special_cases_AArch(self):
|
def test_marker_special_cases_AArch(self):
|
||||||
bytes_line = '.byte 213,3,32,31\n'
|
bytes_line = '.byte 213,3,32,31\n'
|
||||||
mov_start = 'mov x1, #111\n'
|
start_marker = 'mov x1, #111\n' + bytes_line
|
||||||
mov_end = 'mov x1, #222\n'
|
end_marker = 'mov x1, #222\n' + bytes_line
|
||||||
prologue = 'dup v0.2d, x14\n' + ' neg x9, x9\n' + ' .p2align 6\n'
|
prologue = (
|
||||||
|
'dup v0.2d, x14\n'
|
||||||
|
'neg x9, x9\n'
|
||||||
|
'.p2align 6\n')
|
||||||
kernel = (
|
kernel = (
|
||||||
'.LBB0_28:\n'
|
'.LBB0_28:\n'
|
||||||
+ 'fmul v7.2d, v7.2d, v19.2d\n'
|
+ 'fmul v7.2d, v7.2d, v19.2d\n'
|
||||||
+ 'stp q0, q1, [x10, #-32]\n'
|
+ 'stp q0, q1, [x10, #-32]\n'
|
||||||
+ 'b.ne .LBB0_28\n'
|
+ 'b.ne .LBB0_28\n')
|
||||||
)
|
epilogue = (
|
||||||
epilogue = '.LBB0_29: // Parent Loop BB0_20 Depth=1\n' + 'bl dummy\n'
|
'.LBB0_29: // Parent Loop BB0_20 Depth=1\n'
|
||||||
kernel_length = len(list(filter(None, kernel.split('\n'))))
|
'bl dummy\n')
|
||||||
|
|
||||||
# marker directly at the beginning
|
samples = [
|
||||||
code_beginning = mov_start + bytes_line + kernel + mov_end + bytes_line + epilogue
|
# (test name,
|
||||||
beginning_parsed = self.parser_AArch.parse_file(code_beginning)
|
# ignored prologue, section to be extraced, ignored epilogue)
|
||||||
test_kernel = reduce_to_section(beginning_parsed, 'AArch64')
|
("markers",
|
||||||
self.assertEqual(len(test_kernel), kernel_length)
|
prologue + start_marker, kernel, end_marker + epilogue),
|
||||||
kernel_start = len(list(filter(None, (mov_start + bytes_line).split('\n'))))
|
("marker at file start",
|
||||||
parsed_kernel = self.parser_AArch.parse_file(kernel, start_line=kernel_start)
|
start_marker, kernel, end_marker + epilogue),
|
||||||
self.assertEqual(test_kernel, parsed_kernel)
|
("no start marker",
|
||||||
|
'', prologue + kernel, end_marker + epilogue),
|
||||||
|
("marker at file end",
|
||||||
|
prologue + start_marker, kernel, end_marker),
|
||||||
|
("no end marker",
|
||||||
|
prologue + start_marker, kernel + epilogue, ''),
|
||||||
|
("empty kernel",
|
||||||
|
prologue + start_marker, '', end_marker + epilogue),
|
||||||
|
]
|
||||||
|
|
||||||
# marker at the end
|
for test_name, pro, kernel, epi in samples:
|
||||||
code_end = prologue + mov_start + bytes_line + kernel + mov_end + bytes_line + epilogue
|
code = pro + kernel + epi
|
||||||
end_parsed = self.parser_AArch.parse_file(code_end)
|
parsed = self.parser_AArch.parse_file(code)
|
||||||
test_kernel = reduce_to_section(end_parsed, 'AArch64')
|
test_kernel = reduce_to_section(parsed, 'AArch64')
|
||||||
self.assertEqual(len(test_kernel), kernel_length)
|
if kernel:
|
||||||
kernel_start = len(list(filter(None, (prologue + mov_start + bytes_line).split('\n'))))
|
kernel_length = len(kernel.strip().split('\n'))
|
||||||
parsed_kernel = self.parser_AArch.parse_file(kernel, start_line=kernel_start)
|
else:
|
||||||
self.assertEqual(test_kernel, parsed_kernel)
|
kernel_length = 0
|
||||||
|
self.assertEqual(
|
||||||
# no kernel
|
len(test_kernel), kernel_length,
|
||||||
code_empty = prologue + mov_start + bytes_line + mov_end + bytes_line + epilogue
|
msg="Invalid exctracted kernel length on {!r} sample".format(test_name))
|
||||||
empty_parsed = self.parser_AArch.parse_file(code_empty)
|
if pro:
|
||||||
test_kernel = reduce_to_section(empty_parsed, 'AArch64')
|
kernel_start = len((pro).strip().split('\n'))
|
||||||
self.assertEqual(len(test_kernel), 0)
|
else:
|
||||||
kernel_start = len(list(filter(None, (prologue + mov_start + bytes_line).split('\n'))))
|
kernel_start = 0
|
||||||
self.assertEqual(test_kernel, [])
|
parsed_kernel = self.parser_AArch.parse_file(kernel, start_line=kernel_start)
|
||||||
|
self.assertEqual(
|
||||||
# no start marker
|
test_kernel, parsed_kernel,
|
||||||
code_no_start = prologue + bytes_line + kernel + mov_end + bytes_line + epilogue
|
msg="Invalid exctracted kernel on {!r}".format(test_name))
|
||||||
no_start_parsed = self.parser_AArch.parse_file(code_no_start)
|
|
||||||
with self.assertRaises(LookupError):
|
|
||||||
reduce_to_section(no_start_parsed, 'AArch64')
|
|
||||||
|
|
||||||
# no end marker
|
|
||||||
code_no_end = prologue + mov_start + bytes_line + kernel + mov_end + epilogue
|
|
||||||
no_end_parsed = self.parser_AArch.parse_file(code_no_end)
|
|
||||||
with self.assertRaises(LookupError):
|
|
||||||
reduce_to_section(no_end_parsed, 'AArch64')
|
|
||||||
|
|
||||||
# no marker at all
|
|
||||||
code_no_marker = prologue + kernel + epilogue
|
|
||||||
no_marker_parsed = self.parser_AArch.parse_file(code_no_marker)
|
|
||||||
with self.assertRaises(LookupError):
|
|
||||||
reduce_to_section(no_marker_parsed, 'AArch64')
|
|
||||||
|
|
||||||
def test_marker_special_cases_x86(self):
|
def test_marker_special_cases_x86(self):
|
||||||
bytes_line = '.byte 100\n.byte 103\n.byte 144\n'
|
bytes_line = (
|
||||||
mov_start = 'movl $111, %ebx\n'
|
'.byte 100\n'
|
||||||
mov_end = 'movl $222, %ebx\n'
|
'.byte 103\n'
|
||||||
prologue = 'movl -88(%rbp), %r10d\n' + 'xorl %r11d, %r11d\n' + '.p2align 4,,10\n'
|
'.byte 144\n')
|
||||||
|
start_marker = 'movl $111, %ebx\n' + bytes_line
|
||||||
|
end_marker = 'movl $222, %ebx\n' + bytes_line
|
||||||
|
prologue = (
|
||||||
|
'movl -88(%rbp), %r10d\n'
|
||||||
|
'xorl %r11d, %r11d\n'
|
||||||
|
'.p2align 4,,10\n')
|
||||||
kernel = (
|
kernel = (
|
||||||
'.L3: #L3\n'
|
'.L3: #L3\n'
|
||||||
+ 'vmovsd .LC1(%rip), %xmm0\n'
|
'vmovsd .LC1(%rip), %xmm0\n'
|
||||||
+ 'vmovsd %xmm0, (%r15,%rcx,8)\n'
|
'vmovsd %xmm0, (%r15,%rcx,8)\n'
|
||||||
+ 'cmpl %ecx, %ebx\n'
|
'cmpl %ecx, %ebx\n'
|
||||||
+ 'jle .L3\n'
|
'jle .L3\n')
|
||||||
)
|
epilogue = (
|
||||||
epilogue = 'leaq -56(%rbp), %rsi\n' + 'movl %r10d, -88(%rbp)\n' + 'call timing\n'
|
'leaq -56(%rbp), %rsi\n'
|
||||||
kernel_length = len(list(filter(None, kernel.split('\n'))))
|
'movl %r10d, -88(%rbp)\n'
|
||||||
|
'call timing\n')
|
||||||
|
samples = [
|
||||||
|
# (test name,
|
||||||
|
# ignored prologue, section to be extraced, ignored epilogue)
|
||||||
|
("markers",
|
||||||
|
prologue + start_marker, kernel, end_marker + epilogue),
|
||||||
|
("marker at file start",
|
||||||
|
start_marker, kernel, end_marker + epilogue),
|
||||||
|
("no start marker",
|
||||||
|
'', prologue + kernel, end_marker + epilogue),
|
||||||
|
("marker at file end",
|
||||||
|
prologue + start_marker, kernel, end_marker),
|
||||||
|
("no end marker",
|
||||||
|
prologue + start_marker, kernel + epilogue, ''),
|
||||||
|
("empty kernel",
|
||||||
|
prologue + start_marker, '', end_marker + epilogue),
|
||||||
|
]
|
||||||
|
|
||||||
# marker directly at the beginning
|
for test_name, pro, kernel, epi in samples:
|
||||||
code_beginning = mov_start + bytes_line + kernel + mov_end + bytes_line + epilogue
|
code = pro + kernel + epi
|
||||||
beginning_parsed = self.parser_x86.parse_file(code_beginning)
|
parsed = self.parser_x86.parse_file(code)
|
||||||
test_kernel = reduce_to_section(beginning_parsed, 'x86')
|
test_kernel = reduce_to_section(parsed, 'x86')
|
||||||
self.assertEqual(len(test_kernel), kernel_length)
|
if kernel:
|
||||||
kernel_start = len(list(filter(None, (mov_start + bytes_line).split('\n'))))
|
kernel_length = len(kernel.strip().split('\n'))
|
||||||
parsed_kernel = self.parser_x86.parse_file(kernel, start_line=kernel_start)
|
else:
|
||||||
self.assertEqual(test_kernel, parsed_kernel)
|
kernel_length = 0
|
||||||
|
self.assertEqual(
|
||||||
# marker at the end
|
len(test_kernel), kernel_length,
|
||||||
code_end = prologue + mov_start + bytes_line + kernel + mov_end + bytes_line + epilogue
|
msg="Invalid exctracted kernel length on {!r} sample".format(test_name))
|
||||||
end_parsed = self.parser_x86.parse_file(code_end)
|
if pro:
|
||||||
test_kernel = reduce_to_section(end_parsed, 'x86')
|
kernel_start = len((pro).strip().split('\n'))
|
||||||
self.assertEqual(len(test_kernel), kernel_length)
|
else:
|
||||||
kernel_start = len(list(filter(None, (prologue + mov_start + bytes_line).split('\n'))))
|
kernel_start = 0
|
||||||
parsed_kernel = self.parser_x86.parse_file(kernel, start_line=kernel_start)
|
parsed_kernel = self.parser_x86.parse_file(kernel, start_line=kernel_start)
|
||||||
self.assertEqual(test_kernel, parsed_kernel)
|
self.assertEqual(
|
||||||
|
test_kernel, parsed_kernel,
|
||||||
# no kernel
|
msg="Invalid exctracted kernel on {!r}".format(test_name))
|
||||||
code_empty = prologue + mov_start + bytes_line + mov_end + bytes_line + epilogue
|
|
||||||
empty_parsed = self.parser_x86.parse_file(code_empty)
|
|
||||||
test_kernel = reduce_to_section(empty_parsed, 'x86')
|
|
||||||
self.assertEqual(len(test_kernel), 0)
|
|
||||||
kernel_start = len(list(filter(None, (prologue + mov_start + bytes_line).split('\n'))))
|
|
||||||
self.assertEqual(test_kernel, [])
|
|
||||||
|
|
||||||
# no start marker
|
|
||||||
code_no_start = prologue + bytes_line + kernel + mov_end + bytes_line + epilogue
|
|
||||||
no_start_parsed = self.parser_x86.parse_file(code_no_start)
|
|
||||||
with self.assertRaises(LookupError):
|
|
||||||
reduce_to_section(no_start_parsed, 'x86')
|
|
||||||
|
|
||||||
# no end marker
|
|
||||||
code_no_end = prologue + mov_start + bytes_line + kernel + mov_end + epilogue
|
|
||||||
no_end_parsed = self.parser_x86.parse_file(code_no_end)
|
|
||||||
with self.assertRaises(LookupError):
|
|
||||||
reduce_to_section(no_end_parsed, 'x86')
|
|
||||||
|
|
||||||
# no marker at all
|
|
||||||
code_no_marker = prologue + kernel + epilogue
|
|
||||||
no_marker_parsed = self.parser_x86.parse_file(code_no_marker)
|
|
||||||
with self.assertRaises(LookupError):
|
|
||||||
reduce_to_section(no_marker_parsed, 'x86')
|
|
||||||
|
|
||||||
def test_find_jump_labels(self):
|
def test_find_jump_labels(self):
|
||||||
self.assertEqual(find_jump_labels(self.parsed_x86),
|
self.assertEqual(find_jump_labels(self.parsed_x86),
|
||||||
|
|||||||
Reference in New Issue
Block a user