📄 bc-optab.c
字号:
enum typecode to; int cost; struct conversion_list *prev;};/* Determine if it is "reasonable" to add a given conversion to a given list of conversions. The following criteria define "reasonable" conversion lists: * No typecode appears more than once in the sequence (no loops). * At most one conversion from integer to float or vice versa is present. * Either sign extensions or zero extensions may be present, but not both. * No widening conversions occur after a signed/unsigned conversion. * The sequence of sizes must be strict nonincreasing or nondecreasing. */static intconversion_reasonable_p (conversion, list) struct conversion_info *conversion; struct conversion_list *list;{ struct conversion_list *curr; int curr_size, prev_size; int has_int_float, has_float_int; int has_sign_extend, has_zero_extend; int has_signed_unsigned, has_unsigned_signed; has_int_float = 0; has_float_int = 0; has_sign_extend = 0; has_zero_extend = 0; has_signed_unsigned = 0; has_unsigned_signed = 0; /* Make sure the destination typecode doesn't already appear in the list. */ for (curr = list; curr; curr = curr->prev) if (conversion->to == curr->to) return 0; /* Check for certain kinds of conversions. */ if (TYPECODE_INTEGER_P (conversion->from) && TYPECODE_FLOAT_P (conversion->to)) has_int_float = 1; if (TYPECODE_FLOAT_P (conversion->from) && TYPECODE_INTEGER_P (conversion->to)) has_float_int = 1; if (TYPECODE_SIGNED_P (conversion->from) && TYPECODE_SIGNED_P (conversion->to) && GET_TYPECODE_SIZE (conversion->from) < GET_TYPECODE_SIZE (conversion->to)) has_sign_extend = 1; if (TYPECODE_UNSIGNED_P (conversion->from) && TYPECODE_UNSIGNED_P (conversion->to) && GET_TYPECODE_SIZE (conversion->from) < GET_TYPECODE_SIZE (conversion->to)) has_zero_extend = 1; for (curr = list; curr && curr->prev; curr = curr->prev) { if (TYPECODE_INTEGER_P (curr->prev->to) && TYPECODE_FLOAT_P (curr->to)) has_int_float = 1; if (TYPECODE_FLOAT_P (curr->prev->to) && TYPECODE_INTEGER_P (curr->to)) has_float_int = 1; if (TYPECODE_SIGNED_P (curr->prev->to) && TYPECODE_SIGNED_P (curr->to) && GET_TYPECODE_SIZE (curr->prev->to) < GET_TYPECODE_SIZE (curr->to)) has_sign_extend = 1; if (TYPECODE_UNSIGNED_P (curr->prev->to) && TYPECODE_UNSIGNED_P (curr->to) && GET_TYPECODE_SIZE (curr->prev->to) < GET_TYPECODE_SIZE (curr->to)) has_zero_extend = 1; if (TYPECODE_SIGNED_P (curr->prev->to) && TYPECODE_UNSIGNED_P (curr->to)) has_signed_unsigned = 1; if (TYPECODE_UNSIGNED_P (curr->prev->to) && TYPECODE_SIGNED_P (curr->to)) has_unsigned_signed = 1; } if (TYPECODE_INTEGER_P (conversion->from) && TYPECODE_INTEGER_P (conversion->to) && GET_TYPECODE_SIZE (conversion->to) > GET_TYPECODE_SIZE (conversion->from) && (has_signed_unsigned || has_unsigned_signed)) return 0; if (has_float_int && has_int_float || has_sign_extend && has_zero_extend) return 0; /* Make sure the sequence of destination typecode sizes is strictly nondecreasing or strictly nonincreasing. */ prev_size = GET_TYPECODE_SIZE (conversion->to); for (curr = list; curr; curr = curr->prev) { curr_size = GET_TYPECODE_SIZE (curr->to); if (curr_size != prev_size) break; } if (!curr) return 1; if (curr_size < prev_size) for (prev_size = curr_size; curr; curr = curr->prev) { curr_size = GET_TYPECODE_SIZE (curr->to); if (curr_size > prev_size) return 0; prev_size = curr_size; } else for (prev_size = curr_size; curr; curr = curr->prev) { curr_size = GET_TYPECODE_SIZE (curr->to); if (curr_size < prev_size) return 0; prev_size = curr_size; } return 1;}/* Exhaustively search all reasonable conversions to find one to convert the given types. */static struct conversion_recipededuce_conversion (from, to) enum typecode from, to;{ struct rl { struct conversion_list *list; struct rl *next; } *prev, curr, *good, *temp; struct conversion_list *conv, *best; int i, cost, bestcost; struct conversion_recipe result; struct obstack recipe_obstack; obstack_init (&recipe_obstack); curr.next = (struct rl *) obstack_alloc (&recipe_obstack, sizeof (struct rl)); curr.next->list = (struct conversion_list *) obstack_alloc (&recipe_obstack, sizeof (struct conversion_list)); curr.next->list->opcode = -1; curr.next->list->to = from; curr.next->list->cost = 0; curr.next->list->prev = 0; curr.next->next = 0; good = 0; while (curr.next) { /* Remove successful conversions from further consideration. */ for (prev = &curr; prev; prev = prev->next) if (prev->next && prev->next->list->to == to) { temp = prev->next->next; prev->next->next = good; good = prev->next; prev->next = temp; } /* Go through each of the pending conversion chains, trying all possible candidate conversions on them. */ for (prev = curr.next, curr.next = 0; prev; prev = prev->next) for (i = 0; i < NUM_CONVERSIONS; ++i) if (conversion_info[i].from == prev->list->to && conversion_reasonable_p (&conversion_info[i], prev->list)) { temp = (struct rl *) obstack_alloc (&recipe_obstack, sizeof (struct rl)); temp->list = (struct conversion_list *) obstack_alloc (&recipe_obstack, sizeof (struct conversion_list)); temp->list->opcode = conversion_info[i].opcode; temp->list->to = conversion_info[i].to; temp->list->cost = conversion_info[i].cost; temp->list->prev = prev->list; temp->next = curr.next; curr.next = temp; } } bestcost = BIG_ARBITRARY_NUMBER; best = 0; for (temp = good; temp; temp = temp->next) { for (conv = temp->list, cost = 0; conv; conv = conv->prev) cost += conv->cost; if (cost < bestcost) { bestcost = cost; best = temp->list; } } if (!best) abort (); for (i = 0, conv = best; conv; conv = conv->prev) if (conv->opcode != -1) ++i; result.opcodes = (unsigned char *) xmalloc (i); result.nopcodes = i; for (conv = best; conv; conv = conv->prev) if (conv->opcode != -1) result.opcodes[--i] = conv->opcode; result.cost = bestcost; obstack_free (&recipe_obstack, 0); return result;}#define DEDUCE_CONVERSION(FROM, TO) \ (conversion_recipe[(int) FROM][(int) TO].opcodes ? 0 \ : (conversion_recipe[(int) FROM][(int) TO] \ = deduce_conversion (FROM, TO), 0))/* Emit a conversion between the given scalar types. */voidemit_typecode_conversion (from, to) enum typecode from, to;{ int i; DEDUCE_CONVERSION (from, to); for (i = 0; i < conversion_recipe[(int) from][(int) to].nopcodes; ++i) bc_emit_instruction (conversion_recipe[(int) from][(int) to].opcodes[i]);}/* Initialize mode_to_code_map[] */voidbc_init_mode_to_code_map (){ int mode; for (mode = 0; mode < MAX_MACHINE_MODE + 1; mode++) { signed_mode_to_code_map[mode] = unsigned_mode_to_code_map[mode] = LAST_AND_UNUSED_TYPECODE; }#define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \ { signed_mode_to_code_map[(int) SYM] = CODE; \ unsigned_mode_to_code_map[(int) SYM] = UCODE; }#include "modemap.def"#undef DEF_MODEMAP /* Initialize opcode maps for const, load, and store */ bc_init_mode_to_opcode_maps ();}/* Given a machine mode return the preferred typecode. */enum typecodepreferred_typecode (mode, unsignedp) enum machine_mode mode; int unsignedp;{ enum typecode code = (unsignedp ? unsigned_mode_to_code_map : signed_mode_to_code_map) [MIN ((int) mode, (int) MAX_MACHINE_MODE)]; if (code == LAST_AND_UNUSED_TYPECODE) abort (); return code;}/* Expand a conversion between the given types. */voidbc_expand_conversion (from, to) tree from, to;{ enum typecode fcode, tcode; fcode = preferred_typecode (TYPE_MODE (from), TREE_UNSIGNED (from)); tcode = preferred_typecode (TYPE_MODE (to), TREE_UNSIGNED (to)); emit_typecode_conversion (fcode, tcode);}/* Expand a conversion of the given type to a truth value. */voidbc_expand_truth_conversion (from) tree from;{ enum typecode fcode; fcode = preferred_typecode (TYPE_MODE (from), TREE_UNSIGNED (from)); emit_typecode_conversion (fcode, Tcode);}/* Emit an appropriate binary operation. */voidbc_expand_binary_operation (optab, resulttype, arg0, arg1) struct binary_operator optab[]; tree resulttype, arg0, arg1;{ int i, besti, cost, bestcost; enum typecode resultcode, arg0code, arg1code; resultcode = preferred_typecode (TYPE_MODE (resulttype), TREE_UNSIGNED (resulttype)); arg0code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg0)), TREE_UNSIGNED (resulttype)); arg1code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg1)), TREE_UNSIGNED (resulttype)); besti = -1; bestcost = BIG_ARBITRARY_NUMBER; for (i = 0; optab[i].opcode != -1; ++i) { cost = 0; DEDUCE_CONVERSION (arg0code, optab[i].arg0); cost += conversion_recipe[(int) arg0code][(int) optab[i].arg0].cost; DEDUCE_CONVERSION (arg1code, optab[i].arg1); cost += conversion_recipe[(int) arg1code][(int) optab[i].arg1].cost; if (cost < bestcost) { besti = i; bestcost = cost; } } if (besti == -1) abort (); expand_expr (arg1, 0, VOIDmode, 0); emit_typecode_conversion (arg1code, optab[besti].arg1); expand_expr (arg0, 0, VOIDmode, 0); emit_typecode_conversion (arg0code, optab[besti].arg0); bc_emit_instruction (optab[besti].opcode); emit_typecode_conversion (optab[besti].result, resultcode);}/* Emit an appropriate unary operation. */voidbc_expand_unary_operation (optab, resulttype, arg0) struct unary_operator optab[]; tree resulttype, arg0;{ int i, besti, cost, bestcost; enum typecode resultcode, arg0code; resultcode = preferred_typecode (TYPE_MODE (resulttype), TREE_UNSIGNED (resulttype)); arg0code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg0)), TREE_UNSIGNED (TREE_TYPE (arg0))); besti = -1; bestcost = BIG_ARBITRARY_NUMBER; for (i = 0; optab[i].opcode != -1; ++i) { DEDUCE_CONVERSION (arg0code, optab[i].arg0); cost = conversion_recipe[(int) arg0code][(int) optab[i].arg0].cost; if (cost < bestcost) { besti = i; bestcost = cost; } } if (besti == -1) abort (); expand_expr (arg0, 0, VOIDmode, 0); emit_typecode_conversion (arg0code, optab[besti].arg0); bc_emit_instruction (optab[besti].opcode); emit_typecode_conversion (optab[besti].result, resultcode);}/* Emit an appropriate increment. */voidbc_expand_increment (optab, type) struct increment_operator optab[]; tree type;{ enum typecode code; int i; code = preferred_typecode (TYPE_MODE (type), TREE_UNSIGNED (type)); for (i = 0; (int) optab[i].opcode >= 0; ++i) if (code == optab[i].arg) { bc_emit_instruction (optab[i].opcode); return; } abort ();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -