def gen_find_fos(self, fname): obj_str = self.cdict.strings_dict['obj_str'] obj_type = self.cdict.strings_dict['obj_type'] key_str= self.cdict.strings_dict['key_str'] hidx_str = self.cdict.strings_dict['hidx_str'] const = self.cdict.strings_dict['obj_const'] lu_namespace = self.cdict.strings_dict['lu_namespace'] #FIXME: this is a temporary, when we will implement the iform encoding # we will be able to remove this code if genutil.field_check(self.cdict, 'ntluf') or \ genutil.field_check(self.cdict, 'nt'): return_type = 'xed_uint32_t' else: return_type = self.cdict.action_codegen.get_return_type() static = self.cdict.strings_dict['static'] fo = codegen.function_object_t(fname, return_type=return_type, static=static, inline=False) lu_operands = '_'.join(self.cdict.cnames) lu_operands_fn = 'xed_lu_%s' % lu_operands key_ctype = self.cdict.strings_dict['key_type'] operand_lu_fo = codegen.function_object_t(lu_operands_fn, return_type=key_ctype, static=False, inline=False, force_no_inline=True) ild_arg = "%s%s* %s" % (const,obj_type, obj_str) fo.add_arg(ild_arg) if genutil.field_check(self.cdict, 'ntluf'): fo.add_arg('xed_reg_enum_t arg_reg') operand_lu_fo.add_arg(ild_arg) #add key-computing code (constraints tuple to integer) nt_lups = self.add_cgen_key_lines(operand_lu_fo) #several non terminals has special getter functions #the add-cgen_kiet function returns a list of all the nt_lups and #regular cnames lu_operands_fn = 'xed_%s_lu_%s' % (lu_namespace,'_'.join(nt_lups)) operand_lu_fo.set_function_name(lu_operands_fn) #add the operands lookup function self.add_lu_table(fo) self.add_op_lu_function(fo,lu_operands_fn) self.add_find_lines(fo) return ([fo],operand_lu_fo)
def _gen_capture_chain_fo(nt_names, fname=None): """ Given a list of NT names, generate a function object (function_object_t) that calls corresponding xed3 NT capturing functions. Each such function captures everything that xed2 decode graph would capture for a given pattern with NTs (nt_names) in it. """ if not fname: fname = _get_xed3_capture_chain_fn(nt_names) inst = 'd' fo = codegen.function_object_t(fname, return_type=_xed3_chain_return_t, static=True, inline=True) fo.add_arg(ildutil.xed3_decoded_inst_t + '* %s' % inst) for name in nt_names: capture_fn = _get_xed3_nt_capture_fn(name) capture_stmt = '%s(%s)' % (capture_fn, inst) fo.add_code_eol(capture_stmt) #now check if we have errors in current NT getter_fn = operand_storage.get_op_getter_fn(_xed3_err_op) errval = '%s(%s)' % (getter_fn, inst) fo.add_code('if (%s) {' % errval) fo.add_code_eol('return %s' % errval) fo.add_code('}') fo.add_code_eol('return %s' % _xed_no_err_val) return fo
def gen_derived_operand_getter(agi, opname, op_arr, op_nt_names): return_type = agi.operand_storage.get_ctype(opname) op_lufn = ild_nt.get_lufn(op_nt_names, opname) getter_fn = get_derived_op_getter_fn(op_nt_names, opname) fo = codegen.function_object_t(getter_fn, return_type, static=True, inline=True) data_name = 'x' fo.add_arg('const ' + ildutil.ild_c_type + ' %s' % data_name) for range_tuple in op_arr.ranges: range_type, range_min, range_max, paramname = range_tuple param_name = '_%s' % paramname.lower() fo.add_code_eol(ildutil.ild_c_op_type + ' %s' % param_name) params = [] for range_tuple in op_arr.ranges: range_type, range_min, range_max, paramname = range_tuple param_name = '_%s' % paramname.lower() access_call = emit_ild_access_call(paramname, data_name) fo.add_code_eol('%s = (%s)%s' % (param_name, ildutil.ild_c_op_type, access_call)) params.append(param_name) lu_fn = op_arr.lookup_fn.function_name lu_call = lu_fn + '(%s)' lu_call = lu_call % (', '.join(params)) fo.add_code_eol('return %s' % lu_call) return fo
def gen_init_function(arr_list, name): #make a function_object_t to call all the individual init routines overall_init_f = codegen.function_object_t(name, return_type='void') for array in arr_list: if not array.is_const_lookup_fun(): overall_init_f.add_code_eol(array.init_fn.function_name + '()') return overall_init_f
def gen_find_fos(self, fname): # L2 phash obj_str = self.cdict.strings_dict['obj_str'] obj_type = self.cdict.strings_dict['obj_type'] const = self.cdict.strings_dict['obj_const'] hx2fo = {} for hx, phash in list(self.hx2phash.items()): fid = '%s_%d_l1' % (fname, hx) (hx2fo_list, operand_lu_fo) = phash.gen_find_fos(fid) if not operand_lu_fo: genutil.die("L2 hash cannot have trivial operand lu fn") hx2fo[hx] = hx2fo_list[0] fname = '%s' % fname if genutil.field_check(self.cdict, 'ntluf') or \ genutil.field_check(self.cdict, 'nt'): return_type = 'xed_uint32_t' else: return_type = self.cdict.action_codegen.get_return_type() static = self.cdict.strings_dict['static'] fo = codegen.function_object_t(fname, return_type=return_type, static=static, inline=False) fo.add_arg('%s%s* %s' % (const, obj_type, obj_str)) self.add_lu_table(fo, hx2fo) #we only need to override add_lookup_lines lu_fname = operand_lu_fo.function_name self.add_op_lu_function(fo, lu_fname) self.add_find_lines(fo) fos = list(hx2fo.values()) fos.append(fo) #all the operand_lu_fo going to be the same so we just take the last one return fos, operand_lu_fo
def _gen_generic_getter(self): ''' for xed's internal usage (printing) we need to be able to get an operand based on its index. generating here a switch/case over the operand index to call the correct getter function ''' inst = 'd' fname = 'xed3_get_generic_operand' ret_arg = 'ret_arg' fo = codegen.function_object_t(fname, return_type='void', static=False, inline=False, dll_export=True) fo.add_arg('const xed_decoded_inst_t* %s' % inst) fo.add_arg('xed_operand_enum_t operand') fo.add_arg('void* %s' % ret_arg) switch_gen = codegen.c_switch_generator_t('operand', fo) op_names = sorted(self.operand_fields.keys()) for op in op_names: switch_key = "XED_OPERAND_%s" % op ctype = self.get_ctype(op) func_getter = "%s(d)" % get_op_getter_fn(op) code = "*((%s*)%s)=%s;" % (ctype, ret_arg, func_getter) switch_gen.add_case(switch_key, [code]) switch_gen.add_default(['xed_assert(0);']) switch_gen.finish() return fo
def _gen_generic_setter(self): ''' generating a switch/case over the operand index to call the correct setter function ''' inst = 'd' fname = 'xed3_set_generic_operand' in_value = 'val' fo = codegen.function_object_t(fname, return_type='void', static=False, inline=False, dll_export=True) fo.add_arg('xed_decoded_inst_t* %s' % inst) fo.add_arg('xed_operand_enum_t operand') fo.add_arg('xed_uint32_t %s' % in_value) switch_gen = codegen.c_switch_generator_t('operand', fo) op_names = sorted(self.operand_fields.keys()) for op in op_names: switch_key = "XED_OPERAND_%s" % op ctype = self.get_ctype(op) func_setter = get_op_setter_fn(op) code = "%s(%s,(%s)%s);" % (func_setter, inst, ctype, in_value) switch_gen.add_case(switch_key, [code]) switch_gen.add_default(['xed_assert(0);']) switch_gen.finish() return fo
def _make_fb_setter_fo(self, iform, i): ''' create the function object for pattern of fields bindings @param iform: iform_t object @param i: index of the pattern function @return: function_object_t ''' fname = "%s_%d" % (bind_function_prefix, i) fo = codegen.function_object_t(fname, return_type='void') obj_name = encutil.enc_strings['obj_str'] enc_arg = "%s* %s" % (encutil.enc_strings['obj_type'], obj_name) fo.add_arg(enc_arg) if not iform.fbs: #no field binding we need to set, pacify the compiler fo.add_code_eol('(void)%s' % obj_name) return fo fo.add_code_eol(' const xed_uint8_t* val') fo.add_code_eol(' val = %s(%s)' % (get_field_value, obj_name)) for i, fb_action in enumerate(iform.fbs): value_from_lu_table = '*(val+%d)' % i operand_setter = "%s_set_%s" % (encutil.enc_strings['op_accessor'], fb_action.field_name.lower()) code = ' %s(%s,%s);' % (operand_setter, obj_name, value_from_lu_table) fo.add_code(code) return fo
def gen_l1_bymode_resolution_function(agi, info_list, nt_dict, is_conflict_fun, gen_l2_fn_fun, fn_suffix): if len(info_list) < 1: ildutil.ild_warn("Trying to resolve conflict for empty info_list") return None insn_map = info_list[0].insn_map opcode = info_list[0].opcode ildutil.ild_warn('generating by mode fun_dict for opcode %s map %s' % (opcode, insn_map)) machine_modes = agi.common.get_state_space_values('MODE') fun_dict = _gen_bymode_fun_dict(machine_modes, info_list, nt_dict, is_conflict_fun, gen_l2_fn_fun) if not fun_dict: #it is not ild_err because we might have other conflict resolution #functions to try. #In general we have a list of different conflict resolution functions #that we iterate over and try to resolve the conflict ildutil.ild_warn('Failed to generate by mode fun_dict for opcode ' + '%s map %s' % (opcode, insn_map)) return None #if not all modrm.reg values have legal instructions defined, we don't #have full 0-7 dict for modrm.reg here, and we can't generate the interval #dict if len(list(fun_dict.keys())) == len(machine_modes): int_dict = _gen_intervals_dict(fun_dict) else: int_dict = None lufn = ild_nt.gen_lu_names(['RESOLVE_BYMODE'], fn_suffix)[2] lufn += '_map%s_op%s_l1' % (insn_map, opcode) operand_storage = agi.operand_storage return_type = 'void' fo = codegen.function_object_t(lufn, return_type, static=True, inline=True) data_name = 'x' fo.add_arg(ildutil.ild_c_type + ' %s' % data_name) mode_type = ildutil.ild_c_op_type mode_var = '_mode' fo.add_code_eol(mode_type + ' %s' % mode_var) #get MODE value access_call = emit_ild_access_call("MODE", data_name) if not access_call: return None fo.add_code_eol('%s = (%s)%s' % (mode_var, mode_type, access_call)) #now emit the resolution code, that checks condtions from dict #(in this case the MODE value) #and calls appropriate L2 function for each condition #if we have an interval dict, we can emit several if statements if int_dict: _add_int_dict_dispatching(fo, int_dict, mode_var, data_name) #if we don't have interval dict, we emit switch statement else: _add_switch_dispatching(fo, fun_dict, mode_var, data_name) return fo
def work(lines, xeddir = '.', gendir = 'obj'): tables = [] _read_constant_tables(lines,tables) tables=list(filter(lambda x: x.valid() , tables)) names= [ x.name for x in 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 = [ x+'\n' for x in 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( [ x+'\n' for x in hdr] ) hfe.close() srcs.append(hfe.full_file_name) srcs.append(xfe.full_file_name) return srcs
def _make_test_function_object(env, enc_fn): encoder_fn = enc_fn.get_function_name() versions = env.test_function_names[encoder_fn] fname = 'test_{}_{}'.format(versions, encoder_fn) if env.test_checked_interface: fname = '{}_chk'.format(fname) env.test_function_names[encoder_fn] += 1 fo = codegen.function_object_t(fname, return_type='xed_uint32_t') return fo
def _make_emit_fo(self, iform, i): ''' create the function object for this emit pattern @param iform: iform_t object @param i: index of the pattern function @return: function_object_t ''' fname = "%s_%d" % (emit_function_prefix, i) fo = codegen.function_object_t(fname, return_type='void') # obj_str is the function parameters for the emit function obj_str = encutil.enc_strings['obj_str'] enc_arg = "%s* %s" % (encutil.enc_strings['obj_type'], obj_str) fo.add_arg(enc_arg) for action in iform.rule.actions: # MASSIVE HACK: we store the legacy_map as MAP0 in # xed_encode_iform_db[] (obj/xed-encoder-iforms-init.c) # for VEX/EVEX/XOP instr (see # _identify_map_and_nominal_opcode() ) to avoid emitting # any escape/map bytes at runtime. if action.field_name == 'MAP': if iform.encspace == 0: # legacy genutil.die("Should not see MAP here: {}".format( iform.iclass)) pass elif action.field_name and action.field_name in [ 'LEGACY_MAP1', 'LEGACY_MAP2', 'LEGACY_MAP3', 'LEGACY_MAP3DNOW' ]: if iform.encspace != 0: # legacy genutil.die("This should only occur for legacy instr") self._emit_legacy_map(fo, iform) elif action.field_name and action.field_name == 'NOM_OPCODE': code = '' get_opcode = 'xed_encoder_get_nominal_opcode(%s)' % obj_str if action.nbits == 8: emit_func = 'xed_encoder_request_emit_bytes' else: emit_func = 'xed_encoder_request_encode_emit' code = ' ' * 4 code += '%s(%s,%d,%s)' % (emit_func, obj_str, action.nbits, get_opcode) fo.add_code_eol(code) else: code = action.emit_code('EMIT') for c in code: fo.add_code(c) return fo
def _gen_op_getter_fo(self, opname): ''' generate the function object for the getter accessors adding cast to the C type according to the data files(ctype)''' inst = 'd' fname = get_op_getter_fn(opname) ret_type = self.get_ctype(opname) fo = codegen.function_object_t(fname, return_type=ret_type, static=True, inline=True) fo.add_arg('const xed_decoded_inst_t* %s' % inst) op = opname.lower() fo.add_code_eol('return (%s)%s->_operands.%s' % (ret_type, inst, op)) return fo
def gen_scalable_l2_function(agi, nt_name, target_opname, ild_t_member, arg_arr, arg_nt_names): return_type = 'void' l3_fn = ild_nt.get_lufn([nt_name], target_opname, flevel='l3') arg_name = arg_arr.get_target_opname() l2_fn = get_l2_fn([nt_name], target_opname, arg_nt_names, arg_name, None, False) fo = codegen.function_object_t(l2_fn, return_type, static=True, inline=True) data_name = 'x' fo.add_arg(ildutil.ild_c_type + ' %s' % data_name) arg_type = agi.operand_storage.get_ctype(arg_name) arg_var = '_%s' % arg_name.lower() fo.add_code_eol('%s %s' % (arg_type, arg_var)) temp_var = '_%s' % ild_t_member ctype = ildutil.ild_c_op_type fo.add_code_eol('%s %s' % (ctype, temp_var)) for range_tuple in arg_arr.ranges: range_type, range_min, range_max, paramname = range_tuple param_name = '_%s' % paramname.lower() fo.add_code_eol(ildutil.ild_c_op_type + ' %s' % param_name) params = [] for range_tuple in arg_arr.ranges: range_type, range_min, range_max, paramname = range_tuple param_name = '_%s' % paramname.lower() access_call = emit_ild_access_call(paramname, data_name) fo.add_code_eol('%s = (%s)%s' %(param_name, ildutil.ild_c_op_type, access_call)) params.append(param_name) arg_fn = arg_arr.lookup_fn.function_name arg_call = arg_fn + '(%s)' arg_call = arg_call % (', '.join(params)) fo.add_code_eol('%s = %s' % (arg_var, arg_call)) fcall = '%s(%s)' % (l3_fn, arg_var) fo.add_code_eol('%s = (%s)%s' % (temp_var, ctype, fcall)) setter_fn = operand_storage.get_op_setter_fn(ild_t_member) fo.add_code_eol('%s(%s, %s)' % (setter_fn, data_name,temp_var)) return fo
def _make_emit_fo(self, iform, i): ''' create the function object for this emit pattern @param iform: iform_t object @param i: index of the pattern function @return: function_object_t ''' fname = "%s_%d" % (emit_function_prefix,i) fo = codegen.function_object_t(fname, return_type='void') # obj_str is the function parameters for the emit function obj_str = encutil.enc_strings['obj_str'] enc_arg = "%s* %s" % (encutil.enc_strings['obj_type'], obj_str) fo.add_arg(enc_arg) for action in iform.rule.actions: # MASSIVE HACK: we store the legacy_map as MAP0 in # xed_encode_iform_db[] (obj/xed-encoder-iforms-init.c) # for VEX/EVEX/XOP instr (see # _identify_map_and_nominal_opcode() ) to avoid emitting # any escape/map bytes at runtime. # FIXME: We could avoid ths call to emit legacy map for # non-legacy stuff and speed up encoder slightly. if action.field_name and action.field_name == 'MAP': emit_map = 'xed_encoder_request_emit_legacy_map' code = " %s(%s)" % (emit_map,obj_str) fo.add_code_eol(code) elif action.field_name and action.field_name == 'NOM_OPCODE': code = '' get_opcode = 'xed_encoder_get_nominal_opcode(%s)' % obj_str if action.nbits == 8: emit_func = 'xed_encoder_request_emit_bytes' else: emit_func = 'xed_encoder_request_encode_emit' code = ' '*4 code += '%s(%s,%d,%s)' % (emit_func,obj_str, action.nbits,get_opcode) fo.add_code_eol(code) else: code = action.emit_code('EMIT') for c in code: fo.add_code(c) return fo
def _gen_imm0_function(agi): """ for patterns that don't set IMM_WIDTH token these patterns have has_im==0 and we define a L2 lookup function that returns 0 """ #return_type = operand_storage.get_ctype(_imm_token) return_type = 'void' fo = codegen.function_object_t(_imm0_fn, return_type, static=True, inline=True) data_name = 'x' fo.add_arg(ildutil.ild_c_type + ' %s' % data_name) setter_fn = operand_storage.get_op_setter_fn(_ild_t_imm_member) fo.add_code_eol('%s(%s, %s)' % (setter_fn, data_name,'0')) return fo
def _gen_op_setter_fo(self, opname): ''' generate the function object for the setter accessors adding cast to the C type according to the data files(ctype)''' inst = 'd' opval = 'opval' fname = get_op_setter_fn(opname) fo = codegen.function_object_t(fname, return_type='void', static=True, inline=True) fo.add_arg('xed_decoded_inst_t* %s' % inst) fo.add_arg('%s %s' % (self.get_ctype(opname), opval)) op = opname.lower() type = self.get_storage_type(opname) fo.add_code_eol('%s->_operands.%s = (%s)%s' % (inst, op, type, opval)) return fo
def _emit_function(fe, isa_sets, name): fo = codegen.function_object_t('xed_classify_{}'.format(name)) fo.add_arg('const xed_decoded_inst_t* d') fo.add_code_eol( ' const xed_isa_set_enum_t isa_set = xed_decoded_inst_get_isa_set(d)' ) # FIXME: 2017-07-14 optimization: could use a static array for faster checking, smaller code switch = codegen.c_switch_generator_t('isa_set', fo) for c in isa_sets: switch.add_case('XED_ISA_SET_{}'.format(c.upper()), [], do_break=False) if len(isa_sets) > 0: switch.add('return 1;') switch.add_default(['return 0;'], do_break=False) switch.finish() fo.emit_file_emitter(fe)
def _gen_ntluf_capture_chain_fo(nt_names, ii): """ Given a list of OP_NAME_NT_NAME strings(nt_names), generate a function object (function_object_t) that calls corresponding xed3 NT capturing functions. Each such function captures everything that xed2 decode graph would capture for a given pattern with operands that have nt_lokkupfns. The difference between this function and _gen_capture_chain_fo is that this function creates chain capturing functions for operand decoding - assigns the REG[0,1] operands, etc. """ fname = get_xed3_capture_chain_fn(nt_names, is_ntluf=True) inst = 'd' fo = fo = codegen.function_object_t(fname, return_type=_xed3_chain_return_t, static=True, inline=True) fo.add_arg(ildutil.xed3_decoded_inst_t + '* %s' % inst) for op in ii.operands: if op.type == 'nt_lookup_fn': nt_name = op.lookupfn_name capture_fn = get_xed3_nt_capture_fn(nt_name) capture_stmt = '%s(%s)' % (capture_fn, inst) fo.add_code_eol(capture_stmt) #if we have NTLUF functions, we need to assign OUTREG getter_fn = operand_storage.get_op_getter_fn('outreg') outreg_expr = '%s(%s)' % (getter_fn, inst) fo.add_code('/*opname %s */' % op.name) _add_op_assign_stmt(fo, op.name, outreg_expr, inst) #now check if we have errors in current NT #we don't need to check if there was a reg_error because #we assign error operand inside the called nt_capture function #if there was a reg_error getter_fn = operand_storage.get_op_getter_fn(_xed3_err_op) errval = '%s(%s)' % (getter_fn, inst) fo.add_code('if (%s) {' % errval) fo.add_code_eol('return %s' % errval) fo.add_code('}') elif op.type in ['imm_const', 'reg']: opval = op.bits _add_op_assign_stmt(fo, op.name, opval, inst) fo.add_code_eol('return %s' % _xed_no_err_val) return fo
def _gen_empty_function(agi): """This function is for patterns that don't set [BR]DISP_WIDTH tokens. These patterns have disp_bytes set earlier in xed-ild.c and we define a L2 lookup function that does nothing """ operand_storage = agi.operand_storage return_type = 'void' fo = codegen.function_object_t(_empty_fn, return_type, static=True, inline=True) data_name = 'x' fo.add_arg(ildutil.ild_c_type + ' %s' % data_name) fo.add_code('/*This function does nothing for map-opcodes whose') fo.add_code('disp_bytes value is set earlier in xed-ild.c') fo.add_code('(regular displacement resolution by modrm/sib)*/\n') fo.add_code('/*pacify the compiler*/') fo.add_code_eol('(void)%s' % data_name) return fo
def _gen_empty_capture_fo(is_ntluf=False): """ Generate capture function that does nothing. For patterns without NTs. """ inst = 'd' if is_ntluf: fname = '%s_ntluf' % _xed3_empty_capture_func else: fname = _xed3_empty_capture_func fo = codegen.function_object_t(fname, return_type=_xed3_chain_return_t, static=True, inline=True) fo.add_arg(ildutil.xed3_decoded_inst_t + '* %s' % inst) fo.add_code_eol('(void)%s' % inst) fo.add_code_eol('return %s' % _xed_no_err_val) return fo
def gen_const_l2_function(agi, nt_name, target_opname, ild_t_member): return_type = 'void' l3_fn = ild_nt.get_lufn([nt_name], target_opname, flevel='l3') l2_fn = get_l2_fn([nt_name], target_opname, [], None, None, True) fo = codegen.function_object_t(l2_fn, return_type, static=True, inline=True) data_name = 'x' fo.add_arg(ildutil.ild_c_type + ' %s' % data_name) temp_var = '_%s' % ild_t_member ctype = ildutil.ild_c_op_type fo.add_code_eol('%s %s' % (ctype, temp_var)) fcall = l3_fn + '()' fo.add_code_eol('%s = (%s)%s' % (temp_var, ctype, fcall)) setter_fn = operand_storage.get_op_setter_fn(ild_t_member) fo.add_code_eol('%s(%s, %s)' % (setter_fn, data_name,temp_var)) return fo
def _make_emit_fo(self, iform, i): ''' create the function object for this emit pattern @param iform: iform_t object @param i: index of the pattern function @return: function_object_t ''' fname = "%s_%d" % (emit_function_prefix,i) fo = codegen.function_object_t(fname, return_type='void') # obj_str is the function parameters for the emit function obj_str = encutil.enc_strings['obj_str'] enc_arg = "%s* %s" % (encutil.enc_strings['obj_type'], obj_str) fo.add_arg(enc_arg) for action in iform.rule.actions: if action.field_name and action.field_name == 'MAP': emit_map = 'xed_encoder_request_emit_legacy_map' code = " %s(%s)" % (emit_map,obj_str) fo.add_code_eol(code) elif action.field_name and action.field_name == 'NOM_OPCODE': code = '' get_opcode = 'xed_encoder_get_nominal_opcode(%s)' % obj_str if action.nbits == 8: emit_func = 'xed_encoder_request_emit_bytes' else: emit_func = 'xed_encoder_request_encode_emit' code = ' '*4 code += '%s(%s,%d,%s)' % (emit_func,obj_str, action.nbits,get_opcode) fo.add_code_eol(code) else: code = action.emit_code('EMIT') for c in code: fo.add_code(c) return fo
def _gen_capture_fo(agi, nt_name, all_ops_widths): """ Generate xed3 capturing function for a given NT name. """ gi = agi.generator_dict[nt_name] cdict = gi.xed3_cdict fname = _get_xed3_nt_capture_fn(nt_name) inst = 'd' keystr = 'key' fo = codegen.function_object_t(fname, return_type='void', static=True, inline=True) fo.add_arg(ildutil.xed3_decoded_inst_t + '* %s' % inst) if len(cdict.cnames) > 0: _add_cgen_key_lines(fo, nt_name, gi, all_ops_widths, keystr, inst) fo.add_code('/* now switch code..*/') _add_switchcase_lines(fo, nt_name, gi, all_ops_widths, keystr, inst) else: rule = cdict.rule _add_nt_rhs_assignments(fo, nt_name, gi, rule) return fo
def _gen_empty_function(self,fname): ''' generate a function without constraints ''' return_type = 'xed_uint32_t' fo = codegen.function_object_t(fname, return_type=return_type, static=False, inline=False) obj_type = self.cvg.strings_dict['obj_type'] obj_str = self.cvg.strings_dict['obj_str'] arg = "%s* %s" % (obj_type, obj_str) fo.add_arg(arg) lines = self.cvg.action_codegen.emit_default() for line in lines: if line == 'return ': fo.add_code_eol('return 1') else: fo.add_code_eol(line) fo.add_code_eol('(void)%s' % obj_str) fo.add_code_eol('return 1') return fo
def _make_arg_check_function_object(env, enc_fn): encoder_fn = enc_fn.get_function_name() fname = '{}_chk'.format(encoder_fn) fo = codegen.function_object_t(fname, return_type='void', dll_export=True) return fo
def gen_find_fos(self, fname): # phash_t obj_str = self.cdict.strings_dict['obj_str'] obj_type = self.cdict.strings_dict['obj_type'] key_str = self.cdict.strings_dict['key_str'] hidx_str = self.cdict.strings_dict['hidx_str'] const = self.cdict.strings_dict['obj_const'] lu_namespace = self.cdict.strings_dict['lu_namespace'] #FIXME: this is a temporary, when we will implement the iform encoding # we will be able to remove this code if genutil.field_check(self.cdict, 'ntluf') or \ genutil.field_check(self.cdict, 'nt'): return_type = 'xed_uint32_t' elif self.hash_f.kind() == 'trivial': return_type = 'xed_uint32_t' else: return_type = self.cdict.action_codegen.get_return_type() static = self.cdict.strings_dict['static'] fo = codegen.function_object_t(fname, return_type=return_type, static=static, inline=False) lu_operands = '_'.join(self.cdict.cnames) # temporary function name. we override this later lu_operands_fn = 'xed_lu_%s' % lu_operands key_ctype = self.cdict.strings_dict['key_type'] ild_arg = "%s%s* %s" % (const, obj_type, obj_str) fo.add_arg(ild_arg) if self.hash_f.kind() == 'trivial': operand_lu_fo = None # rule is a pattern_t fo.add_code_eol("return {}".format(self.cdict.rule.ii.inum)) # avoid parmameter-not-used warnings with compilers that # care (like MSVS) fo.add_code_eol("(void)d") else: operand_lu_fo = codegen.function_object_t(lu_operands_fn, return_type=key_ctype, static=False, inline=False, force_no_inline=True) operand_lu_fo.add_arg(ild_arg) if genutil.field_check(self.cdict, 'ntluf'): fo.add_arg('xed_reg_enum_t arg_reg') #add key-computing code (constraints tuple to integer) nt_lups = self.add_cgen_key_lines(operand_lu_fo) #Several nonterminals have special getter functions. The #add_cgen_key_lines function returns a list of all the #nt_lups and regular cnames. (lu_operands is not always #the same as the underscore-joined nt_lups.) lu_operands_fn = 'xed_%s_lu_%s' % (lu_namespace, '_'.join(nt_lups)) operand_lu_fo.set_function_name(lu_operands_fn) #add the operands lookup function self.add_lu_table(fo) self.add_op_lu_function(fo, lu_operands_fn) self.add_find_lines(fo) return ([fo], operand_lu_fo)
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 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]