Skip to content

Commit

Permalink
Merge branch 'master' into detach_x86
Browse files Browse the repository at this point in the history
  • Loading branch information
onroadmuwl authored Jan 29, 2024
2 parents 7372f3c + 1d4659e commit 4d38b5b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 110 deletions.
147 changes: 47 additions & 100 deletions core/ir/aarch64/codec.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@
N = 32 # bits in an instruction word
ONES = (1 << N) - 1

# Stores instances of FallthroughDecode objects for resolution of overlapping
# encodings.
FALLTHROUGH = dict()

opnd_header = '/* This file was generated by codec.py from opnd_defs.txt and the codec_<version>.txt files. */\n\n'
opcode_header = '/* This file was generated by codec.py from codec_<version>.txt files. */\n\n'

Expand Down Expand Up @@ -87,13 +83,6 @@ def __init__(self, fixed, dsts, srcs, enc_order):
self.srcs = srcs
self.enc_order = enc_order

class FallthroughDecode:
def __init__(self, opcode, opndset='', decode_clause='', decode_function=''):
self.flag_name = opcode + '_fallthrough_flag'
self.opndset = opndset
self.decode_clause = decode_clause
self.decode_function = decode_function

class Pattern:
def __init__(self, pattern, opcode_bits, opnd_bits, high_soft_bits, opcode, opndset, enum, feat):
self.pattern = pattern
Expand All @@ -106,6 +95,7 @@ def __init__(self, pattern, opcode_bits, opnd_bits, high_soft_bits, opcode, opnd
self.opndset = opndset
self.enum = enum
self.feat = feat
self._generated_name = None

def __iter__(self):
for field in (self.opcode_bits, self.opnd_bits, self.opcode, self.opndset):
Expand All @@ -124,16 +114,25 @@ def ignored_bit_mask(self):
def set_bits(self):
return self.opcode_bits | self.high_soft_bits

def set_generated_name(self, name):
"""
Generated names need to take account of all possible patterns,
so can't be simply derived from a single pattern
"""
self._generated_name = name

@property
def generated_name(self):
if self._generated_name is None:
raise Exception("Attempted to use generated name before it was set")
return self._generated_name


def codec_header(isa_version):
return '/* This file was generated by codec.py from codec_%s.txt. */\n\n' % isa_version

def fallthrough_instr_id(opcode, opcode_bits, opnd_bits):
return '%s_%08x_%08x' % (opcode, opcode_bits, opnd_bits)

def generate_opndset_decoders(opndsettab, opndtab):
c = []
c += ['bool {} = false;'.format(opcode.flag_name) for opcode in
FALLTHROUGH.values()]
c += ['\n']
for name in sorted(opndsettab):
opnd_set = opndsettab[name]
Expand All @@ -142,7 +141,7 @@ def generate_opndset_decoders(opndsettab, opndtab):
c += ['static bool',
'decode_opnds%s(uint enc, dcontext_t *dcontext, byte *pc, '
'instr_t *instr, int opcode)' % name, '{']
if dsts + srcs != []:
if dsts or srcs:
vars = (['dst%d' % i for i in range(len(dsts))] +
['src%d' % i for i in range(len(srcs))])
tests = (['!decode_opnd_%s(enc & 0x%08x, opcode, pc, &dst%d)' %
Expand Down Expand Up @@ -189,7 +188,7 @@ def indent_append(text):

not_zero_mask = 0
try:
opnd_set = opndsettab[pattern.opndset]
opnd_set = opndsettab[pattern.generated_name]
for mask in (opndtab[o].non_zero for o in opnd_set.dsts + opnd_set.srcs):
not_zero_mask |= mask
except KeyError:
Expand Down Expand Up @@ -220,20 +219,8 @@ def indent_append(text):
'manually handled in codec.c\'s decode_common().' % pattern.opcode)
else:
indent_append(' ASSERT(0);')
enc_key = fallthrough_instr_id(
pattern.opcode, pattern.opcode_bits, pattern.opnd_bits)
if enc_key in FALLTHROUGH and pattern.opndset == FALLTHROUGH[enc_key].opndset:
indent_append(' %s = true;' % FALLTHROUGH[enc_key].flag_name)
FALLTHROUGH[enc_key].decode_clause = \
'if ((enc & 0x%08x) == 0x%08x && %s == true)' % \
(((1 << N) - 1) & pattern.ignored_bit_mask(), pattern.opcode_bits, \
FALLTHROUGH[enc_key].flag_name)
FALLTHROUGH[enc_key].decode_function = \
'return decode_opnds%s(enc, dc, pc, instr, OP_%s);' % \
(pattern.opndset, pattern.opcode)
else:
indent_append(' return decode_opnds%s(enc, dc, pc, '
'instr, OP_%s);' % (pattern.opndset, pattern.opcode))
indent_append(' return decode_opnds%s(enc, dc, pc, '
'instr, OP_%s);' % (pattern.generated_name, pattern.opcode))
if opc_props[pattern.opcode].nzcv_rw != 'n':
indent_append('}')
return
Expand Down Expand Up @@ -276,9 +263,6 @@ def indent_append(text):
'decoder_' + curr_isa + '(uint enc, dcontext_t *dc, byte *pc, instr_t *instr)',
'{']
gen(c, patterns, 1)
for opcode in FALLTHROUGH.values():
c += [' %s' % opcode.decode_clause]
c += [' %s' % opcode.decode_function]
# Call the next version of the decoder if defined.
if next_isa != '':
c.append(' return decoder_' + next_isa + '(enc, dc, pc, instr);')
Expand All @@ -297,7 +281,7 @@ def find_required(fixed, reordered, i, opndtab):
if opndtab[reordered[j][2]].gen & used & ~known != 0:
req = req + ['%s%d' % (reordered[j][0], reordered[j][1])]
known = known | opndtab[reordered[j][2]].gen
return 'enc' if req == [] else '(enc | %s)' % ' | '.join(req)
return 'enc' if not req else '(%s)' % ' | '.join(['enc'] + req)

def make_enc(n, reordered, f, opndtab):
(ds, i, ot) = reordered[n]
Expand Down Expand Up @@ -362,11 +346,11 @@ def generate_opndset_encoders(opndsettab, opndtab):
def generate_encoder(patterns, opndsettab, opndtab, opc_props, curr_isa, next_isa):
c = []
case = dict()
for p in patterns:
(opcode_bits, opnd_bits, opcode, opndset) = p
if opcode not in case:
case[opcode] = []
case[opcode].append(p)
for pattern in patterns:
try:
case[pattern.opcode].append(pattern)
except KeyError:
case[pattern.opcode] = [pattern]

c += ['static uint',
'encoder_' + curr_isa + '(byte *pc, instr_t *instr, decode_info_t *di)',
Expand All @@ -375,9 +359,8 @@ def generate_encoder(patterns, opndsettab, opndtab, opc_props, curr_isa, next_is
' (void)enc;',
' switch (instr->opcode) {']

def reorder_key(t):
opcode_bits, opnd_bits, opcode, opndset = t
return (opcode, opndset, opcode_bits, opnd_bits)
def pattern_sort_key(p):
return (p.opcode, p.generated_name, p.opcode_bits, p.opnd_bits)

for opcode in sorted(case):
c.append(' case OP_%s:' % opcode)
Expand All @@ -386,26 +369,26 @@ def reorder_key(t):
c.append(' if (!proc_has_feature(FEATURE_%s))' % opc_props[opcode].feat)
c.append(' return ENCFAIL;')
c.append('# endif')
patterns = sorted(case[opcode], key=reorder_key)
patterns = sorted(case[opcode], key=pattern_sort_key)
last_pattern = patterns.pop()
for pattern in patterns:
c.append(' enc = encode_opnds%s(pc, instr, 0x%08x, di);' % (
opnd_stem(pattern.opndset), pattern.set_bits()))
opnd_stem(pattern.generated_name), pattern.set_bits()))
c.append(' if (enc != ENCFAIL)')
c.append(' return enc;')
# Fallthrough to call the next version of the encoder if defined.
if next_isa != '':
c.append(' enc = encode_opnds%s(pc, instr, 0x%08x, di);' % (
last_pattern.opndset, last_pattern.set_bits()))
last_pattern.generated_name, last_pattern.set_bits()))
c.append(' if (enc != ENCFAIL)')
c.append(' return enc;')
c += [' break;']
else:
c.append(' return encode_opnds%s(pc, instr, 0x%08x, di);' % (
last_pattern.opndset, last_pattern.set_bits()))
last_pattern.generated_name, last_pattern.set_bits()))
c += [' }']
# Call the next version of the encoder if defined.
if next_isa != '':
if next_isa:
c += [' return encoder_' + next_isa + '(pc, instr, di);']
else:
c += [' return ENCFAIL;']
Expand Down Expand Up @@ -551,15 +534,15 @@ def __getitem__(self, key):
for line in (l.split('#')[0].strip() for l in file):
if not line:
continue
if not re.match('^[x\?\-\+]{32} +[a-zA-Z_0-9]+$', line):
if not re.match(r'^[x\?\-\+]{32} +[a-zA-Z_0-9]+$', line):
raise Exception('Cannot parse line: %s in %s' % (line, file_msg))
# Syntax: mask opndtype
mask, opndtype = line.split()
if opndtype in opndtab:
raise Exception('Repeated definition of opndtype %s in %s' % (opndtype, file_msg))
opndtab[opndtype] = Opnd(int(re.sub('[x\+]', '1', re.sub('[^x^\+]', '0', mask)), 2),
int(re.sub('\?', '1', re.sub('[^\?]', '0', mask)), 2),
int(re.sub('\+', '1', re.sub('[^\+]', '0', mask)), 2))
opndtab[opndtype] = Opnd(int(re.sub(r'[x\+]', '1', re.sub(r'[^x^\+]', '0', mask)), 2),
int(re.sub(r'\?', '1', re.sub(r'[^\?]', '0', mask)), 2),
int(re.sub(r'\+', '1', re.sub(r'[^\+]', '0', mask)), 2))
except IOError as e:
raise Exception('Unable to read operand definitions file, {}: {}'.format(path, e.strerror))

