Beispiel #1
0
def _add_switchcase_lines(fo,
                          nt_name,
                          gi,
                          all_ops_widths,
                          key_str='key',
                          inst='d'):
    cdict = gi.xed3_cdict
    fo.add_code('switch(%s) {' % key_str)

    int2key = {}
    key2int = {}
    for key in list(cdict.tuple2rule.keys()):
        keyval = tup2int.tuple2int(key, cdict.cnames, all_ops_widths)
        #This checks for a nasty conflict that should never happen:
        #when two different tuple keys have the same integer value.
        #This conflict can happen when bit widths of all constraints are
        #bigger than 32 bit (key is uint32 currently).
        #In general such error will be caught by C compiler when we try
        #to build a key and shift more than 32 bits.
        #Checking here too just to be sure.
        #FIXME: add an assertion to constraint_dict_t constructor to check
        #for that?
        #FIXME: this doesn't really checks for integer overflow, because
        #python autmatically extends int32 if it overflows to int64.
        #Need better checking.
        if keyval in int2key:
            msg = []
            msg.append('CDICT TUPLE VALUE CONFLICT in nt %s !!!!' % nt_name)
            msg.append('keyval %s' % keyval)
            msg.append('key1 %s, key2 %s' % (key, int2key[keyval]))
            msg.append('cdict %s')
            msg = '\n'.join(msg)
            ildutil.ild_err(msg)
        int2key[keyval] = key
        key2int[key] = keyval

    covered_rules = set()

    #we want cases sorted by value - prettier
    for keyval in sorted(int2key.keys()):
        key = int2key[keyval]
        rule = cdict.tuple2rule[key]
        if rule in covered_rules:
            continue
        covered_rules.add(rule)
        keys = cdict.get_all_keys_by_val(rule)
        for key in keys:
            #FIXME: move tuple2int to ild_cdict?
            keyval = key2int[key]
            fo.add_code('case %s: /*%s -> %s*/' % (keyval, key, rule))
        _add_case_lines(fo, nt_name, gi, rule)
    fo.add_code('default:')
    if gi.parser_output.otherwise_ok:
        fo.add_code('/* otherwise_ok */')
    else:
        #FIXME: temporary using general error, later
        #define more specific error enum
        #errval = _nt_2_xed3_err_enum(nt_name)
        errval = 'XED_ERROR_GENERAL_ERROR'
        _add_op_assign_stmt(fo, _xed3_err_op, errval, inst, indent=1)
    fo.add_code_eol('    break')
    fo.add_code('}')
Beispiel #2
0
def gen_l1_functions_and_lookup(agi, united_lookup, disp_dict):
    """Compute L1(conflict resolution) functions list and disp_bytes lookup 
    tables dict.
    @param agi: all generators info
    
    @param united_lookup: the 2D lookup by map-opcode to info objects list.
    united_lookup['0x0']['0x78'] == [ild_info1, ild_info2, ... ]
    @type united_lookup: 
    {string(insn_map) : {string(opcode): [ild_info.ild_info_t]} }
    
    
    """
    #list of L1 function objects that resolve conflicts in map-opcodes
    #functions. This list will be dumped to xed_ild_imm_l1.h
    l1_resolution_fos = []
    
    #dictionary l1_lookup[insn_map][opcode] = l1_function_name
    #this dictionary will be used to dump the has_imm lookup tables
    l1_lookup = {}
    
    #dictionary from function body(as string) to list of function objects
    #with that body.
    #This dict will be used to bucket identical functions in order to
    #not define same functions more than once.
    l1_bucket_dict = collections.defaultdict(list)
    
    
    for insn_map in ild_info.get_maps(united_lookup.is_amd):
        l1_lookup[insn_map] = {}
        for opcode in range(0, 256):
            #look in the hardcoded resolution functions
            if (insn_map, hex(opcode)) in harcoded_res_functions:
                l1_fn = harcoded_res_functions[(insn_map, hex(opcode))]
                l1_lookup[insn_map][hex(opcode)] = l1_fn
                continue
            info_list = united_lookup.get_info_list(insn_map, hex(opcode))
            #get only info objects with minimum priority
            info_list = ild_info.get_min_prio_list(info_list)
            is_conflict = _is_disp_conflict(info_list, disp_dict)
            if len(info_list) > 1 and is_conflict:
                l1_fo = _resolve_conflicts(agi, info_list, disp_dict)
                if not l1_fo:
                    ildutil.ild_err('FAILED TO GENERATE L1 CONFLICT ' +
                    'RESOLUTION FUNCTION FOR DISP\n infos: %s' %
                    "\n".join([str(info) for info in info_list]))
                l1_bucket_dict[l1_fo.emit_body()].append(l1_fo)
                l1_fn = l1_fo.function_name
            
            elif len(info_list) == 0:
                #if map-opcode pair is undefined the lookup function ptr is
                #NULL.
                #This will happen for opcodes like 0F in 0F map - totally 
                #illegal opcodes, that should never be looked up in runtime.
                #We define NULL pointer for such map-opcodes
                l1_fn = '(%s)0' % (ildutil.l1_ptr_typename)
            else:
                #there are no conflicts, we can use L2 function as L1
                info = info_list[0]
                l1_fn = get_l2_fn_from_info(info, disp_dict)
            l1_lookup[insn_map][hex(opcode)] = l1_fn
    
    #there are 18 L1 functions with same body (currently, may change 
    #in future) 
    #we are going to bucket L1 functions with identical body but different
    #names in order to have only one function for each unique body
    #FIXME: the bucketed function name is not self descriptive
    bucket_name = 'xed_lookup_function_DISP_BUCKET_%s_l1'
    cur_bucket = 0
    for res_fun_list in l1_bucket_dict.values():
        if len(res_fun_list) == 1:
            #only one such function - we should define it as is
            l1_resolution_fos.append(res_fun_list[0])
        else:
            #more than one L1 function with identical body
            #we should define L1 function with that body
            #and fix references in the lookup table
            
            #the function name
            cur_buck_name = bucket_name % cur_bucket
            cur_bucket += 1
            
            #fix references in the lookup table
            for res_fun in res_fun_list:
                for insn_map in l1_lookup.keys():
                    for opcode in l1_lookup[insn_map].keys():
                        cur_fn = l1_lookup[insn_map][opcode]
                        if cur_fn == res_fun.function_name:
                            l1_lookup[insn_map][opcode] = cur_buck_name
            #define the L1 function and add it to the list of L1 functions
            #to dump
            buck_fo = res_fun_list[0]
            buck_fo.function_name = cur_buck_name
            l1_resolution_fos.append(buck_fo)
                
    return l1_resolution_fos,l1_lookup
