Add explicit support for AArch64

Specifies register shape and suffix for floating point and vector
registers. The former cannot be benchmarked without and the latter would
require adding the required suffixes manually in the instruction
operands. Doing both allows using them in the same manner as on x86.

Additionally there are two small changes affecting all architectures:

Allow the 'w' constraint code, which is used for vector registers on
aarch64.

Always specify a clobber for the flags register as many instructions one
might want to benchmark modify it.
This commit is contained in:
Git out :V
2020-10-20 17:15:54 +02:00
parent 9143ac609e
commit d18b4d2004

View File

@@ -2,6 +2,8 @@
import re
from itertools import zip_longest
import llvmlite.binding as llvm
# TODO use abc to force implementation of interface requirements
init_value_by_llvm_type = {'i' + bits: '3' for bits in ['1', '8', '16', '32', '64']}
@@ -16,6 +18,22 @@ init_value_by_llvm_type.update(
for vec in [2, 4, 8, 16, 32, 64]})
aarch64_llvm_type_shape = {
'float': 's',
'double': 'd'
}
aarch64_llvm_type_suffix = {
'<8 x i8>': '8b',
'<16 x i8>': '16b',
'<4 x i16>': '4h',
'<8 x i16>': '8h',
'<4 x i32>': '4s',
'<2 x i64>>': '2d',
'<4 x float>': '4s',
'<2 x double>': '2d'
}
class NotSerializableError(Exception):
pass
@@ -26,6 +44,38 @@ class Operand:
def get_constraint_char(self):
raise NotImplementedError()
def template_string(self, index):
"""
Generate template string to be used in LLVM IR call asm.
This is used to disambiguate different usage types of a single register
from its constaint code.
E.g. on aarch64 targets float types will append a shape parameter to
differentiate between single and double precision types.
:param index: Index to use for input or output constraints.
"""
# Optional ${reg:shape} parameter
shape = None
# Optional ${reg}.suffix parameter
suffix = None
target_triple = llvm.get_default_triple()
if target_triple.startswith('aarch64-'):
shape = aarch64_llvm_type_shape.get(self.llvm_type)
suffix = aarch64_llvm_type_suffix.get(self.llvm_type)
if shape == None:
shape = ''
else:
shape = ':' + shape
if suffix == None:
suffix = ''
else:
suffix = '.' + suffix
return '${{{}{}}}{}'.format(index, shape, suffix)
def __repr__(self):
return '{}({})'.format(
self.__class__.__name__,
@@ -154,7 +204,7 @@ class Register(Operand):
:param s: must have the form: "llvm_type:constraint_char"
"""
llvm_type, constraint_char = s.split(':', 1)
valid_cc = 'rx'
valid_cc = 'rxw'
if constraint_char not in valid_cc:
raise ValueError("Invalid constraint character, must be one of {!r}".format(valid_cc))
return cls(llvm_type, constraint_char)
@@ -240,7 +290,8 @@ class Instruction(Operation):
# Build constraint string from operands
constraints = ','.join(
['=' + self.destination_operand.get_constraint_char()] +
[sop.get_constraint_char() for sop in self.source_operands])
[sop.get_constraint_char() for sop in self.source_operands] +
['~{cc}'])
# Build argument string from operands and register names
operands = []
@@ -305,13 +356,13 @@ class Instruction(Operation):
if 'src' in direction and not 'dst' in direction:
src_ops.append(operand)
# replace with index string
instruction = (instruction[:m.start()] + "${}".format(src_index)
instruction = (instruction[:m.start()] + operand.template_string(src_index)
+ instruction[m.end():])
src_index += 1
if 'dst' in direction:
dst_ops.append(operand)
# replace with index string
instruction = (instruction[:m.start()] + "${}".format(dst_index)
instruction = (instruction[:m.start()] + operand.template_string(dst_index)
+ instruction[m.end():])
if 'src' in direction:
src_ops.append(Register(operand_string.split(':', 1)[0], str(dst_index)))