Expand All @@ -574,7 +557,7 @@ def read_codec_file(path):
for line in (l.split('#')[0].strip() for l in file):
if not line:
continue
if re.match('^[01x\^]{32} +[n|r|w|rw|wr|er|ew]+ +[0-9]+ +[a-zA-Z0-9]* +[a-zA-Z_0-9][a-zA-Z_0-9 \.]*:[a-zA-Z_0-9 \.]*$', line):
if re.match(r'^[01x\^]{32} +[n|r|w|rw|wr|er|ew]+ +[0-9]+ +[a-zA-Z0-9]* +[a-zA-Z_0-9][a-zA-Z_0-9 \.]*:[a-zA-Z_0-9 \.]*$', line):
# Syntax: pattern opcode opndtype* : opndtype*
pattern, nzcv_rw_flag, enum, feat, opcode, args = line.split(None, 5)
dsts, srcs = [a.split() for a in args.split(':')]
Expand All @@ -584,7 +567,7 @@ def read_codec_file(path):
patterns.append(Pattern(pattern, opcode_bits, opnd_bits, high_soft_bits, opcode, (dsts, srcs), enum, feat))
opc_props[opcode] = Opcode(opcode, nzcv_rw_flag, feat)
continue
if re.match('^[01x\^]{32} +[n|r|w|rw|wr|er|ew]+ +[0-9]+ +[a-zA-Z0-9]* +[a-zA-Z_0-9]+ +[a-zA-Z_0-9]+', line):
if re.match(r'^[01x\^]{32} +[n|r|w|rw|wr|er|ew]+ +[0-9]+ +[a-zA-Z0-9]* +[a-zA-Z_0-9]+ +[a-zA-Z_0-9]+', line):
# Syntax: pattern opcode opndset
pattern, nzcv_rw_flag, enum, feat, opcode, opndset = line.split()
opcode_bits = int(re.sub('x', '0', pattern), 2)
Expand Down Expand Up @@ -618,47 +601,14 @@ def consistency_check(patterns, opndtab):
for ot in dsts + srcs:
try:
unhandled_bits &= ~opndtab[ot].gen
except KeyError:
raise Exception('Undefined opndtype %s in:\n%s' %
(opnd_stem(ot), pattern_to_str(*p)))
except KeyError as e :
raise Exception(
'Undefined opndtype %s in:\n%s' %
(opnd_stem(ot), pattern_to_str(*p))) from e
if unhandled_bits:
raise Exception('Unhandled bits:\n%32s in:\n%s' %
(re.sub('1', 'x', re.sub('0', ' ', bin(unhandled_bits)[2:])),
pattern_to_str(*p)))
# Detect and mark overlapping patterns for special handling. Named as
# 'fallthrough' because the special handling is done at the end of the
# decoder's main if/then/else clauses block.
for i, pattern_a in enumerate(patterns):
for pattern_b in patterns[:i]:
non_zero_bits_a = 0
non_zero_bits_b = 0
try:
for opnd in (opndtab[op] for op in pattern_a.all_opnds()):
non_zero_bits_a &= opnd.non_zero
except KeyError:
pass
try:
for opnd in (opndtab[op] for op in pattern_b.all_opnds()):
non_zero_bits_b &= opnd.non_zero
except KeyError:
pass

