Skip to content

Commit

Permalink
i#3044 AArch64 SVE: Add SVE support to generation scripts.
Browse files Browse the repository at this point in the history
Issue: #3044

Change-Id: I8af06df778c203498a5c247bdc19b5c2064a1766
  • Loading branch information
fhahn committed Jun 28, 2018
1 parent 88eec56 commit ddfcf00
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 53 deletions.
44 changes: 28 additions & 16 deletions tools/aarch64_gen_patterns_from_isa/generate_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@
# DAMAGE.

ARG_TO_REG = {
'h0': ('Rd', 'The output register.'),
'h5': ('Rm', 'The first input register.'),
'h16': ('Rn', 'The second input register.'),
'h10': ('Ra', 'The third input register.'),
's0': ('Rd', 'The output register.'),
's5': ('Rm', 'The first input register.'),
's16': ('Rn', 'The second input register.'),
's10': ('Ra', 'The third input register.'),
'd0': ('Rd', 'The output register.'),
'd5': ('Rm', 'The first input register.'),
'd16': ('Rn', 'The second input register.'),
'd10': ('Ra', 'The third input register.'),
'dq0': ('Rd', 'The output register.'),
'dq5': ('Rm', 'The first input register.'),
'dq16': ('Rn', 'The second input register.'),
Expand All @@ -37,17 +49,17 @@
'float_reg5': ('Rm', 'The first input register.'),
'float_reg16': ('Rn', 'The second input register.'),
'float_reg10': ('Ra', 'The third input register.'),
'sd_sz': ('width', 'The vector element width. Use either OPND_CREATE_HALF(), \n * OPND_CREATE_SINGLE() or OPND_CREATE_DOUBLE().'),
'hsd_sz': ('width', 'The vector element width. Use either OPND_CREATE_HALF(), \n * OPND_CREATE_SINGLE() or OPND_CREATE_DOUBLE().'),
'bhsd_sz': ('width', 'The vector element width. Use either OPND_CREATE_BYTE(), OPND_CREATE_HALF(), \n * OPND_CREATE_SINGLE() or OPND_CREATE_DOUBLE().'),
'bhs_sz': ('width', 'The vector element width. Use either OPND_CREATE_BYTE(), OPND_CREATE_HALF(), \n * OPND_CREATE_SINGLE().'),
'hs_sz': ('width', 'The vector element width. Use either OPND_CREATE_HALF(), \n * OPND_CREATE_SINGLE().'),
'b_sz': ('width', 'The vector element width. Use either OPND_CREATE_BYTE().'),
}

TYPE_TO_STR2 = {
'advsimd': 'vector',
'float': 'scalar',
'z0': ('Zd', 'The output SVE vector register.'),
'z5': ('Zm', 'The first input SVE vector register.'),
'z16': ('Zn', 'The second input SVE vector register.'),
'z10': ('Za', 'The third input SVE vector register.'),
'p10_low': ('Pg', 'Predicate register for predicated instruction, P0-P7.'),
'sd_sz': ('width', 'The vector element width. Use either OPND_CREATE_HALF(),\n * OPND_CREATE_SINGLE() or OPND_CREATE_DOUBLE().'),
'hsd_sz': ('width', 'The vector element width. Use either OPND_CREATE_HALF(),\n * OPND_CREATE_SINGLE() or OPND_CREATE_DOUBLE().'),
'bhsd_sz': ('width', 'The vector element width. Use either OPND_CREATE_BYTE(),\n * OPND_CREATE_HALF(), OPND_CREATE_SINGLE() or OPND_CREATE_DOUBLE().'),
'bhs_sz': ('width', 'The vector element width. Use either OPND_CREATE_BYTE(),\n * OPND_CREATE_HALF() or OPND_CREATE_SINGLE().'),
'hs_sz': ('width', 'The vector element width. Use either OPND_CREATE_HALF() or\n * OPND_CREATE_SINGLE().'),
'b_sz': ('width', 'The vector element width. Use OPND_CREATE_BYTE().'),
}


Expand All @@ -60,18 +72,18 @@ def get_doc_comments(enc):
params = [' * \param {}'.format(get_param_comment(p)) for p in enc.outputs] + \
[' * \param {}'.format(get_param_comment(p)) for p in enc.inputs_no_dst()]

