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 add_lookup_lines(self, fo): key_validation = self.hash_f.add_key_validation( self.cdict.strings_dict) fo.add_code('%s {' % key_validation) actions = self.cdict.action_codegen.emit_actions() for a in actions: fo.add_code_eol(" " + a) if self.cdict.action_codegen.has_fcall(): fo.add_code_eol(" return res") #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'): fo.add_code_eol(" return 1") fo.add_code('}') # get the default action that will executed when we did not hit valid # look up table entry default = self.cdict.action_codegen.emit_default() fo.add_code('else{') for line in default: fo.add_code_eol(" %s" % line) fo.add_code('}')
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 add_lu_type(self, fo): if genutil.field_check(self.cdict, 'ntluf') or \ genutil.field_check(self.cdict, 'nt'): ret_type = 'xed_uint32_t' else: ret_type = self.cdict.action_codegen.get_return_type() fname = self.cdict.strings_dict['luf_name'] param_name = "%s%s*" % (self.cdict.strings_dict['obj_const'], self.cdict.strings_dict['obj_type']) luf_type = "typedef %s (*%s)(%s)" % (ret_type, fname, param_name) fo.add_code_eol(luf_type) lu_entry = self.cdict.strings_dict['lu_entry'] entry_desc = 'typedef struct {xed_uint32_t key;' entry_desc += ' %s l2_func;} %s' % (fname, lu_entry) fo.add_code_eol(entry_desc)
def _is_amd3dnow(agi): for g in agi.generator_list: ii = g.parser_output.instructions[0] if genutil.field_check(ii, 'iclass'): for ii in g.parser_output.instructions: if ii.category == _xed_3dnow_category: return True return False
def _get_nested_nts(agi): nested_nts = set() for nt_name in agi.nonterminal_dict.keys(): g = agi.generator_dict[nt_name] ii = g.parser_output.instructions[0] if genutil.field_check(ii,'iclass'): continue #only real NTs, not instructions for rule in g.parser_output.instructions: for bt in rule.ipattern.bits: if bt.is_nonterminal(): nested_nts.add(nt_name) for op in rule.operands: if op.type == 'nt_lookup_fn': nested_nts.add(nt_name) return nested_nts
def get_patterns(agi, is_3dnow, eosz_nts, easz_nts, imm_nts, disp_nts, brdisp_nts, all_state_space): """ This function generates the pattern_t objects that have all the necessary information for the ILD. Returns these objects as a list. """ patterns = [] for g in agi.generator_list: ii = g.parser_output.instructions[0] if genutil.field_check(ii, 'iclass'): for ii in g.parser_output.instructions: ptrn = pattern_t(ii, is_3dnow, eosz_nts, easz_nts, imm_nts, disp_nts, brdisp_nts, ildutil.mode_space, all_state_space) patterns.append(ptrn) if ptrn.incomplete_opcode: expanded_ptrns = ptrn.expand_opcode() patterns.extend(expanded_ptrns) return patterns
def get_all_constraints_state_space(agi): """Returns a 2D dictionary state_space. state_space[OPNAME][OPVAL] == True if there is an operand with name OPNAME and value OPVAL. The dictionary contains all legal values for operands in grammar. Only operands that appear as operand deciders, prebindings, or instruction operands are added to the returned dictionary. """ state_space = collections.defaultdict(dict) for g in agi.generator_list: for ii in g.parser_output.instructions: _set_state_space_from_ii(agi, ii, state_space) #set state_space from operands #These are NTs partition tables right parts for g in agi.generator_list: ii = g.parser_output.instructions[0] if genutil.field_check(ii,'iclass'): continue #only real NTs, not instructions for ii in g.parser_output.instructions: _set_space_from_operands(agi, ii.operands, state_space) # in some configurations xed can be build without any AVX # instructions, in this case the operand VEXVALID will no be added. # the ild relies on this operand so we add it manually if 'VEXVALID' not in state_space: state_space['VEXVALID'][0] = True else: # KNC/AVX/EVEX builds... # 2014-10-10: when I got rid of the NTs for decoding the # VEX/EVEX/XOP prefixes, I ended up losing the only NTs that # mention ZEROING=1 and VLBAD (VL=3). So we add them here. # They are required for proper splattering of don't care # cases. in the hash function generation. For example when, # EVEX.RC is rounding control and co-opting the EVEX.LL field, # we need to have the value of VL=3 because it is not # "corrected" when we are still picking an instruction (aka # 'static decode'). state_space['ZEROING'][1] = True state_space['VL'][3] = True return state_space
def add_op_lu_function(self, fo, lu_function): if hasattr(self.hash_f, 'emit_cvar_decl'): fo.add_code_eol(self.hash_f.emit_cvar_decl()) fo.add_code_eol('%s %s = 0' % (self.cdict.strings_dict['key_type'], self.cdict.strings_dict['key_str'])) fo.add_code_eol('%s %s = 0' % (self.cdict.strings_dict['hidx_type'], self.cdict.strings_dict['hidx_str'])) #Initializing res to 1 since it will not always be read. if self.cdict.action_codegen.has_fcall(): fo.add_code_eol('%s %s = 1' % (self.cdict.strings_dict['hidx_type'], 'res')) obj_str = self.cdict.strings_dict['obj_str'] #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'): fo.add_code_eol('xed3_operand_set_outreg(%s,arg_reg)' % obj_str) lu_code = 'key = %s(%s)' % (lu_function, obj_str) fo.add_code_eol(lu_code)
def get_patterns(agi, eosz_nts, easz_nts, imm_nts, disp_nts, brdisp_nts, all_state_space): """ This function generates the pattern_t objects that have all the necessary information for the ILD. Returns these objects as a list. """ machine_modes = agi.common.get_state_space_values('MODE') patterns = [] pattern_t.map_info_g = agi.map_info for g in agi.generator_list: ii = g.parser_output.instructions[0] if genutil.field_check(ii,'iclass'): for ii in g.parser_output.instructions: ptrn = pattern_t(ii, eosz_nts, easz_nts, imm_nts, disp_nts, brdisp_nts, machine_modes, all_state_space) patterns.append(ptrn) if ptrn.incomplete_opcode: expanded_ptrns = ptrn.expand_partial_opcode() patterns.extend(expanded_ptrns) return patterns
def work(agi): sse_isa_sets = set([]) avx_isa_sets = set([]) avx512_isa_sets = set([]) avx512_kmask_op = set([]) for generator in agi.generator_list: for ii in generator.parser_output.instructions: if genutil.field_check(ii, 'iclass'): if re.search('AVX512', ii.isa_set): avx512_isa_sets.add(ii.isa_set) if re.search('KOP', ii.isa_set): avx512_kmask_op.add(ii.isa_set) elif re.search('AVX', ii.isa_set) or ii.isa_set in ['F16C', 'FMA']: avx_isa_sets.add(ii.isa_set) elif re.search('SSE', ii.isa_set) or ii.isa_set in [ 'AES', 'PCLMULQDQ' ]: # Exclude MMX instructions that come in with SSE2 & # SSSE3. The several purely MMX instr in SSE are # "SSE-opcodes" with memop operands. One can look for # those with SSE2MMX and SSSE3MMX xed isa_sets. # # Also exclude the SSE_PREFETCH operations; Those are # just memops. if (not re.search('MMX', ii.isa_set) and not re.search('PREFETCH', ii.isa_set) and not re.search('X87', ii.isa_set) and not re.search('MWAIT', ii.isa_set)): sse_isa_sets.add(ii.isa_set) fe = agi.open_file('xed-classifiers.c') # xed_file_emitter_t _emit_function(fe, avx512_isa_sets, 'avx512') _emit_function(fe, avx512_kmask_op, 'avx512_maskop') _emit_function(fe, avx_isa_sets, 'avx') _emit_function(fe, sse_isa_sets, 'sse') fe.close() return
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)