/* Expands front end tree to back end RTL for GCC
- Copyright (C) 1987-2018 Free Software Foundation, Inc.
+ Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GCC.
#include "langhooks.h"
#include "cfganal.h"
#include "tree-cfg.h"
-#include "params.h"
#include "dumpfile.h"
#include "builtins.h"
*/
-struct simple_case_node
+class simple_case_node
{
+public:
simple_case_node (tree low, tree high, tree code_label):
m_low (low), m_high (high), m_code_label (code_label)
{}
/* Label to jump to when node matches. */
tree m_code_label;
};
-
-extern basic_block label_to_block_fn (struct function *, tree);
\f
static bool check_unique_operand_names (tree, tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree, tree);
}
/* Loop through the constraint string. */
- for (p = constraint + 1; *p; p += CONSTRAINT_LEN (*p, p))
- switch (*p)
- {
- case '+':
- case '=':
- error ("operand constraint contains incorrectly positioned "
- "%<+%> or %<=%>");
- return false;
+ for (p = constraint + 1; *p; )
+ {
+ switch (*p)
+ {
+ case '+':
+ case '=':
+ error ("operand constraint contains incorrectly positioned "
+ "%<+%> or %<=%>");
+ return false;
+
+ case '%':
+ if (operand_num + 1 == ninputs + noutputs)
+ {
+ error ("%<%%%> constraint used with last operand");
+ return false;
+ }
+ break;
- case '%':
- if (operand_num + 1 == ninputs + noutputs)
- {
- error ("%<%%%> constraint used with last operand");
- return false;
- }
- break;
+ case '?': case '!': case '*': case '&': case '#':
+ case '$': case '^':
+ case 'E': case 'F': case 'G': case 'H':
+ case 's': case 'i': case 'n':
+ case 'I': case 'J': case 'K': case 'L': case 'M':
+ case 'N': case 'O': case 'P': case ',':
+ break;
- case '?': case '!': case '*': case '&': case '#':
- case '$': case '^':
- case 'E': case 'F': case 'G': case 'H':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L': case 'M':
- case 'N': case 'O': case 'P': case ',':
- break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '[':
+ error ("matching constraint not valid in output operand");
+ return false;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case '[':
- error ("matching constraint not valid in output operand");
- return false;
+ case '<': case '>':
+ /* ??? Before flow, auto inc/dec insns are not supposed to exist,
+ excepting those that expand_call created. So match memory
+ and hope. */
+ *allows_mem = true;
+ break;
- case '<': case '>':
- /* ??? Before flow, auto inc/dec insns are not supposed to exist,
- excepting those that expand_call created. So match memory
- and hope. */
- *allows_mem = true;
- break;
+ case 'g': case 'X':
+ *allows_reg = true;
+ *allows_mem = true;
+ break;
- case 'g': case 'X':
- *allows_reg = true;
- *allows_mem = true;
- break;
+ default:
+ if (!ISALPHA (*p))
+ break;
+ enum constraint_num cn = lookup_constraint (p);
+ if (reg_class_for_constraint (cn) != NO_REGS
+ || insn_extra_address_constraint (cn))
+ *allows_reg = true;
+ else if (insn_extra_memory_constraint (cn))
+ *allows_mem = true;
+ else
+ insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
+ break;
+ }
- default:
- if (!ISALPHA (*p))
+ for (size_t len = CONSTRAINT_LEN (*p, p); len; len--, p++)
+ if (*p == '\0')
break;
- enum constraint_num cn = lookup_constraint (p);
- if (reg_class_for_constraint (cn) != NO_REGS
- || insn_extra_address_constraint (cn))
- *allows_reg = true;
- else if (insn_extra_memory_constraint (cn))
- *allows_mem = true;
- else
- insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
- break;
- }
+ }
return true;
}
return true;
failure:
- error ("duplicate asm operand name %qs", TREE_STRING_POINTER (i_name));
+ error ("duplicate %<asm%> operand name %qs", TREE_STRING_POINTER (i_name));
return false;
}
/* Output the table. */
emit_label (table_label);
- if (CASE_VECTOR_PC_RELATIVE || flag_pic)
+ if (CASE_VECTOR_PC_RELATIVE
+ || (flag_pic && targetm.asm_out.generate_pic_addr_diff_vec ()))
emit_jump_table_data (gen_rtx_ADDR_DIFF_VEC (CASE_VECTOR_MODE,
gen_rtx_LABEL_REF (Pmode,
table_label),
tree index_type = TREE_TYPE (index_expr);
tree elt;
basic_block bb = gimple_bb (stmt);
+ gimple *def_stmt;
auto_vec<simple_case_node> case_list;
/* Find the default case target label. */
tree default_lab = CASE_LABEL (gimple_switch_default_label (stmt));
default_label = jump_target_rtx (default_lab);
- basic_block default_bb = label_to_block_fn (cfun, default_lab);
+ basic_block default_bb = label_to_block (cfun, default_lab);
edge default_edge = find_edge (bb, default_bb);
/* Get upper and lower bounds of case values. */
else
maxval = fold_convert (index_type, CASE_LOW (elt));
+ /* Try to narrow the index type if it's larger than a word.
+ That is mainly for -O0 where an equivalent optimization
+ done by forward propagation is not run and is aimed at
+ avoiding a call to a comparison routine of libgcc. */
+ if (TYPE_PRECISION (index_type) > BITS_PER_WORD
+ && TREE_CODE (index_expr) == SSA_NAME
+ && (def_stmt = SSA_NAME_DEF_STMT (index_expr))
+ && is_gimple_assign (def_stmt)
+ && gimple_assign_rhs_code (def_stmt) == NOP_EXPR)
+ {
+ tree inner_index_expr = gimple_assign_rhs1 (def_stmt);
+ tree inner_index_type = TREE_TYPE (inner_index_expr);
+
+ if (INTEGRAL_TYPE_P (inner_index_type)
+ && TYPE_PRECISION (inner_index_type) <= BITS_PER_WORD
+ && int_fits_type_p (minval, inner_index_type)
+ && int_fits_type_p (maxval, inner_index_type))
+ {
+ index_expr = inner_index_expr;
+ index_type = inner_index_type;
+ minval = fold_convert (index_type, minval);
+ maxval = fold_convert (index_type, maxval);
+ }
+ }
+
/* Compute span of values. */
range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
rtx_insn *before_case = get_last_insn ();
- /* Decide how to expand this switch.
- The two options at this point are a dispatch table (casesi or
- tablejump) or a decision tree. */
-
+ /* If the default case is unreachable, then set default_label to NULL
+ so that we omit the range check when generating the dispatch table.
+ We also remove the edge to the unreachable default case. The block
+ itself will be automatically removed later. */
+ if (EDGE_COUNT (default_edge->dest->succs) == 0
+ && gimple_seq_unreachable_p (bb_seq (default_edge->dest)))
{
- /* If the default case is unreachable, then set default_label to NULL
- so that we omit the range check when generating the dispatch table.
- We also remove the edge to the unreachable default case. The block
- itself will be automatically removed later. */
- if (EDGE_COUNT (default_edge->dest->succs) == 0
- && gimple_seq_unreachable_p (bb_seq (default_edge->dest)))
- {
- default_label = NULL;
- remove_edge (default_edge);
- default_edge = NULL;
- }
- emit_case_dispatch_table (index_expr, index_type,
- case_list, default_label, default_edge,
- minval, maxval, range, bb);
+ default_label = NULL;
+ remove_edge (default_edge);
+ default_edge = NULL;
}
+ emit_case_dispatch_table (index_expr, index_type,
+ case_list, default_label, default_edge,
+ minval, maxval, range, bb);
+
reorder_insns (NEXT_INSN (before_case), get_last_insn (), before_case);
free_temp_slots ();