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_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 gen_getter_fn_lookup(agi, united_lookup, eosz_dict): # NOT USED """Compute L1(conflict resolution) functions list and eosz 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]} } """ l1_lookup = {} for insn_map in united_lookup.get_maps(): l1_lookup[insn_map] = {} for opcode in range(0, 256): 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 = False if len(info_list) > 1: is_conflict = is_eosz_conflict(info_list) if is_conflict: genutil.msg("EOSZ CONFLICT MAP/OPCODE:{}/{}".format( insn_map, opcode)) # l1_fo = _resolve_conflicts(agi, info_list, nt_dict) # if not l1_fo: # ildutil.ild_err('FAILED TO GENERATE CONFLICT ' + # 'RESOLUTION FUNCTION FOR EOSZ\n infos:\n %s' % # "\n".join([str(info) for info in info_list])) # # l1_resolution_fos.append(l1_fo) # l1_fn = l1_fo.function_name l1_fn = None #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. elif len(info_list) == 0: l1_fn = '(%s)0' % (ildutil.l1_ptr_typename) else: #there are no conflicts, we can use the eosz_nt_seq #function info = info_list[0] l1_fn = ild_nt.get_lufn(info.eosz_nt_seq, _eosz_token) l1_lookup[insn_map][hex(opcode)] = l1_fn return l1_lookup
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 get_l2_fn(target_nt_names, target_opname, arg_nts, arg_name, empty_seq_name, is_const): """Generate L2 function name from IMM NT names list and EOSZ NT names list. Each L2 function is defined by a single PATTERN row in xed's grammar. (By pattern's IMM-binding and EOSZ-binding NTs) Hence, it is enough to know the IMM NTs sequence and EOSZ NTs sequence to define a L2 function. Or in this case to define a L2 function name. ATTENTION: as we decided to hardcode special AMD's double immediate instruction's L1 functions, the length of imm_nt_names can be ONLY 1 @param imm_nt_names: list of IMM-binding NT names @param eosz_nt_names: list of EOSZ-binding NT names @return: L2 function name """ #if there are no target NTs in pattern, then L2 function is #the default function for empty sequences #(return 0 for immediates and return; for disp) if len(target_nt_names) == 0: return empty_seq_name #currently there are no supported target NT sequences that have more #than 1 NT. Check that. if len(target_nt_names) > 1: ildutil.ild_err("Cannot generate L2 function name for NT seq %s" % target_nt_names) if is_const: arg_suffix = _arg_const_suffix else: arg_suffix = "_".join(arg_nts + [arg_name]) #L2 function name is a concatenation of L3 function name and possible #argument(e.g EOSZ or EASZ) NT names l3_prefix = ild_nt.get_lufn(target_nt_names, target_opname) return l3_prefix + '_%s_l2' % arg_suffix
def gen_getter_fn_lookup(agi, united_lookup, easz_dict): # NOT USED """Compute L1(conflict resolution) functions list and easz 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]} } """ l1_lookup = {} for insn_map in united_lookup.get_maps(): l1_lookup[insn_map] = {} for opcode in range(0, 256): 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 = False if len(info_list) > 1: is_conflict = is_easz_conflict(info_list) if is_conflict: l1_fn = None #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. elif len(info_list) == 0: l1_fn = '(%s)0' % (ildutil.l1_ptr_typename) else: #there are no conflicts, we can use the eosz_nt_seq #function info = info_list[0] l1_fn = ild_nt.get_lufn(info.easz_nt_seq, _easz_token) l1_lookup[insn_map][hex(opcode)] = l1_fn return l1_lookup
def get_derived_op_getter_fn(op_nts, opname): return ild_nt.get_lufn(op_nts, opname) + '_getter'