if enc.reads_dst():
if enc.reads_dst:
params[0] = params[0] + ' The instruction also reads this register.'

comment = """
/**
* Creates a {} {} instruction.
* \param dc The void * dcontext used to allocate memory for the instr_t.
* \param dc The void * dcontext used to allocate memory for the instr_t.
{}
*/
"""
return comment.format(
enc.mnemonic, enc.type_as_str(), '\n'.join(params))
enc.mnemonic.upper(), enc.type_as_str(), '\n'.join(params))


def get_macro(enc):
Expand All @@ -81,8 +93,8 @@ def get_macro(enc):

args_def = ', '.join(ARG_TO_REG[p][0]
for p in enc.outputs + enc.inputs_no_dst())
return '#define INSTR_CREATE_{}_{}(dc, {}) \\\n{}'.format(
enc.mnemonic, TYPE_TO_STR2[enc.class_info['instr-class']], args_def, call)
return '#define {}(dc, {}) \\\n{}'.format(
enc.get_macro_name() , args_def, call)


def get_macro_string(enc):
Expand Down
59 changes: 44 additions & 15 deletions tools/aarch64_gen_patterns_from_isa/generate_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@

TYPE_TO_STR2 = {
'advsimd': 'vector',
'sve': 'vector',
'float': 'scalar',
}


def generate_size_strs(selected):
def generate_size_strs(selected, enc):
res = []
if enc.is_sve():
if selected == 'bhsd':
return ['$0x00', '$0x01', '$0x02', '$0x03']
assert False
for s in selected:
if s == 'b':
res += ['$0x00', '$0x00']
Expand All @@ -62,6 +67,14 @@ def generate_vreg_strs(selected):
filtered = [(asm, ir) for (asm, ir) in combined if asm[-1] in selected]
return zip(*filtered)

def generate_vreg_sve_strs(selected):
full_asm = ['z{}.b', 'z{}.h', 'z{}.s', 'z{}.d']
full_ir = ['%z{}', '%z{}', '%z{}', '%z{}']
combined = zip(full_asm, full_ir)

filtered = [ (asm, ir) for (asm, ir) in combined if asm[-1] in selected ]
return zip(*filtered)


def generate_reg_strs(op, enc):
"""
Expand All @@ -73,21 +86,28 @@ def generate_reg_strs(op, enc):
different element sizes.
"""
if op.endswith('_sz'):
return [], generate_size_strs(op.replace('_sz', ''))
return [], generate_size_strs(op.replace('_sz', ''), enc)

if not op.startswith('dq') and not op.startswith('float_reg'):
if not op.startswith('dq') and not op.startswith('float_reg') and not op.startswith('z') and not op.startswith('p'):
num = random.randint(0, 31)
return ['{}{}'.format(op[0], num)], ['%{}{}'.format(op[0], num)]

asm = []
ir = []

num = random.randint(0, 31)
if op.startswith('dq'):
temp_asm, temp_ir = generate_vreg_strs(enc.get_selected_sizes())
elif op.startswith('float_reg'):
temp_asm = ['d{}', 's{}', 'h{}']
temp_ir = ['%d{}', '%s{}', '%h{}']
elif op.startswith('z'):
temp_asm, temp_ir = generate_vreg_sve_strs(enc.get_selected_sizes())
elif op.startswith('p10_low'):
num = random.randint(0, 7)
temp_asm = ['p{}/m'] * 4
temp_ir = ['%p{}'] * 4

num = random.randint(0, 31)
for (t_asm, t_ir) in zip(temp_asm, temp_ir):
asm.append(t_asm.format(num))
ir.append(t_ir.format(num))
Expand All @@ -106,25 +126,25 @@ def ir_arg_to_c(ir):
"""
Returns a string to create ir in C.
"""
for (ir_prefix, c) in [('%d', 'D'), ('%q', 'Q'), ('%s', 'S'), ('%h', 'H')]:
for (ir_prefix, c) in [('%d', 'D'), ('%q', 'Q'), ('%s', 'S'), ('%h', 'H'), ('%z', 'Z'), ('%p', 'P')]:
if not ir.startswith(ir_prefix):
continue
return "opnd_create_reg(DR_REG_" + c + ir.replace(ir_prefix, '') + ")"
return SIZE_TO_MACRO[ir]


def generate_api_test(opcode, ir_ops, str_type):
def generate_api_test(enc, ir_ops):
"""
Returns C statements to create an instruction with opcode and ir_ops as
arguments, as well as a call to test_instr_encoding for the generated
instruction.
"""
c_args = [ir_arg_to_c(ir) for ir in ir_ops]
macro_start = ' instr = INSTR_CREATE_{}_{}(dc,'.format(opcode, str_type)
macro_start = ' instr = {}(dc,'.format(enc.get_macro_name())
return '\n'.join(['',
'{}\n{});'.format(macro_start,
',\n'.join((len(macro_start) - 3) * ' ' + arg for arg in c_args)),
' test_instr_encoding(dc, OP_{}, instr);'.format(opcode)])
' test_instr_encoding(dc, OP_{}, instr);'.format(enc.mnemonic)])


def generate_dis_test(mnemonic, asm_ops, ir_str):
Expand All @@ -142,7 +162,7 @@ def generate_dis_test(mnemonic, asm_ops, ir_str):
f.write('\n')

subprocess.check_call(
["gcc", "-march=armv8.3-a", "-c", "-o", "/tmp/autogen.o", "/tmp/autogen.s", ])
["gcc", "-march=armv8.3-a+sve", "-c", "-o", "/tmp/autogen.o", "/tmp/autogen.s", ])
out = subprocess.check_output(["objdump", "-d", "/tmp/autogen.o"])
enc_str = out.decode('utf-8').split('\n')[-2][6:14]
return '{} : {:<40} : {}'.format(enc_str, asm_str, ir_str)
Expand All @@ -168,7 +188,9 @@ def num_combinations_to_test(enc):
szs = [s for s in enc.inputs if s.endswith('sz')]
if len(szs) == 0:
return 2
return len(list(generate_vreg_strs(szs[0].replace('_sz', ''))))
return len(generate_size_strs(szs[0].replace('_sz', ''), enc))
elif enc.is_sve():
return 4


def generate_test_strings(enc):
Expand All @@ -184,7 +206,7 @@ def generate_test_strings(enc):
api_tests_expected = []
num_strs = num_combinations_to_test(enc)

# Requires GCC8....
# Requires GCC8...., so manually add them for now.
if enc.mnemonic in ('fmlal', 'fmlal2', 'fmlsl', 'fmlsl2'):
asm_ops.append(['v2.2s', 'v6.4s'])
output_ir.append(['%d2', '%q6'])
Expand All @@ -196,9 +218,10 @@ def generate_test_strings(enc):
asm, ir = generate_reg_strs(op, enc)
asm_ops.append(asm)
output_ir.append(ir)
if enc.reads_dst():
if enc.reads_dst and not enc.is_sve():
input_ir.append(ir)


for op in enc.inputs:
asm, ir = generate_reg_strs(op, enc)
if op == 'dq0':
Expand All @@ -208,6 +231,13 @@ def generate_test_strings(enc):
if ir:
input_ir.append(ir)


if enc.reads_dst and enc.is_sve():
if 'p10_low' in enc.inputs or 'p10' in enc.inputs:
asm_ops[2] = asm_ops[0]
input_ir[1] = output_ir[0]
else:
assert False
# Above we built tables like
# input_asm = [ [ v1, v4],
# [ v9, v7] ]
Expand All @@ -225,13 +255,12 @@ def generate_test_strings(enc):

test_lines.append(generate_dis_test(enc.mnemonic, asm, ir_str))

if enc.reads_dst():
if enc.reads_dst and not enc.is_sve():
api_in_ir = in_ir[1:]
else:
api_in_ir = in_ir

api_tests.append(generate_api_test(enc.mnemonic, out_ir +
api_in_ir, TYPE_TO_STR2[enc.class_info['instr-class']]))
api_tests.append(generate_api_test(enc, out_ir + api_in_ir))
api_tests_expected.append(ir_str)

return test_lines, api_tests, api_tests_expected
Loading

0 comments on commit ddfcf00

Please sign in to comment.