def work(agi, all_state_space, all_ops_widths, patterns): """ Main entry point of the module. For each NT generate a capturing function. Then for each sequence of NTs in patterns generate a chain capturing function that would call single capturing functions for each NT. Then for each combination of operands generate operands chain captuirng function. Also generate lookup tables to obtain those chain capturing functions from inum (xed_inst_t index). """ gendir = ild_gendir = agi.common.options.gendir logfn = mbuild.join(gendir, 'xed3_nt_cdicts.txt') log_f = open(logfn, 'w') #generate NT capturing functions capture_fn_list = [] for nt_name in list(agi.nonterminal_dict.keys()): #skip nonterminals that we don't want to capture: #PREFIXES, AVX_SPLITTER, *ISA, etc. if _skip_nt(nt_name): continue _vlog(log_f, 'processing %s\n' % nt_name) #create a constraint_dict_t for each NT nt_cdict = _gen_cdict(agi, nt_name, all_state_space) _vlog(log_f, 'NT:%s:\n%s\n' % (nt_name, nt_cdict)) gi = agi.generator_dict[nt_name] gi.xed3_cdict = nt_cdict #just for transporting #create a function_object_t for the NT fo = _gen_capture_fo(agi, nt_name, all_ops_widths) gi.xed3_capture_fo = fo capture_fn_list.append(fo) _vlog(log_f, fo.emit()) #dump NT capturing functions headers = [operand_storage.get_operand_accessors_fn(), ildutil.ild_header] ild_codegen.dump_flist_2_header(agi, _xed3_nt_capture_header, headers, capture_fn_list, is_private=True) #in each pattern we have a number of NTs, #now that we have a capturing function for each NT #we can create a create a function that would call #needed capturing functions for each pattern. #Also dump lookup tables from inum(xed_inst_t index) to #chain capturing functions _dump_capture_chain_fo_lu(agi, patterns) #do the same for operands of each xed_inst_t _dump_op_capture_chain_fo_lu(agi, patterns) #create chain capturing functions for the NTs that come from #spine, before the INSTRUCTIONS NT _dump_dynamic_part1_f(agi) log_f.close()
def work(agi, united_lookup, eosz_nts, ild_gendir, debug): #dump lookup tables for each NT #just for debugging nt_arrays = [] for nt_name in eosz_nts: array = ild_nt.gen_nt_lookup(agi, nt_name, 'EOSZ') if not array: return None nt_arrays.append(array) ild_nt.dump_lu_arrays(agi, nt_arrays, 'ild_eosz_debug.txt', 'ild_eosz_debug_header.txt') #get all sequences of NTs that set EOSZ #we will use these sequences to create EOSZ-computing functions all_eosz_seq = get_all_eosz_seq(united_lookup) debug.write('EOSZ SEQS: %s\n' % all_eosz_seq) #for each EOSZ sequence create a lookup array nt_seq_arrays = {} for nt_seq in all_eosz_seq: array = ild_nt.gen_nt_seq_lookup(agi, nt_seq, _eosz_token) if not array: return None nt_seq_arrays[tuple(nt_seq)] = array #init function calls all single init functions for the created tables init_f = ild_nt.gen_init_function(list(nt_seq_arrays.values()), 'xed_ild_eosz_init') #dump init and lookup functions for EOSZ sequences ild_nt.dump_lu_arrays(agi, list(nt_seq_arrays.values()), _eosz_c_fn, mbuild.join('include-private', _eosz_header_fn), init_f) #generate EOSZ getter functions - they get xed_decoded_inst_t* #and return EOSZ value (corresponding to EOSZ NT sequence #that they represent) getter_fos = [] for names in nt_seq_arrays.keys(): arr = nt_seq_arrays[names] getter_fo = ild_codegen.gen_derived_operand_getter( agi, _eosz_token, arr, list(names)) getter_fos.append(getter_fo) ild_codegen.dump_flist_2_header(agi, 'xed-ild-eosz-getters.h', [ ildutil.ild_private_header, _eosz_header_fn, operand_storage.get_operand_accessors_fn() ], getter_fos) #getter_lookup = gen_getter_fn_lookup(agi, united_lookup, nt_seq_arrays) return nt_seq_arrays
def work(agi, united_lookup, easz_nts, ild_gendir, debug): #dump lookup tables for each NT #just for debugging nt_arrays = [] for nt_name in easz_nts: array = ild_nt.gen_nt_lookup(agi, nt_name, 'EASZ') if not array: return nt_arrays.append(array) ild_nt.dump_lu_arrays(agi, nt_arrays, 'ild_easz_debug.txt', 'ild_easz_debug_header.txt') all_easz_seq = get_all_easz_seq(united_lookup) debug.write('EASZ SEQS: %s\n' % all_easz_seq) nt_seq_arrays = {} for nt_seq in all_easz_seq: array = ild_nt.gen_nt_seq_lookup(agi, nt_seq, _easz_token) if not array: return nt_seq_arrays[tuple(nt_seq)] = array #init function calls all single init functions for the created tables nt_seq_values = [v for (k,v) in sorted(nt_seq_arrays.items())] init_f = ild_nt.gen_init_function(nt_seq_values, 'xed_ild_easz_init') ild_nt.dump_lu_arrays(agi, nt_seq_values, _easz_c_fn, mbuild.join('include-private', _easz_header_fn), init_f) getter_fos = [] for names in nt_seq_arrays.keys(): arr = nt_seq_arrays[names] getter_fo = ild_codegen.gen_derived_operand_getter(agi, _easz_token, arr, list(names)) getter_fos.append(getter_fo) headers = [ildutil.ild_private_header, _easz_header_fn, operand_storage.get_operand_accessors_fn()] ild_codegen.dump_flist_2_header(agi, 'xed-ild-easz-getters.h', headers, getter_fos) #getter_lookup = gen_getter_fn_lookup(agi, united_lookup, nt_seq_arrays) return nt_seq_arrays
def work(agi, united_lookup, imm_nts, ild_gendir, eosz_dict, debug): """ main entry point of the module. """ #dump lookup functions for each NT #Let's call these function Level3 functions (L3) nt_dict = {} #generate the L3 functions #Every NT, that changes IMM_WIDTH, defines a L3 function. #For example SIMM8() NT defines a L3 function that returns 1 (1 byte). #And SIMMv() NT defines a function that gets EOSZ and returns IMM_WIDTH #value depending on EOSZ. #UIMM8_1 doesn't bind IMM_WIDTH operand, it is a special case #there is nothing to generate for it. for nt_name in _filter_uimm1_nt(imm_nts): array = ild_nt.gen_nt_lookup(agi, nt_name, _imm_token, target_type=ildutil.ild_c_op_type, level='l3') nt_dict[nt_name] = array #create function that calls all initialization functions for L3 init_f = ild_nt.gen_init_function(list(nt_dict.values()), 'xed_ild_imm_l3_init') #dump L3 functions ild_nt.dump_lu_arrays(agi, list(nt_dict.values()), _l3_c_fn, mbuild.join('include-private',_l3_header_fn), init_f) #get all IMM NT sequences that are used in patterns #The only case of IMM sequence is when we have UIMM1() NT - the second #immediate NT. all_imm_seq = get_all_imm_seq(united_lookup) debug.write('IMM SEQS: %s\n' % all_imm_seq) # L2 / Level2 functions: set imm_width # Now we define functions that compute EOSZ value (using one of # the EOSZ-resolution functions) and then use # one of the L3 functions(that need EOSZ) to set IMM_WIDTH. # The names of these functions should be something like # xed_ild_SIMMz_OSZ_NONTERM_DF64 - to define the imm-binding nonterm # and to define the EOSZ-resolution NT sequence. # L2 functions are defined by single ild_info_t object - by its # eosz_nt_seq and imm_nt_seq l2_functions = ild_codegen.gen_l2_func_list(agi, nt_dict, eosz_dict, _ild_t_imm_member) #append function for imm_bytes==0 l2_functions.append(_gen_imm0_function(agi)) l2_headers = [ild_eosz.get_ntseq_header_fn(), _l3_header_fn, ildutil.ild_header, operand_storage.get_operand_accessors_fn()] ild_codegen.dump_flist_2_header(agi, _l2_header_fn, l2_headers, l2_functions) # L1 / Level1 functions: # Now we define functions that resolve conflicts (if any) # using modrm.reg bits, and that way decide which L2 function to # call to set the IMM value. # These functions will be the value of map,opcode lookup tables. # These functions should be dumped after we have a look on the # united_lookup mapping in order to know what conflicts exist and # for each conflict to create a resolution lookup table. # L1 functions are defined by a list of ild_info_t objects that # have same map,opcode. res = gen_l1_functions_and_lookup(agi, united_lookup, nt_dict) l1_functions,l1_lookup = res ild_codegen.dump_flist_2_header(agi, _l1_header_fn, [_l2_header_fn], l1_functions) headers = [_l1_header_fn, ildutil.ild_private_header, operand_storage.get_operand_accessors_fn()] ild_codegen.dump_lookup(agi, l1_lookup, _ild_t_imm_member, _imm_lu_header_fn, headers, ildutil.l1_ptr_typename)
def work(agi, united_lookup, disp_nts, brdisp_nts, ild_gendir, eosz_dict, easz_dict, debug): """ Main entry point of the module. Generates all the L1-3 functions and dumps disp_bytes lookup tables. """ #get all used DISP NT sequences that appear in patterns #we are going to generate L1-3 functions only for these sequences all_disp_seq = get_all_disp_seq(united_lookup) #check that all sequences are actually single NTs #(each sequence has only one NT) #my observation is that they really are. This simplifies things #and we are going to rely on that. all_nts = [] for ntseq in all_disp_seq: if len(ntseq) > 1: ildutil.ild_err("Unexpected DISP NT SEQ %s" % ntseq) if len(ntseq) == 0: continue #the empty NT sequence all_nts.append(ntseq[0]) #get only those NTs that actually appear in PATTERNs disp_nts = list(filter(lambda nt: nt in all_nts, disp_nts)) brdisp_nts = list(filter(lambda nt: nt in all_nts, brdisp_nts)) debug.write('DISP SEQS: %s\n' % all_disp_seq) debug.write('DISP NTs: %s\n' % disp_nts) debug.write('BRDISP NTs: %s\n' % brdisp_nts) brdisp_dict = _gen_l3_array_dict(agi, brdisp_nts, _brdisp_token) disp_dict = _gen_l3_array_dict(agi, disp_nts, _disp_token) nt_arr_list = list(brdisp_dict.values()) + list(disp_dict.values()) #create function that calls all initialization functions init_f = ild_nt.gen_init_function(nt_arr_list, 'xed_ild_disp_l3_init') #dump L3 functions ild_nt.dump_lu_arrays(agi, nt_arr_list, _l3_c_fn, mbuild.join('include-private', _l3_header_fn), init_f) #create L2 functions #The thing is that we need to know for each #DISP NT whether it depends on EOSZ or EASZ and supply appropriate arg_dict #to gen_l2_func_list() l2_functions = [] eosz_op = ild_eosz.get_target_opname() easz_op = ild_easz.get_target_opname() for nt_name, array in list(disp_dict.items()) + list(brdisp_dict.items()): #Some DISP NTs depend on EOSZ, others on EASZ, we need to know #that when we generate L2 functions if eosz_op in array.get_arg_names(): arg_dict = eosz_dict else: arg_dict = easz_dict flist = ild_codegen.gen_l2_func_list(agi, {nt_name: array}, arg_dict, _ild_t_disp_member) l2_functions.extend(flist) #create the doing-nothing L2 function for map-opcodes #with regular displacement resolution l2_functions.append(_gen_empty_function(agi)) #dump L2 functions l2_headers = [ ild_eosz.get_ntseq_header_fn(), ild_easz.get_ntseq_header_fn(), _l3_header_fn, ildutil.ild_private_header, operand_storage.get_operand_accessors_fn() ] ild_codegen.dump_flist_2_header(agi, _l2_header_fn, l2_headers, l2_functions) #create the L1 functions and lookup tables #unite brdisp and dips dictionaries disp_dict.update(brdisp_dict) #generate L1 functions and lookup tables res = gen_l1_functions_and_lookup(agi, united_lookup, disp_dict) l1_functions, l1_lookup = res #dump L1 functions ild_codegen.dump_flist_2_header(agi, _l1_header_fn, [_l2_header_fn], l1_functions) #dump lookup tables headers = [ _l1_header_fn, ildutil.ild_private_header, operand_storage.get_operand_accessors_fn() ] ild_codegen.dump_lookup(agi, l1_lookup, _ild_t_disp_member, _disp_lu_header_fn, headers, ildutil.l1_ptr_typename)