]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/stmt.c
c++: Handle multiple aggregate overloads [PR95319].
[thirdparty/gcc.git] / gcc / stmt.c
index 457fe7f6f7886ccd15254c08e7b7c8a6fa115e61..d81271a81604a3efae1b12716bd6bf69c5f34ef1 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
 
@@ -50,7 +50,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "cfganal.h"
 #include "tree-cfg.h"
-#include "params.h"
 #include "dumpfile.h"
 #include "builtins.h"
 
@@ -68,8 +67,9 @@ along with GCC; see the file COPYING3.  If not see
 
 */
 
-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)
   {}
@@ -81,8 +81,6 @@ struct simple_case_node
   /* 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);
@@ -247,62 +245,68 @@ parse_output_constraint (const char **constraint_p, int operand_num,
     }
 
   /* 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;
 }
@@ -517,7 +521,7 @@ check_unique_operand_names (tree outputs, tree inputs, tree labels)
   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;
 }
 
@@ -847,7 +851,8 @@ emit_case_dispatch_table (tree index_expr, tree index_type,
   /* 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),
@@ -879,6 +884,7 @@ expand_case (gswitch *stmt)
   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;
 
@@ -900,7 +906,7 @@ expand_case (gswitch *stmt)
   /* 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.  */
@@ -912,6 +918,31 @@ expand_case (gswitch *stmt)
   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);
 
@@ -963,27 +994,22 @@ expand_case (gswitch *stmt)
 
   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 ();