zero_overlap = (
non_zero_bits_a & pattern_b.opnd_bits == 0 or
non_zero_bits_b & pattern_b.opnd_bits == 0)

if ((pattern_b.opcode_bits ^ pattern_a.opcode_bits) &
~pattern_b.opnd_bits & ~pattern_a.opnd_bits == 0 and
not zero_overlap):
print('Overlap found between:\n%s\nand\n%s' %
(pattern_to_str(*pattern_b),
pattern_to_str(*pattern_a)))
enc_key = fallthrough_instr_id(pattern_a.opcode, pattern_a.opcode_bits, pattern_a.opnd_bits)
if enc_key in FALLTHROUGH:
raise Exception('Error: multiple overlaps detected for '
'%s. Unable to resolve.\n' % enc_key)
print('Resolving overlap.')
FALLTHROUGH[enc_key] = FallthroughDecode(enc_key)

# This function reorders the operands for encoding so that no operand encoder
# requires bits that are generated by an operand encoder that has not yet
Expand Down Expand Up @@ -697,18 +647,15 @@ def opndset_naming(patterns, opndtab):
opndsettab = dict() # maps generated name to original opndsets
for p in patterns:
if type(p.opndset) is str:
new_opndset = '_' + p.opndset
function_name = '_' + p.opndset
else:
(dsts, srcs) = p.opndset
h = (' '.join(dsts), ' '.join(srcs), p.opnd_bits)
new_opndset = 'gen_%08x_%08x' % (opndsets[h], p.opnd_bits)
function_name = 'gen_%08x_%08x' % (opndsets[h], p.opnd_bits)
reordered = reorder_opnds(ONES & ~p.opnd_bits, dsts, srcs, opndtab)
if not new_opndset in opndsettab:
opndsettab[new_opndset] = reordered
p.opndset = new_opndset
enc_key = fallthrough_instr_id(p.opcode, p.opcode_bits, p.opnd_bits)
if enc_key in FALLTHROUGH:
FALLTHROUGH[enc_key].opndset = new_opndset
if not function_name in opndsettab:
opndsettab[function_name] = reordered
p.set_generated_name(function_name)
return (patterns, opndsettab)

def main():
Expand Down
Loading

0 comments on commit 4d38b5b

Please sign in to comment.