Beispiel #3
0
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 = filter(lambda(nt): nt in all_nts, disp_nts)
    brdisp_nts = 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 = brdisp_dict.values() + disp_dict.values()
    #create function that calls all intialization 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 disp_dict.items() + 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)
Beispiel #4
0
def gen_ph_fos(agi, cdict_by_map_opcode, is_amd, log_fn, ptrn_dict, vv):
    """
    Returns a tuple (phash_lu_table, phash_fo_list, op_lu_list)
    * phash_lu_table:  is a traditional 2D dict by map, opcode to a
      hash function name.
    * phash_fo_list: is a list of all phash function objects created
      (we might have fos that are not in lookup table - when we have
      2-level hash functions).
    * op_lu_list:  is a list for all the operands lookup functions

    Also writes log file for debugging.
    """
    maps = ild_info.get_maps(is_amd)
    log_f = open(log_fn, 'w')
    cnames = set()  # only for logging
    stats = {
        '0. #map-opcodes': 0,
        '1. #entries': 0,
        '2. #hentries': 0,
        '3. #hashes': 0,
        '4. #min_hashes': 0,
        '5. #cdict_size_1_to_10': 0,
        '6. #cdict_size_10_to_20': 0,
        '7. #cdict_size_20_to_100': 0,
        '8. #cdict_size_at_least_100': 0
    }
    lu_fo_list = []
    op_lu_map = {}  # fn name -> fn obj
    phash_lu = {}  # map, opcode -> fn name
    for insn_map in maps:
        phash_lu[insn_map] = {}
        for opcode in range(0, 256):
            opcode = hex(opcode)
            cdict = cdict_by_map_opcode[insn_map][opcode]
            if cdict:
                stats['0. #map-opcodes'] += 1
                stats['1. #entries'] += len(cdict.tuple2rule)
                cnames = cnames.union(set(cdict.cnames))
                _log(log_f,
                     'MAP:%s OPCODE:%s:\n%s\n' % (insn_map, opcode, cdict))

                phash = ild_phash.gen_hash(cdict)
                if phash:
                    _log(log_f, "%s" % phash)
                    phash_id = 'map%s_opcode%s_vv%d' % (insn_map, opcode, vv)
                    fname = "%s_%s" % (_find_fn_pfx, phash_id)
                    (fo_list, op_lu_fo) = phash.gen_find_fos(fname)
                    lu_fo_list.extend(fo_list)

                    #hold only one instance of each function
                    if op_lu_fo:
                        if op_lu_fo.function_name not in op_lu_map:
                            op_lu_map[op_lu_fo.function_name] = op_lu_fo
                    for fo in fo_list:
                        _log(log_f, '//find function:\n')
                        _log(log_f, fo.emit())
                        _log(log_f, '-----------------------------\n')
                    #FIXME: assumption: L2 function is last in the list
                    #maybe return dict or tuple to make a distinction between
                    #L2 and L1 functions?
                    phlu_fn = lu_fo_list[-1]
                    phash_lu[insn_map][opcode] = phlu_fn.function_name
                    phash.update_stats(stats)
                else:
                    _log(log_f, '---NOPHASH-----\n')
                    msg = "Failed to gen phash for map %s opcode %s"
                    ildutil.ild_err(msg % (insn_map, opcode))
            else:
                phash_lu[insn_map][opcode] = '(xed3_find_func_t)0'
    _log(log_f, "cnames: %s\n" % cnames)
    for key in sorted(stats.keys()):
        _log(log_f, "%s %s\n" % (key, stats[key]))
    log_f.close()
    return phash_lu, lu_fo_list, list(op_lu_map.values())