def dump_header_with_header(agi, fname, header_dict): """ emit the header fname. add the header in header_dict with the maximal id. this mechanism is used in order to choose header files in the build time, different build configuration use different header files. e.g. when building without AVX512 we are using the basic getters. when building with AVX512 the header that is used comes form avx512 layer. FIXME: when all avx512 will move into the base layer we can removed this mechanism and use C defines. """ _msg("HEADER DICT: %s" % header_dict) xeddir = os.path.abspath(agi.common.options.xeddir) gendir = mbuild.join(agi.common.options.gendir, 'include-private') if header_dict: header = max(header_dict, key=header_dict.get) header = os.path.normcase(header) header_basename = os.path.basename(header) _msg("HEADER: %s" % header) if os.path.exists(header): _msg("HEADER EXISTS: %s" % header) else: _msg("BADNESS - HEADER DOES NOT EXIST: %s" % header) try: shutil.copyfile(header, os.path.join(gendir, header_basename)) except: ildutil.ild_err("Failed to copyfile src=%s dst=%s" % (header, os.path.join(gendir, header_basename))) else: header_basename = None h_file = codegen.xed_file_emitter_t(xeddir, gendir, fname, shell_file=False, is_private=True) if header_basename: h_file.add_header(header_basename) h_file.start() h_file.close()
def dump_operand_accessors(self, agi): ''' Dump operand accessor to inspect the data structure xed_operand_storage_t ''' fo_list = [] h_fname = get_operand_accessors_fn() c_fname = h_fname.replace('.h', '.c') for opname in self.operand_fields.keys(): getter_fo = self._gen_op_getter_fo(opname) setter_fo = self._gen_op_setter_fo(opname) fo_list.append(getter_fo) fo_list.append(setter_fo) # generate a generic getter generic_getter = self._gen_generic_getter() generic_setter = self._gen_generic_setter() xeddir = os.path.abspath(agi.common.options.xeddir) gendir = agi.common.options.gendir h_file = codegen.xed_file_emitter_t(xeddir, gendir, h_fname, shell_file=False, is_private=False) h_file.add_header(['xed-decoded-inst.h', 'xed-operand-storage.h']) h_file.start() for fo in fo_list: decl = fo.emit_header() h_file.add_code(decl) h_file.add_code(generic_getter.emit_header()) h_file.add_code(generic_setter.emit_header()) for fo in fo_list: fo.emit_file_emitter(h_file) h_file.close() c_file = codegen.file_emitter_t(gendir, c_fname, shell_file=False) c_file.add_header(h_fname) c_file.start() generic_getter.emit_file_emitter(c_file) generic_setter.emit_file_emitter(c_file) c_file.close()
def write_table(agi,ots): """Emit the xtypes enum and write the initialization table""" fp = codegen.xed_file_emitter_t(agi.common.options.xeddir, agi.common.options.gendir, 'xed-init-operand-type-mappings.c') fp.start() fp.add_code("const xed_operand_type_info_t xed_operand_xtype_info[] = {") names = list(ots.keys()) names.sort() names = ['INVALID'] + names ots['INVALID'] = operand_type_t('INVALID','INVALID','0') for n in names: v = ots[n] s = '/* %s */ { XED_OPERAND_ELEMENT_TYPE_%s, %s },' % (n, v.dtype, v.bits_per_element) fp.add_code(s) fp.add_code_eol("}") fp.close() return fp.full_file_name
def __init__(self, lines, xeddir, gendir, base_name, type_name, prefix, namespace='XED', stream_ifdef='XED_PRINT', cplusplus=True, proto_prefix='XED_DLL_EXPORT', extra_header="xed-common-hdrs.h", upper_case=True, density='automatic', string_convert=True): self.cplusplus = cplusplus self.lines = lines self.tuples = None # list [enumer.enumer_value_t] objects self.gendir = gendir self.xeddir = xeddir self.base_name = base_name self.type_name = type_name self.prefix = prefix self.proto_prefix = proto_prefix self.extra_header = extra_header # could be a list self.upper_case = upper_case self.density = density self.string_convert = string_convert self.file_emitter = \ codegen.xed_file_emitter_t(xeddir, gendir, self.base_name +'-enum.txt', shell_file=True) self.base_fn = self.base_name + '-enum' if self.cplusplus: self.cfn = self.base_fn + '.cpp' self.hfn = self.base_fn + '.H' else: self.cfn = self.base_fn + '.c' self.hfn = self.base_fn + '.h' self.namespace = namespace self.stream_ifdef = stream_ifdef
def _gen_xed3_op_struct(agi, hfn): """ Dump xed3_oprands_struct_t definition """ xeddir = os.path.abspath(agi.common.options.xeddir) gendir = mbuild.join(agi.common.options.gendir) h_file = codegen.xed_file_emitter_t(xeddir,gendir, hfn, shell_file=False, is_private=False) h_file.add_header('xed-operand-storage.h') h_file.start() typedef_s = 'typedef struct xed3_operands_struct_s {' h_file.add_code(typedef_s) for op_name in agi.xed3_operand_names: h_file.add_code('%s %s;'% (_xed_op_type, op_name.lower())) h_file.add_code('} %s;' %_xed3_opstruct_type) h_file.close()
def dump_nt_enum_2_capture_fptr(agi, fname): """Dump mapping nt_enum -> nt_capture_fptr """ xeddir = os.path.abspath(agi.common.options.xeddir) gendir = mbuild.join(agi.common.options.gendir, 'include-private') h_file = codegen.xed_file_emitter_t(xeddir, gendir, fname, shell_file=False, is_private=True) h_file.add_header('xed-lookup-functions.h') h_file.add_header(_xed3_nt_capture_header) h_file.start() lu_name = 'xed3_nt_2_capture' xed3_capture_f_t = 'xed3_capture_function_t' fptr_typedef = 'typedef void(*%s)(%s*);' % (xed3_capture_f_t, ildutil.xed3_decoded_inst_t) fptr_typedef = 'typedef void(*%s)(xed_decoded_inst_t*);' % xed3_capture_f_t h_file.add_code(fptr_typedef) h_file.add_code(('static %s ' % xed3_capture_f_t) +\ '%s[XED_NONTERMINAL_LAST] = {' % lu_name) nonterminals = list(agi.nonterminal_dict.keys()) invalid_line = '/*XED_NONTERMINAL_INVALID*/ (%s)0,' % xed3_capture_f_t h_file.add_code(invalid_line) for nt_name in list(agi.xed3_nt_enum_val_map.values()): enum_val = 'XED_NONTERMINAL_%s' % nt_name.upper() if _skip_nt(nt_name): fn = '0' else: fn = get_xed3_nt_capture_fn(nt_name) h_file.add_code('/*%s*/ (%s)%s,' % (enum_val, xed3_capture_f_t, fn)) h_file.add_code('};') h_file.close()
def work(lines, xeddir = '.', gendir = 'obj'): tables = [] while lines: y = constant_table_t() y.read(lines) #y.dump() olines = y.emit_init() #for l in olines: # print l tables.append(y) tables=filter(lambda(x): x.valid() , tables) names=map(lambda(x): x.name , tables) srcs = emit_convert_enum(['INVALID'] + names, xeddir, gendir) src_file_name = 'xed-convert-table-init.c' hdr_file_name = 'xed-convert-table-init.h' xfe = codegen.xed_file_emitter_t(xeddir, gendir, src_file_name) xfe.add_header(hdr_file_name) xfe.start() hfe = codegen.xed_file_emitter_t(xeddir, gendir, hdr_file_name) hfe.start() xfe.add_code('xed_convert_table_t xed_convert_table[XED_OPERAND_CONVERT_LAST];') for t in tables: l = t.emit_init() l = map(lambda(x): x+'\n', l) xfe.writelines(l) fo = codegen.function_object_t('xed_init_convert_tables', 'void') s1 = 'xed_convert_table[XED_OPERAND_CONVERT_%s].table_name = %s;' % ('INVALID', '0') s2 = 'xed_convert_table[XED_OPERAND_CONVERT_%s].limit = %s;' % ('INVALID', '0') s3 = 'xed_convert_table[XED_OPERAND_CONVERT_%s].opnd = %s;' % ('INVALID', 'XED_OPERAND_INVALID') fo.add_code(s1) fo.add_code(s2) fo.add_code(s3) for t in tables: s1 = 'xed_convert_table[XED_OPERAND_CONVERT_%s].table_name = %s;' % (t.name, t.string_table_name) s2 = 'xed_convert_table[XED_OPERAND_CONVERT_%s].limit = %s;' % (t.name, len(t.value_string_pairs)) s3 = 'xed_convert_table[XED_OPERAND_CONVERT_%s].opnd = %s;' % (t.name, t.operand) fo.add_code(s1) fo.add_code(s2) fo.add_code(s3) fo.emit_file_emitter(xfe) xfe.close() hdr = [] hdr.append("typedef struct {\n") hdr.append(" const char** table_name;\n") hdr.append(" xed_operand_enum_t opnd;\n") # which operand indexes the table! hdr.append(" unsigned int limit;\n") hdr.append("} xed_convert_table_t;") hdr.append("extern xed_convert_table_t xed_convert_table[XED_OPERAND_CONVERT_LAST];") hfe.writelines(map(lambda(x): x+'\n', hdr)) hfe.close() srcs.append(hfe.full_file_name) srcs.append(xfe.full_file_name) return srcs
def work(arg): (chips, chip_features_dict) = read_database(arg.input_file_name) isa_set_per_chip_fn = dump_chip_hierarchy(arg, chips, chip_features_dict) # the XED_CHIP_ enum chips.append("ALL") chip_enum = enum_txt_writer.enum_info_t(['INVALID'] + chips, arg.xeddir, arg.gendir, 'xed-chip', 'xed_chip_enum_t', 'XED_CHIP_', cplusplus=False) chip_enum.print_enum() chip_enum.run_enumer() # Add the "ALL" chip # the XED_ISA_SET_ enum isa_set = set() for vl in chip_features_dict.values(): for v in vl: isa_set.add(v.upper()) isa_set = list(isa_set) isa_set.sort() chip_features_dict['ALL'] = isa_set isa_set = ['INVALID'] + isa_set isa_set_enum = enum_txt_writer.enum_info_t(isa_set, arg.xeddir, arg.gendir, 'xed-isa-set', 'xed_isa_set_enum_t', 'XED_ISA_SET_', cplusplus=False) isa_set_enum.print_enum() isa_set_enum.run_enumer() # the initialization file and header chip_features_cfn = 'xed-chip-features-table.c' chip_features_hfn = 'xed-chip-features-table.h' cfe = codegen.xed_file_emitter_t(arg.xeddir, arg.gendir, chip_features_cfn, shell_file=False) private_gendir = os.path.join(arg.gendir, 'include-private') hfe = codegen.xed_file_emitter_t(arg.xeddir, private_gendir, chip_features_hfn, shell_file=False) for header in ['xed-isa-set-enum.h', 'xed-chip-enum.h']: cfe.add_header(header) hfe.add_header(header) cfe.start() hfe.start() cfe.write("xed_uint64_t xed_chip_features[XED_CHIP_LAST][4];\n") hfe.write("extern xed_uint64_t xed_chip_features[XED_CHIP_LAST][4];\n") fo = codegen.function_object_t('xed_init_chip_model_info', 'void') fo.add_code_eol("const xed_uint64_t one=1") # make a set for each machine name spacing = "\n |" for c in chips: s0 = ['0'] s1 = ['0'] s2 = ['0'] s3 = ['0'] # loop over the features for f in chip_features_dict[c]: feature_index = _feature_index(isa_set, f) if feature_index < 64: s0.append('(one<<XED_ISA_SET_%s)' % (f)) elif feature_index < 128: s1.append('(one<<(XED_ISA_SET_%s-64))' % (f)) elif feature_index < 192: s2.append('(one<<(XED_ISA_SET_%s-128))' % (f)) elif feature_index < 256: s3.append('(one<<(XED_ISA_SET_%s-192))' % (f)) else: _die("Feature index > 256. Need anotehr features array") s0s = spacing.join(s0) s1s = spacing.join(s1) s2s = spacing.join(s2) s3s = spacing.join(s3) for i, x in enumerate([s0s, s1s, s2s, s3s]): fo.add_code_eol("xed_chip_features[XED_CHIP_{}][{}] = {}".format( c, i, x)) cfe.write(fo.emit()) cfe.close() hfe.write(fo.emit_header()) hfe.close() return ([ isa_set_per_chip_fn, chip_enum.hdr_full_file_name, chip_enum.src_full_file_name, isa_set_enum.hdr_full_file_name, isa_set_enum.src_full_file_name, hfe.full_file_name, cfe.full_file_name ], chips, isa_set)
def _dump_capture_chain_fo_lu(agi, patterns): """ Creates chain capturing functions - for each pattern, dumps those functions definitions, dumps a mapping from inum(xed_inst_t index) to those functions. """ fn_2_fo = {} inum_2_fn = {} nop_fo = _gen_empty_capture_fo() fn_2_fo[nop_fo.function_name] = nop_fo for ptrn in patterns: ii = ptrn.ii nt_names = _get_nt_names_from_ii(ii) if len(nt_names) == 0: #if no NTs we use empty capturing function fn = nop_fo.function_name else: fn = _get_xed3_capture_chain_fn(nt_names) if fn not in fn_2_fo: fo = _gen_capture_chain_fo(nt_names) fn_2_fo[fn] = fo inum_2_fn[ii.inum] = (fn, ptrn.ptrn) #dump chain functions headers = [_xed3_nt_capture_header] ild_codegen.dump_flist_2_header(agi, _xed3_chain_header, headers, list(fn_2_fo.values()), is_private=True) lu_size = max(inum_2_fn.keys()) + 1 xeddir = os.path.abspath(agi.common.options.xeddir) gendir = mbuild.join(agi.common.options.gendir, 'include-private') h_file = codegen.xed_file_emitter_t(xeddir, gendir, _xed3_chain_lu_header, shell_file=False, is_private=True) h_file.add_header(_xed3_chain_header) h_file.start() lu_name = 'xed3_chain_fptr_lu' xed3_chain_f_t = 'xed3_chain_function_t' fptr_typedef = 'typedef %s(*%s)(%s*);' % ( _xed3_chain_return_t, xed3_chain_f_t, ildutil.xed3_decoded_inst_t) h_file.add_code(fptr_typedef) h_file.add_code('static {} {}[{}] = {{'.format(xed3_chain_f_t, lu_name, lu_size)) empty_line = '/*NO PATTERN*/ (%s)0,' % xed3_chain_f_t for inum in range(0, lu_size): if inum in inum_2_fn: (fn, ptrn_str) = inum_2_fn[inum] entry_str = '/*\n%s\ninum=%s*/ %s,' % (ptrn_str, inum, fn) else: entry_str = empty_line h_file.add_code(entry_str) h_file.add_code('};') h_file.close()
def emit_map_info_tables(agi): '''variable modrm,disp,imm tables, per encoding space using natural map ids. returns list of files generated''' map_features_cfn = 'xed-map-feature-tables.c' map_features_hfn = 'xed-map-feature-tables.h' private_gendir = os.path.join(agi.common.options.gendir, 'include-private') hfe = codegen.xed_file_emitter_t(agi.common.options.xeddir, private_gendir, map_features_hfn) for h in ['xed-map-info.h']: hfe.add_header(h) hfe.start() sorted_list = sorted(agi.map_info, key=lambda x: x.map_name) spaces = list(set([mi.space for mi in sorted_list])) sorted_spaces = sorted(spaces, key=lambda x: encoding_space_to_vexvalid(x)) max_space_id = _encoding_space_max() # legacy,vex,evex,xop,knc #max_space_id = encoding_space_to_vexvalid(sorted_spaces[-1]) max_map_id = max([mi.map_id for mi in agi.map_info]) #0...31 fields = ['modrm', 'disp', 'imm'] cvt_yes_no_var = {'yes': 1, 'no': 0, 'var': 2} cvt_imm = {'0': 0, '1': 1, '2': 2, '4': 4, 'var': 7} field_to_cvt = { 'modrm': cvt_yes_no_var, 'disp': cvt_yes_no_var, 'imm': cvt_imm } bits_per_chunk = 64 # The field width in bits must be a power of 2 for current design, # otherwise the bits of interest can span the 64b chunks we are # using to store the values. field_to_bits = {'modrm': 2, 'disp': 2, 'imm': 4} def collect_codes(field, space_maps): '''cvt is dict converting strings to integers. the codes are indexed by map id.''' cvt = field_to_cvt[field] codes = {key: 0 for key in range(0, max_map_id + 1)} for mi in space_maps: codes[mi.map_id] = cvt[getattr(mi, field)] codes_as_list = [codes[i] for i in range(0, max_map_id + 1)] return codes_as_list def convert_list_to_integer(lst, bits_per_field): '''return an integer or a list of integer if more than 64b''' integers = [] tot = 0 shift = 0 for v in lst: if shift >= 64: integers.append(tot) tot = 0 shift = 0 tot = tot + (v << shift) shift = shift + bits_per_field integers.append(tot) if len(integers) == 1: return integers[0] return integers for space_id in _encoding_space_range(): space = _space_id_to_name[space_id] space_maps = [mi for mi in sorted_list if mi.space == space] for field in fields: bits_per_field = field_to_bits[field] total_bits = max_map_id * bits_per_field required_chunks = math.ceil(total_bits / bits_per_chunk) values_per_chunk = bits_per_chunk // bits_per_field ilog2_values_per_chunk = int(math.log2(values_per_chunk)) mask = (1 << bits_per_field) - 1 f = codegen.function_object_t('xed_ild_has_{}_{}'.format( field, space), 'xed_bool_t', static=True, inline=True) f.add_arg('xed_uint_t m') if space_maps: codes = collect_codes(field, space_maps) constant = convert_list_to_integer(codes, bits_per_field) else: codes = [0] constant = 0 f.add_code('/* {} */'.format(codes)) if set(codes) == {0}: # all zero values... f.add_code_eol('return 0') f.add_code_eol('(void)m') else: if required_chunks <= 1: f.add_code_eol( 'const xed_uint64_t data_const = 0x{:x}ULL'.format( constant)) f.add_code_eol( 'return (xed_bool_t)((data_const >> ({}*m)) & {})'. format(bits_per_field, mask)) else: f.add_code('const xed_uint64_t data_const[{}] = {{'.format( required_chunks)) ln = ['0x{:x}ULL'.format(c) for c in constant] f.add_code_eol(' {} }}'.format(", ".join(ln))) f.add_code_eol( 'const xed_uint64_t chunkno = m >> {}'.format( ilog2_values_per_chunk)) f.add_code_eol( 'const xed_uint64_t offset = m & ({}-1)'.format( values_per_chunk)) f.add_code_eol( 'return (xed_bool_t)((data_const[chunkno] >> ({}*offset)) & {})' .format(bits_per_field, mask)) hfe.write(f.emit()) # emit the inline function in the header # emit a function that covers all spaces for field in fields: bits_per_field = field_to_bits[field] total_bits = max_map_id * bits_per_field required_chunks = math.ceil(total_bits / bits_per_chunk) values_per_chunk = bits_per_chunk // bits_per_field ilog2_values_per_chunk = int(math.log2(values_per_chunk)) mask = (1 << bits_per_field) - 1 f = codegen.function_object_t('xed_ild_has_{}'.format(field), 'xed_bool_t', static=True, inline=True) f.add_arg('xed_uint_t vv') f.add_arg('xed_uint_t m') if required_chunks <= 1: f.add_code( 'const xed_uint64_t data_const[{}] = {{'.format(max_space_id + 1)) else: f.add_code('const xed_uint64_t data_const[{}][{}] = {{'.format( max_space_id + 1, required_chunks)) for space_id in _encoding_space_range(): space = _space_id_to_name[space_id] space_maps = [mi for mi in sorted_list if mi.space == space] if space_maps: codes = collect_codes(field, space_maps) constant = convert_list_to_integer(codes, bits_per_field) else: codes = [0] * required_chunks if required_chunks <= 1: constant = 0 else: constant = [0] * required_chunks f.add_code('/* {} {} */'.format(codes, space)) if required_chunks <= 1: f.add_code(' 0x{:x}ULL,'.format(constant)) else: ln = ['0x{:x}ULL'.format(c) for c in constant] f.add_code('{{ {} }},'.format(", ".join(ln))) f.add_code_eol('}') f.add_code_eol('xed_assert(vv < {})'.format(max_space_id + 1)) if required_chunks <= 1: f.add_code_eol( 'return (xed_bool_t)((data_const[vv] >> ({}*m)) & {})'.format( bits_per_field, mask)) else: f.add_code_eol('const xed_uint64_t chunkno = m >> {}'.format( ilog2_values_per_chunk)) f.add_code_eol('const xed_uint64_t offset = m & ({}-1)'.format( values_per_chunk)) f.add_code_eol( 'return (xed_bool_t)((data_const[vv][chunkno] >> ({}*offset)) & {})' .format(bits_per_field, mask)) hfe.write(f.emit()) # emit the inline function in the header # emit a set of functions for determining the valid maps in each encoding space if max_map_id > 64: genutil.die("Need to make this work with multiple chunks of u64") for space_id in _encoding_space_range(): space = _space_id_to_name[space_id] space_maps = [mi for mi in sorted_list if mi.space == space] f = codegen.function_object_t('xed_ild_map_valid_{}'.format(space), 'xed_bool_t', static=True, inline=True) f.add_arg('xed_uint_t m') max_id = _encoding_space_max() #max_id = max( [mi.map_id for mi in space_maps ] ) codes_dict = {key: 0 for key in range(0, max_map_id + 1)} for mi in space_maps: codes_dict[mi.map_id] = 1 codes = [codes_dict[i] for i in range(0, max_map_id + 1)] f.add_code('/* {} */'.format(codes)) constant = convert_list_to_integer(codes, 1) f.add_code_eol( 'const xed_uint64_t data_const = 0x{:x}ULL'.format(constant)) # no need for a max-map test since, the upper bits of the # constant will be zero already f.add_code_eol('return (xed_bool_t)((data_const >> m) & 1)') hfe.write(f.emit()) # emit the inline function in the header # emit a table filling in "xed_map_info_t xed_legacy_maps[] = { ... }" legacy_maps = [mi for mi in sorted_list if mi.space == 'legacy'] legacy_maps = sorted(legacy_maps, key=lambda x: -len(x.search_pattern) * 10 + x.map_id) hfe.add_code('const xed_map_info_t xed_legacy_maps[] = {') for mi in legacy_maps: if mi.map_id == 0: continue has_legacy_opcode = 1 if mi.legacy_opcode != 'N/A' else 0 legacy_opcode = mi.legacy_opcode if mi.legacy_opcode != 'N/A' else 0 legacy_escape = mi.legacy_escape if mi.legacy_escape != 'N/A' else 0 hfe.add_code('{{ {}, {}, {}, {}, {} }},'.format( legacy_escape, has_legacy_opcode, legacy_opcode, mi.map_id, mi.opcpos)) hfe.add_code_eol('}') hfe.close() return [hfe.full_file_name]