diff mbox

[committed] Backports from trunk to 4.7 branch

Message ID 20130201142157.GM4385@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Feb. 1, 2013, 2:21 p.m. UTC
Hi!

I've committed following backports from trunk to 4.7 branch, after
bootstrapping/regtesting it on x86_64-linux and i686-linux.

	Jakub
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-11-13  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/54127
	* cfgrtl.c (force_nonfallthru_and_redirect): When redirecting
	asm goto labels from BB_HEAD (e->dest) to target bb, decrement
	LABEL_NUSES of BB_HEAD (e->dest) and increment LABEL_NUSES of
	BB_HEAD (target) appropriately and adjust JUMP_LABEL and/or
	REG_LABEL_TARGET and REG_LABEL_OPERAND.

	* gcc.dg/torture/pr54127.c: New test.
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-11-17  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/55236
	* fold-const.c (make_range_step) <case NEGATE_EXPR>: For -fwrapv
	and signed ARG0_TYPE, force low and high to be non-NULL.

	* gcc.dg/pr55236.c: New test.

--- gcc/fold-const.c	(revision 193590)
+++ gcc/fold-const.c	(revision 193591)
@@ -3880,6 +3880,17 @@ make_range_step (location_t loc, enum tr
       return arg0;
 
     case NEGATE_EXPR:
+      /* If flag_wrapv and ARG0_TYPE is signed, make sure
+	 low and high are non-NULL, then normalize will DTRT.  */
+      if (!TYPE_UNSIGNED (arg0_type)
+	  && !TYPE_OVERFLOW_UNDEFINED (arg0_type))
+	{
+	  if (low == NULL_TREE)
+	    low = TYPE_MIN_VALUE (arg0_type);
+	  if (high == NULL_TREE)
+	    high = TYPE_MAX_VALUE (arg0_type);
+	}
+
       /* (-x) IN [a,b] -> x in [-b, -a]  */
       n_low = range_binop (MINUS_EXPR, exp_type,
 			   build_int_cst (exp_type, 0),
--- gcc/testsuite/gcc.dg/pr55236.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr55236.c	(revision 193591)
@@ -0,0 +1,31 @@
+/* PR tree-optimization/55236 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fwrapv" } */
+
+extern void abort ();
+
+__attribute__((noinline, noclone)) void
+foo (int i)
+{
+  if (i > 0)
+    abort ();
+  i = -i;
+  if (i < 0)
+    return;
+  abort ();
+}
+
+__attribute__((noinline, noclone)) void
+bar (int i)
+{
+  if (i > 0 || (-i) >= 0)
+    abort ();
+}
+
+int
+main ()
+{
+  foo (-__INT_MAX__ - 1);
+  bar (-__INT_MAX__ - 1);
+  return 0;
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-11-20  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/55094
	* builtins.c (expand_builtin_trap): Add REG_ARGS_SIZE note
	on the trap insn for !ACCUMULATE_OUTGOING_ARGS.
	* cfgcleanup.c (outgoing_edges_match): Don't look at debug insns
	on the first old_insns_match_p call.  For !ACCUMULATE_OUTGOING_ARGS
	fail if the last real insn doesn't have REG_ARGS_SIZE note.

	* gcc.dg/pr55094.c: New test.

--- gcc/builtins.c	(revision 193648)
+++ gcc/builtins.c	(revision 193649)
@@ -4666,7 +4666,14 @@ expand_builtin_trap (void)
 {
 #ifdef HAVE_trap
   if (HAVE_trap)
-    emit_insn (gen_trap ());
+    {
+      rtx insn = emit_insn (gen_trap ());
+      /* For trap insns when not accumulating outgoing args force
+	 REG_ARGS_SIZE note to prevent crossjumping of calls with
+	 different args sizes.  */
+      if (!ACCUMULATE_OUTGOING_ARGS)
+	add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
+    }
   else
 #endif
     emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
--- gcc/cfgcleanup.c	(revision 193648)
+++ gcc/cfgcleanup.c	(revision 193649)
@@ -1487,6 +1487,8 @@ outgoing_edges_match (int mode, basic_bl
   edge fallthru1 = 0, fallthru2 = 0;
   edge e1, e2;
   edge_iterator ei;
+  rtx last1, last2;
+  bool nonfakeedges;
 
   /* If we performed shrink-wrapping, edges to the EXIT_BLOCK_PTR can
      only be distinguished for JUMP_INSNs.  The two paths may differ in
@@ -1695,9 +1697,15 @@ outgoing_edges_match (int mode, basic_bl
 	}
     }
 
+  last1 = BB_END (bb1);
+  last2 = BB_END (bb2);
+  if (DEBUG_INSN_P (last1))
+    last1 = prev_nondebug_insn (last1);
+  if (DEBUG_INSN_P (last2))
+    last2 = prev_nondebug_insn (last2);
   /* First ensure that the instructions match.  There may be many outgoing
      edges so this test is generally cheaper.  */
-  if (old_insns_match_p (mode, BB_END (bb1), BB_END (bb2)) != dir_both)
+  if (old_insns_match_p (mode, last1, last2) != dir_both)
     return false;
 
   /* Search the outgoing edges, ensure that the counts do match, find possible
@@ -1706,10 +1714,14 @@ outgoing_edges_match (int mode, basic_bl
   if (EDGE_COUNT (bb1->succs) != EDGE_COUNT (bb2->succs))
     return false;
 
+  nonfakeedges = false;
   FOR_EACH_EDGE (e1, ei, bb1->succs)
     {
       e2 = EDGE_SUCC (bb2, ei.index);
 
+      if ((e1->flags & EDGE_FAKE) == 0)
+	nonfakeedges = true;
+
       if (e1->flags & EDGE_EH)
 	nehedges1++;
 
@@ -1727,6 +1739,18 @@ outgoing_edges_match (int mode, basic_bl
       || (fallthru1 != 0) != (fallthru2 != 0))
     return false;
 
+  /* If !ACCUMULATE_OUTGOING_ARGS, bb1 (and bb2) have no successors
+     and the last real insn doesn't have REG_ARGS_SIZE note, don't
+     attempt to optimize, as the two basic blocks might have different
+     REG_ARGS_SIZE depths.  For noreturn calls and unconditional
+     traps there should be REG_ARG_SIZE notes, they could be missing
+     for __builtin_unreachable () uses though.  */
+  if (!nonfakeedges
+      && !ACCUMULATE_OUTGOING_ARGS
+      && (!INSN_P (last1)
+          || !find_reg_note (last1, REG_ARGS_SIZE, NULL)))
+    return false;
+
   /* fallthru edges must be forwarded to the same destination.  */
   if (fallthru1)
     {
--- gcc/testsuite/gcc.dg/pr55094.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr55094.c	(revision 193649)
@@ -0,0 +1,45 @@
+/* PR middle-end/55094 */
+/* { dg-do compile } */
+/* { dg-options "-fcompare-debug -Os" } */
+/* { dg-additional-options "-fomit-frame-pointer -fno-asynchronous-unwind-tables -mpreferred-stack-boundary=2" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
+
+extern int fn (long);
+int v;
+
+int
+foo (int x, long *y)
+{
+  if (x)
+    {
+      fn (y[0]);
+      __builtin_trap ();
+    }
+  __builtin_trap ();
+}
+
+int
+bar (int x, long *y)
+{
+  if (x)
+    {
+      fn (y[0]);
+      v = 1;
+      __builtin_unreachable ();
+    }
+  v = 1;
+  __builtin_unreachable ();
+}
+
+int
+baz (int x, long *y)
+{
+  if (x)
+    {
+      fn (y[0]);
+      v = 1;
+      __builtin_unreachable ();
+    }
+  v = 1;
+  int w = 1;
+  __builtin_unreachable ();
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-11-23  Jakub Jelinek  <jakub@redhat.com>

	PR c++/54046
	* Makefile.in (gimple-low.o): Depend on langhooks.h.
	* gimple-low.c: Include langhooks.c.
	(block_may_fallthru): Handle TARGET_EXPR and ERROR_MARK,
	by default call lang_hooks.block_may_fallthru.
	* langhooks.h (struct lang_hooks): Add block_may_fallthru
	langhook.
	* langhooks-def.h (LANG_HOOKS_BLOCK_MAY_FALLTHRU): Define.
	(LANG_HOOKS_INITIALIZER): Use it.

	* cp-objcp-common.h (LANG_HOOKS_BLOCK_MAY_FALLTHRU): Redefine.
	* cp-objcp-common.c (cxx_block_may_fallthru): New function.
	* cp-tree.h (cxx_block_may_fallthru): New prototype.

	* g++.dg/warn/Wreturn-type-8.C: New test.

--- gcc/cp/cp-objcp-common.c	(revision 193761)
+++ gcc/cp/cp-objcp-common.c	(revision 193762)
@@ -227,6 +227,25 @@ init_shadowed_var_for_decl (void)
 					   tree_decl_map_eq, 0);
 }
 
+/* Return true if stmt can fall thru.  Used by block_may_fallthru
+   default case.  */
+
+bool
+cxx_block_may_fallthru (const_tree stmt)
+{
+  switch (TREE_CODE (stmt))
+    {
+    case EXPR_STMT:
+      return block_may_fallthru (EXPR_STMT_EXPR (stmt));
+
+    case THROW_EXPR:
+      return false;
+
+    default:
+      return true;
+    }
+}
+
 void
 cp_common_init_ts (void)
 {
--- gcc/cp/cp-objcp-common.h	(revision 193761)
+++ gcc/cp/cp-objcp-common.h	(revision 193762)
@@ -94,6 +94,8 @@ extern void cp_common_init_ts (void);
 #define LANG_HOOKS_TYPE_HASH_EQ	cxx_type_hash_eq
 #undef LANG_HOOKS_MISSING_NORETURN_OK_P
 #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p
+#undef LANG_HOOKS_BLOCK_MAY_FALLTHRU
+#define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru
 
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
--- gcc/cp/cp-tree.h	(revision 193761)
+++ gcc/cp/cp-tree.h	(revision 193762)
@@ -6019,6 +6019,7 @@ extern bool cp_var_mod_type_p			(tree, t
 extern void cxx_initialize_diagnostics		(diagnostic_context *);
 extern int cxx_types_compatible_p		(tree, tree);
 extern void init_shadowed_var_for_decl		(void);
+extern bool cxx_block_may_fallthru		(const_tree);
 
 /* in cp-gimplify.c */
 extern int cp_gimplify_expr			(tree *, gimple_seq *,
--- gcc/gimple-low.c	(revision 193761)
+++ gcc/gimple-low.c	(revision 193762)
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.
 #include "function.h"
 #include "diagnostic-core.h"
 #include "tree-pass.h"
+#include "langhooks.h"
 
 /* The differences between High GIMPLE and Low GIMPLE are the
    following:
@@ -739,8 +740,14 @@ block_may_fallthru (const_tree block)
     case CLEANUP_POINT_EXPR:
       return block_may_fallthru (TREE_OPERAND (stmt, 0));
 
-    default:
+    case TARGET_EXPR:
+      return block_may_fallthru (TREE_OPERAND (stmt, 1));
+
+    case ERROR_MARK:
       return true;
+
+    default:
+      return lang_hooks.block_may_fallthru (stmt);
     }
 }
 
--- gcc/langhooks.h	(revision 193761)
+++ gcc/langhooks.h	(revision 193762)
@@ -456,6 +456,10 @@ struct lang_hooks
      FUNCTION_DECL for `std::terminate'.  */
   tree (*eh_protect_cleanup_actions) (void);
 
+  /* Return true if a stmt can fallthru.  Used by block_may_fallthru
+     to possibly handle language trees.  */
+  bool (*block_may_fallthru) (const_tree);
+
   /* True if this language uses __cxa_end_cleanup when the ARM EABI
      is enabled.  */
   bool eh_use_cxa_end_cleanup;
--- gcc/Makefile.in	(revision 193761)
+++ gcc/Makefile.in	(revision 193762)
@@ -2596,7 +2596,7 @@ gimple-low.o : gimple-low.c $(CONFIG_H)
    $(DIAGNOSTIC_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h \
    $(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
    $(EXCEPT_H) $(FLAGS_H) $(RTL_H) $(FUNCTION_H) $(EXPR_H) $(TREE_PASS_H) \
-   $(HASHTAB_H) $(DIAGNOSTIC_CORE_H) tree-iterator.h
+   $(HASHTAB_H) $(DIAGNOSTIC_CORE_H) tree-iterator.h langhooks.h
 omp-low.o : omp-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(RTL_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h $(DIAGNOSTIC_CORE_H) \
    $(TREE_FLOW_H) $(TIMEVAR_H) $(FLAGS_H) $(EXPR_H) $(DIAGNOSTIC_CORE_H) \
--- gcc/langhooks-def.h	(revision 193761)
+++ gcc/langhooks-def.h	(revision 193762)
@@ -115,6 +115,7 @@ extern void lhd_omp_firstprivatize_type_
 #define LANG_HOOKS_EH_PERSONALITY	lhd_gcc_personality
 #define LANG_HOOKS_EH_RUNTIME_TYPE	lhd_pass_through_t
 #define LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS	NULL
+#define LANG_HOOKS_BLOCK_MAY_FALLTHRU	hook_bool_const_tree_true
 #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP	false
 #define LANG_HOOKS_DEEP_UNSHARING	false
 
@@ -300,6 +301,7 @@ extern void lhd_end_section (void);
   LANG_HOOKS_EH_PERSONALITY, \
   LANG_HOOKS_EH_RUNTIME_TYPE, \
   LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS, \
+  LANG_HOOKS_BLOCK_MAY_FALLTHRU, \
   LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
   LANG_HOOKS_DEEP_UNSHARING \
 }
--- gcc/testsuite/g++.dg/warn/Wreturn-type-8.C	(revision 0)
+++ gcc/testsuite/g++.dg/warn/Wreturn-type-8.C	(revision 193762)
@@ -0,0 +1,90 @@
+// PR c++/54046
+// { dg-do compile }
+// { dg-options "-O0 -Wall -Wno-unused" }
+
+void foo (void) __attribute__((noreturn));
+
+struct A
+{
+  ~A () {}
+};
+
+bool
+check1 (int x)
+{
+  A z;
+  switch (x)
+    {
+    case 0:
+      return false;
+    default:
+      throw "X";
+      break;
+    }
+}
+
+bool
+check2 (int x)
+{
+  A z;
+  switch (x)
+    {
+    case 0:
+      return false;
+    default:
+      foo ();
+      break;
+    }
+}
+
+bool
+check3 (int x)
+{
+  switch (x)
+    {
+    case 0:
+      return false;
+    default:
+      throw "X";
+      break;
+    }
+}
+
+bool
+check4 (int x)
+{
+  switch (x)
+    {
+    case 0:
+      return false;
+    default:
+      foo ();
+      break;
+    }
+}
+
+bool
+check5 (int x)
+{
+  A z;
+  switch (x)
+    {
+    case 0:
+      return false;
+    default:
+      throw "X";
+    }
+}
+
+bool
+check6 (int x)
+{
+  A z;
+  switch (x)
+    {
+    case 0:
+      return false;
+    default:
+      foo ();
+    }
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-12-01  Jakub Jelinek  <jakub@redhat.com>

	PR c++/55542
	* pt.c (make_ith_pack_parameter_name): Return NULL if
	name is NULL.
	(tsubst_decl): Call make_ith_pack_parameter_name even if
	DECL_NAME is NULL.

	* g++.dg/cpp0x/vt-55542.C: New test.

--- gcc/cp/pt.c	(revision 194009)
+++ gcc/cp/pt.c	(revision 194010)
@@ -2905,6 +2905,8 @@ make_ith_pack_parameter_name (tree name,
   char* newname;
   int newname_len;
 
+  if (name == NULL_TREE)
+    return name;
   snprintf (numbuf, NUMBUF_LEN, "%i", i);
   newname_len = IDENTIFIER_LENGTH (name)
 	        + strlen (numbuf) + 2;
@@ -10261,10 +10263,9 @@ tsubst_decl (tree t, tree args, tsubst_f
                 /* Get the Ith type.  */
                 type = TREE_VEC_ELT (expanded_types, i);
 
-                if (DECL_NAME (r))
-                  /* Rename the parameter to include the index.  */
-                  DECL_NAME (r) =
-                    make_ith_pack_parameter_name (DECL_NAME (r), i);
+		/* Rename the parameter to include the index.  */
+		DECL_NAME (r)
+		  = make_ith_pack_parameter_name (DECL_NAME (r), i);
               }
             else if (!type)
               /* We're dealing with a normal parameter.  */
--- gcc/testsuite/g++.dg/cpp0x/vt-55542.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/vt-55542.C	(revision 194010)
@@ -0,0 +1,22 @@
+// PR c++/55542
+// { dg-options "-std=c++11" }
+
+template <typename ... P>
+struct B
+{
+  template <typename O>
+  B (O *o, void (O::*f) (P ... p)) {}
+};
+class C
+{
+  void foo (void *, int);
+  template <typename ... A>
+  void bar (A ... a);
+  B <void *> c;
+  B <void *, int> d;
+  C (int) : c (this, &C::bar), d (this, &C::foo) {}
+};
+template <typename ... A>
+void C::bar (A ...)
+{
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-12-13  Jakub Jelinek  <jakub@redhat.com>

	PR c++/55652
	* typeck2.c (merge_exception_specifiers): Don't call operand_equal_p
	if noex is NULL.

	* g++.dg/cpp0x/noexcept19.C: New test.

	2012-12-06  Jakub Jelinek  <jakub@redhat.com>

	PR c++/54207
	* except.c (build_noexcept_spec): Avoid direct comparison
	with boolean_true_node or boolean_false_node, instead use
	operand_equal_p and/or INTEGER_CST check.
	* pt.c (tsubst_exception_specification): Likewise.
	* typeck2.c (merge_exception_specifiers): Likewise.

	* g++.dg/cpp0x/noexcept18.C: New test.

--- gcc/cp/except.c	(revision 194262)
+++ gcc/cp/except.c	(revision 194263)
@@ -1316,15 +1316,21 @@ build_noexcept_spec (tree expr, int comp
 						LOOKUP_NORMAL);
       expr = cxx_constant_value (expr);
     }
-  if (expr == boolean_true_node)
-    return noexcept_true_spec;
-  else if (expr == boolean_false_node)
-    return noexcept_false_spec;
+  if (TREE_CODE (expr) == INTEGER_CST)
+    {
+      if (operand_equal_p (expr, boolean_true_node, 0))
+	return noexcept_true_spec;
+      else
+	{
+	  gcc_checking_assert (operand_equal_p (expr, boolean_false_node, 0));
+	  return noexcept_false_spec;
+	}
+    }
   else if (expr == error_mark_node)
     return error_mark_node;
   else
     {
-      gcc_assert (processing_template_decl || expr == error_mark_node
+      gcc_assert (processing_template_decl
 		  || TREE_CODE (expr) == DEFERRED_NOEXCEPT);
       return build_tree_list (expr, NULL_TREE);
     }
--- gcc/cp/typeck2.c	(revision 194262)
+++ gcc/cp/typeck2.c	(revision 194263)
@@ -1871,7 +1871,7 @@ merge_exception_specifiers (tree list, t
       /* If ADD is a deferred noexcept, we must have been called from
 	 process_subob_fn.  For implicitly declared functions, we build up
 	 a list of functions to consider at instantiation time.  */
-      if (noex == boolean_true_node)
+      if (noex && operand_equal_p (noex, boolean_true_node, 0))
 	noex = NULL_TREE;
       gcc_assert (fn && (!noex || is_overloaded_fn (noex)));
       noex = build_overload (fn, noex);
--- gcc/cp/pt.c	(revision 194262)
+++ gcc/cp/pt.c	(revision 194263)
@@ -10844,7 +10844,7 @@ tsubst_exception_specification (tree fnt
     {
       /* A noexcept-specifier.  */
       tree expr = TREE_PURPOSE (specs);
-      if (expr == boolean_true_node || expr == boolean_false_node)
+      if (TREE_CODE (expr) == INTEGER_CST)
 	new_specs = expr;
       else if (defer_ok)
 	{
--- gcc/testsuite/g++.dg/cpp0x/noexcept18.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/noexcept18.C	(revision 194263)
@@ -0,0 +1,11 @@
+// PR c++/54207
+// { dg-do compile }
+// { dg-options "-std=c++11" }
+
+typedef bool B;
+constexpr B foo () { return true; }
+
+void
+bar () noexcept (foo ())
+{
+}
--- gcc/testsuite/g++.dg/cpp0x/noexcept19.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/noexcept19.C	(revision 194479)
@@ -0,0 +1,29 @@
+// PR c++/55652
+// { dg-do compile }
+// { dg-options "-std=c++11" }
+
+template <typename T>
+struct A
+{
+  static const bool a = false;
+};
+
+template <typename X, typename Y = A <X>>
+struct B
+{
+  B () noexcept (A <Y>::a) {}
+};
+
+template <typename X, typename Y>
+struct C
+{
+  X x;
+  Y y;
+};
+
+struct D
+{
+  D () throw (int);
+};
+
+C <D, B <D>> c;
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-03  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/55838
	* loop-iv.c (iv_number_of_iterations): Call lowpart_subreg on
	iv0.step, iv1.step and step.

	* gcc.dg/pr55838.c: New test.

--- gcc/loop-iv.c	(revision 194836)
+++ gcc/loop-iv.c	(revision 194837)
@@ -2406,6 +2406,9 @@ iv_number_of_iterations (struct loop *lo
       iv1.step = const0_rtx;
     }
 
+  iv0.step = lowpart_subreg (mode, iv0.step, comp_mode);
+  iv1.step = lowpart_subreg (mode, iv1.step, comp_mode);
+
   /* This is either infinite loop or the one that ends immediately, depending
      on initial values.  Unswitching should remove this kind of conditions.  */
   if (iv0.step == const0_rtx && iv1.step == const0_rtx)
@@ -2516,6 +2519,7 @@ iv_number_of_iterations (struct loop *lo
 	step = simplify_gen_unary (NEG, comp_mode, iv1.step, comp_mode);
       else
 	step = iv0.step;
+      step = lowpart_subreg (mode, step, comp_mode);
       delta = simplify_gen_binary (MINUS, comp_mode, iv1.base, iv0.base);
       delta = lowpart_subreg (mode, delta, comp_mode);
       delta = simplify_gen_binary (UMOD, mode, delta, step);
--- gcc/testsuite/gcc.dg/pr55838.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr55838.c	(revision 194837)
@@ -0,0 +1,13 @@
+/* PR rtl-optimization/55838 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -funroll-loops" } */
+
+int a;
+unsigned char c;
+
+void
+f (void)
+{
+  while (c++ < 2)
+    c = a += 129;
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-10  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/55921
	* tree-complex.c (expand_complex_asm): New function.
	(expand_complex_operations_1): Call it for GIMPLE_ASM.

	* gcc.c-torture/compile/pr55921.c: New test.

--- gcc/tree-complex.c	(revision 195079)
+++ gcc/tree-complex.c	(revision 195080)
@@ -1391,6 +1391,36 @@ expand_complex_comparison (gimple_stmt_i
   update_stmt (stmt);
 }
 
+/* Expand inline asm that sets some complex SSA_NAMEs.  */
+
+static void
+expand_complex_asm (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  unsigned int i;
+
+  for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+    {
+      tree link = gimple_asm_output_op (stmt, i);
+      tree op = TREE_VALUE (link);
+      if (TREE_CODE (op) == SSA_NAME
+	  && TREE_CODE (TREE_TYPE (op)) == COMPLEX_TYPE)
+	{
+	  tree type = TREE_TYPE (op);
+	  tree inner_type = TREE_TYPE (type);
+	  tree r = build1 (REALPART_EXPR, inner_type, op);
+	  tree i = build1 (IMAGPART_EXPR, inner_type, op);
+	  gimple_seq list = set_component_ssa_name (op, false, r);
+
+	  if (list)
+	    gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
+
+	  list = set_component_ssa_name (op, true, i);
+	  if (list)
+	    gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
+	}
+    }
+}
 
 /* Process one statement.  If we identify a complex operation, expand it.  */
 
@@ -1403,6 +1433,12 @@ expand_complex_operations_1 (gimple_stmt
   complex_lattice_t al, bl;
   enum tree_code code;
 
+  if (gimple_code (stmt) == GIMPLE_ASM)
+    {
+      expand_complex_asm (gsi);
+      return;
+    }
+
   lhs = gimple_get_lhs (stmt);
   if (!lhs && gimple_code (stmt) != GIMPLE_COND)
     return;
--- gcc/testsuite/gcc.c-torture/compile/pr55921.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/compile/pr55921.c	(revision 195080)
@@ -0,0 +1,22 @@
+/* PR tree-optimization/55921 */
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+typedef union
+{
+  _Complex float cf;
+  long long ll;
+} ucf;
+
+void
+foo (ucf *in, ucf *out, _Complex float r)
+{
+  int i;
+  ucf ucf1;
+  _Complex float cf;
+
+  ucf1.ll = in[i].ll;
+  __asm ("" : "=r" (cf) : "0" (ucf1.ll));
+  cf *= r;
+  __asm ("" : "=r" (ucf1.ll) : "0" (cf));
+  out[i].ll = ucf1.ll;
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-15  Jakub Jelinek  <jakub@redhat.com>

	PR target/55940
	* function.c (thread_prologue_and_epilogue_insns): Always
	add crtl->drap_reg to set_up_by_prologue.set, even if
	stack_realign_drap is false.

	* gcc.dg/pr55940.c: New test.

--- gcc/function.c	(revision 195219)
+++ gcc/function.c	(revision 195220)
@@ -6029,7 +6029,7 @@ thread_prologue_and_epilogue_insns (void
       if (pic_offset_table_rtx)
 	add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
 			     PIC_OFFSET_TABLE_REGNUM);
-      if (stack_realign_drap && crtl->drap_reg)
+      if (crtl->drap_reg)
 	add_to_hard_reg_set (&set_up_by_prologue.set,
 			     GET_MODE (crtl->drap_reg),
 			     REGNO (crtl->drap_reg));
--- gcc/testsuite/gcc.dg/pr55940.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr55940.c	(revision 195220)
@@ -0,0 +1,54 @@
+/* PR target/55940 */
+/* { dg-do run } */
+/* { dg-options "-Os" } */
+/* { dg-additional-options "-mpreferred-stack-boundary=2" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
+
+struct S { int s; unsigned long t; };
+
+__attribute__ ((noinline, noclone)) unsigned long long
+bar (struct S *x, unsigned long y)
+{
+  asm volatile ("" : : "r" (x), "r" (y) : "memory");
+  return x->s + y;
+}
+
+__attribute__ ((noinline, noclone)) unsigned long long
+foo (struct S *x, unsigned long y)
+{
+  unsigned long a;
+  if (__builtin_expect (((__UINTPTR_TYPE__) (x) + 0x1000U < 0x2000U), 0))
+    return ~0ULL;
+  if (__builtin_expect (x->s <= 0 || x->s > 9, 0))
+    return ~0ULL;
+  a = x->t >> 12;
+  if (y == a)
+    return ~0ULL;
+  if (x->s == 3)
+    return x->t + y * 4096;
+  return bar (x, y);
+}
+
+int va, vb, vc, vd;
+
+int
+main ()
+{
+  struct S s;
+  asm volatile ("" : : : "memory");
+  int a = va, b = vb, c = vc, d = vd;
+  asm volatile ("" : : : "memory");
+  int i;
+  for (i = 0; i < 64; i++)
+    if (foo ((struct S *) 0, 0) != ~0ULL)
+      __builtin_abort ();
+  s.s = 3;
+  s.t = 2 << 12;
+  if (foo (&s, 2) != ~0ULL)
+    __builtin_abort ();
+  if (foo (&s, 3) != (2 << 12) + 3 * 4096)
+    __builtin_abort ();
+  asm volatile ("" : : : "memory");
+  va = a; vb = b; vc = c; vd = d;
+  asm volatile ("" : : : "memory");
+  return 0;
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-18  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/56015
	* expr.c (expand_expr_real_2) <case COMPLEX_EXPR>: Handle
	the case where writing real complex part of target modifies
	op1.

	* gfortran.dg/pr56015.f90: New test.

--- gcc/expr.c	(revision 195300)
+++ gcc/expr.c	(revision 195301)
@@ -8860,6 +8860,54 @@ expand_expr_real_2 (sepops ops, rtx targ
 
       if (!target)
 	target = gen_reg_rtx (TYPE_MODE (type));
+      else
+	/* If target overlaps with op1, then either we need to force
+	   op1 into a pseudo (if target also overlaps with op0),
+	   or write the complex parts in reverse order.  */
+	switch (GET_CODE (target))
+	  {
+	  case CONCAT:
+	    if (reg_overlap_mentioned_p (XEXP (target, 0), op1))
+	      {
+		if (reg_overlap_mentioned_p (XEXP (target, 1), op0))
+		  {
+		  complex_expr_force_op1:
+		    temp = gen_reg_rtx (GET_MODE_INNER (GET_MODE (target)));
+		    emit_move_insn (temp, op1);
+		    op1 = temp;
+		    break;
+		  }
+	      complex_expr_swap_order:
+		/* Move the imaginary (op1) and real (op0) parts to their
+		   location.  */
+		write_complex_part (target, op1, true);
+		write_complex_part (target, op0, false);
+
+		return target;
+	      }
+	    break;
+	  case MEM:
+	    temp = adjust_address_nv (target,
+				      GET_MODE_INNER (GET_MODE (target)), 0);
+	    if (reg_overlap_mentioned_p (temp, op1))
+	      {
+		enum machine_mode imode = GET_MODE_INNER (GET_MODE (target));
+		temp = adjust_address_nv (target, imode,
+					  GET_MODE_SIZE (imode));
+		if (reg_overlap_mentioned_p (temp, op0))
+		  goto complex_expr_force_op1;
+		goto complex_expr_swap_order;
+	      }
+	    break;
+	  default:
+	    if (reg_overlap_mentioned_p (target, op1))
+	      {
+		if (reg_overlap_mentioned_p (target, op0))
+		  goto complex_expr_force_op1;
+		goto complex_expr_swap_order;
+	      }
+	    break;
+	  }
 
       /* Move the real (op0) and imaginary (op1) parts to their location.  */
       write_complex_part (target, op0, false);
--- gcc/testsuite/gfortran.dg/pr56015.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/pr56015.f90	(revision 195301)
@@ -0,0 +1,16 @@
+! PR middle-end/56015
+! { dg-do run }
+! { dg-options "-Ofast -fno-inline" }
+
+program pr56015
+  implicit none
+  complex*16 p(10)
+  p(:) = (0.1d0, 0.2d0)
+  p(:) = (0.0d0, 1.0d0) * p(:)
+  call foo (p)
+contains
+  subroutine foo (p)
+    complex*16 p(10)
+    if (any (p .ne. (-0.2d0, 0.1d0))) call abort
+  end subroutine
+end program pr56015
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-21  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/56051
	* fold-const.c (fold_binary_loc): Don't fold
	X < (cast) (1 << Y) into (X >> Y) != 0 if cast is either
	a narrowing conversion, or widening conversion from signed
	to unsigned.

	* gcc.c-torture/execute/pr56051.c: New test.

--- gcc/fold-const.c	(revision 195342)
+++ gcc/fold-const.c	(revision 195343)
@@ -13449,10 +13449,22 @@ fold_binary_loc (location_t loc,
 				   TREE_OPERAND (arg1, 1)),
 			   build_int_cst (TREE_TYPE (arg0), 0));
 
+      /* Similarly for X < (cast) (1 << Y).  But cast can't be narrowing,
+	 otherwise Y might be >= # of bits in X's type and thus e.g.
+	 (unsigned char) (1 << Y) for Y 15 might be 0.
+	 If the cast is widening, then 1 << Y should have unsigned type,
+	 otherwise if Y is number of bits in the signed shift type minus 1,
+	 we can't optimize this.  E.g. (unsigned long long) (1 << Y) for Y
+	 31 might be 0xffffffff80000000.  */
       if ((code == LT_EXPR || code == GE_EXPR)
 	  && TYPE_UNSIGNED (TREE_TYPE (arg0))
 	  && CONVERT_EXPR_P (arg1)
 	  && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
+	  && (TYPE_PRECISION (TREE_TYPE (arg1))
+	      >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0))))
+	  && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 0)))
+	      || (TYPE_PRECISION (TREE_TYPE (arg1))
+		  == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0)))))
 	  && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
 	{
 	  tem = build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
--- gcc/testsuite/gcc.c-torture/execute/pr56051.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/pr56051.c	(revision 195343)
@@ -0,0 +1,32 @@
+/* PR tree-optimization/56051 */
+
+extern void abort (void);
+
+int
+main ()
+{
+  unsigned char x1[1] = { 0 };
+  unsigned int s1 = __CHAR_BIT__;
+  int a1 = x1[0] < (unsigned char) (1 << s1);
+  unsigned char y1 = (unsigned char) (1 << s1);
+  int b1 = x1[0] < y1;
+  if (a1 != b1)
+    abort ();
+#if __SIZEOF_LONG_LONG__ > __SIZEOF_INT__
+  unsigned long long x2[1] = { 2ULL << (sizeof (int) * __CHAR_BIT__) };
+  unsigned int s2 = sizeof (int) * __CHAR_BIT__ - 1;
+  int a2 = x2[0] >= (unsigned long long) (1 << s2);
+  unsigned long long y2 = 1 << s2;
+  int b2 = x2[0] >= y2;
+  if (a2 != b2)
+    abort ();
+  unsigned long long x3[1] = { 2ULL << (sizeof (int) * __CHAR_BIT__) };
+  unsigned int s3 = sizeof (int) * __CHAR_BIT__ - 1;
+  int a3 = x3[0] >= (unsigned long long) (1U << s3);
+  unsigned long long y3 = 1U << s3;
+  int b3 = x3[0] >= y3;
+  if (a3 != b3)
+    abort ();
+#endif
+  return 0;
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-22  Jakub Jelinek  <jakub@redhat.com>

	PR libquadmath/56072
	* libquadmath.texi (M_PI_2q, M_PI_4q): Fix up description.

--- libquadmath/libquadmath.texi	(revision 195359)
+++ libquadmath/libquadmath.texi	(revision 195360)
@@ -123,8 +123,8 @@ The following mathematical constants of
 @item @code{M_LN2q}: natural logarithm of 2
 @item @code{M_LN10q}: natural logarithm of 10
 @item @code{M_PIq}: pi
-@item @code{M_PI_2q}: two pi
-@item @code{M_PI_4q}: four pi
+@item @code{M_PI_2q}: pi divided by two
+@item @code{M_PI_4q}: pi divided by four
 @item @code{M_1_PIq}: one over pi
 @item @code{M_2_PIq}: one over two pi
 @item @code{M_2_SQRTPIq}: two over square root of pi
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-23  Jakub Jelinek  <jakub@redhat.com>

	PR target/49069
	* config/arm/arm.md (cbranchdi4, cstoredi4): Use s_register_operand
	instead of cmpdi_operand for first comparison operand.
	Don't assert that comparison operands aren't both constants.

	* gcc.dg/pr49069.c: New test.

--- gcc/config/arm/arm.md	(revision 195397)
+++ gcc/config/arm/arm.md	(revision 195398)
@@ -6904,7 +6904,7 @@
 (define_expand "cbranchdi4"
   [(set (pc) (if_then_else
 	      (match_operator 0 "expandable_comparison_operator"
-	       [(match_operand:DI 1 "cmpdi_operand" "")
+	       [(match_operand:DI 1 "s_register_operand" "")
 	        (match_operand:DI 2 "cmpdi_operand" "")])
 	      (label_ref (match_operand 3 "" ""))
 	      (pc)))]
@@ -6913,10 +6913,6 @@
      rtx swap = NULL_RTX;
      enum rtx_code code = GET_CODE (operands[0]);
 
-     /* We should not have two constants.  */
-     gcc_assert (GET_MODE (operands[1]) == DImode
-		 || GET_MODE (operands[2]) == DImode);
-
     /* Flip unimplemented DImode comparisons to a form that
        arm_gen_compare_reg can handle.  */
      switch (code)
@@ -7917,17 +7913,13 @@
 (define_expand "cstoredi4"
   [(set (match_operand:SI 0 "s_register_operand" "")
 	(match_operator:SI 1 "expandable_comparison_operator"
-	 [(match_operand:DI 2 "cmpdi_operand" "")
+	 [(match_operand:DI 2 "s_register_operand" "")
 	  (match_operand:DI 3 "cmpdi_operand" "")]))]
   "TARGET_32BIT"
   "{
      rtx swap = NULL_RTX;
      enum rtx_code code = GET_CODE (operands[1]);
 
-     /* We should not have two constants.  */
-     gcc_assert (GET_MODE (operands[2]) == DImode
-		 || GET_MODE (operands[3]) == DImode);
-
     /* Flip unimplemented DImode comparisons to a form that
        arm_gen_compare_reg can handle.  */
      switch (code)
--- gcc/testsuite/gcc.dg/pr49069.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr49069.c	(revision 195398)
@@ -0,0 +1,15 @@
+/* PR target/49069 */
+/* { dg-do compile } */
+/* { dg-options "-Os -fno-tree-forwprop -Wno-div-by-zero" } */
+
+int a;
+const unsigned long long b[1] = { 1ULL };
+extern void bar (int);
+
+void
+foo (void)
+{
+  for (a = 0; a == 1; a = 2)
+    ;
+  bar (b[0] == (a == 0 ? a : a / 0));
+}
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-23  Jakub Jelinek  <jakub@redhat.com>

	PR fortran/56052
	* trans-decl.c (gfc_get_symbol_decl): Set DECL_ARTIFICIAL
	and DECL_IGNORED_P on select_type_temporary and don't set
	DECL_BY_REFERENCE.

	* gfortran.dg/gomp/pr56052.f90: New test.

--- gcc/fortran/trans-decl.c	(revision 195398)
+++ gcc/fortran/trans-decl.c	(revision 195399)
@@ -1397,6 +1397,12 @@ gfc_get_symbol_decl (gfc_symbol * sym)
 	DECL_IGNORED_P (decl) = 1;
     }
 
+  if (sym->attr.select_type_temporary)
+    {
+      DECL_ARTIFICIAL (decl) = 1;
+      DECL_IGNORED_P (decl) = 1;
+    }
+
   if (sym->attr.dimension || sym->attr.codimension)
     {
       /* Create variables to hold the non-constant bits of array info.  */
@@ -1496,7 +1502,8 @@ gfc_get_symbol_decl (gfc_symbol * sym)
       && POINTER_TYPE_P (TREE_TYPE (decl))
       && !sym->attr.pointer
       && !sym->attr.allocatable
-      && !sym->attr.proc_pointer)
+      && !sym->attr.proc_pointer
+      && !sym->attr.select_type_temporary)
     DECL_BY_REFERENCE (decl) = 1;
 
   if (sym->attr.vtab
--- gcc/testsuite/gfortran.dg/gomp/pr56052.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/gomp/pr56052.f90	(revision 195399)
@@ -0,0 +1,16 @@
+! PR fortran/56052
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+subroutine middle(args)
+  type args_t
+  end type
+  type, extends(args_t) :: scan_args_t
+  end type
+  class(args_t),intent(inout) :: args
+  !$omp single
+    select type (args)
+      type is (scan_args_t)
+    end select
+  !$omp end single
+end subroutine middle
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-25  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/56098
	* tree-ssa-phiopt.c (nt_init_block): Don't call add_or_mark_expr
	for stmts with volatile ops.
	(cond_store_replacement): Don't optimize if assign has volatile ops.
	(cond_if_else_store_replacement_1): Don't optimize if either
	then_assign or else_assign have volatile ops.

	* gcc.dg/pr56098-1.c: New test.

--- gcc/tree-ssa-phiopt.c	(revision 195474)
+++ gcc/tree-ssa-phiopt.c	(revision 195475)
@@ -1342,7 +1342,7 @@ nt_init_block (struct dom_walk_data *dat
     {
       gimple stmt = gsi_stmt (gsi);
 
-      if (gimple_assign_single_p (stmt))
+      if (gimple_assign_single_p (stmt) && !gimple_has_volatile_ops (stmt))
 	{
 	  add_or_mark_expr (bb, gimple_assign_lhs (stmt), nontrap_set, true);
 	  add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), nontrap_set, false);
@@ -1419,7 +1419,8 @@ cond_store_replacement (basic_block midd
 
   /* Check if middle_bb contains of only one store.  */
   if (!assign
-      || !gimple_assign_single_p (assign))
+      || !gimple_assign_single_p (assign)
+      || gimple_has_volatile_ops (assign))
     return false;
 
   locus = gimple_location (assign);
@@ -1490,9 +1491,11 @@ cond_if_else_store_replacement_1 (basic_
   if (then_assign == NULL
       || !gimple_assign_single_p (then_assign)
       || gimple_clobber_p (then_assign)
+      || gimple_has_volatile_ops (then_assign)
       || else_assign == NULL
       || !gimple_assign_single_p (else_assign)
-      || gimple_clobber_p (else_assign))
+      || gimple_clobber_p (else_assign)
+      || gimple_has_volatile_ops (else_assign))
     return false;
 
   lhs = gimple_assign_lhs (then_assign);
--- gcc/testsuite/gcc.dg/pr56098-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr56098-1.c	(revision 195475)
@@ -0,0 +1,16 @@
+/* PR tree-optimization/56098 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+volatile int *p;
+
+void
+foo (int x)
+{
+  *p = 1;
+  if (x)
+    *p = 2;
+}
+
+/* { dg-final { scan-tree-dump-not "=\[^\n\r]*\\*p" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
2013-02-01  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-28  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/56125
	* tree-ssa-math-opts.c (gimple_expand_builtin_pow): Don't optimize
	pow(x,c) into sqrt(x) * powi(x, n/2) or
	1.0 / (sqrt(x) * powi(x, abs(n/2))) if c is an integer or when
	optimizing for size.
	Don't optimize pow(x,c) into powi(x, n/3) * powi(cbrt(x), n%3) or
	1.0 / (powi(x, abs(n)/3) * powi(cbrt(x), abs(n)%3)) if 2c is an
	integer.

	* gcc.dg/pr56125.c: New test.

--- gcc/tree-ssa-math-opts.c	(revision 195506)
+++ gcc/tree-ssa-math-opts.c	(revision 195507)
@@ -1113,7 +1113,7 @@ gimple_expand_builtin_pow (gimple_stmt_i
   tree type, sqrtfn, cbrtfn, sqrt_arg0, sqrt_sqrt, result, cbrt_x, powi_cbrt_x;
   tree target = NULL_TREE;
   enum machine_mode mode;
-  bool hw_sqrt_exists;
+  bool hw_sqrt_exists, c_is_int, c2_is_int;
 
   /* If the exponent isn't a constant, there's nothing of interest
      to be done.  */
@@ -1125,8 +1125,9 @@ gimple_expand_builtin_pow (gimple_stmt_i
   c = TREE_REAL_CST (arg1);
   n = real_to_integer (&c);
   real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+  c_is_int = real_identical (&c, &cint);
 
-  if (real_identical (&c, &cint)
+  if (c_is_int
       && ((n >= -1 && n <= 2)
 	  || (flag_unsafe_math_optimizations
 	      && optimize_insn_for_speed_p ()
@@ -1224,7 +1225,8 @@ gimple_expand_builtin_pow (gimple_stmt_i
       return build_and_insert_call (gsi, loc, &target, cbrtfn, sqrt_arg0);
     }
 
-  /* Optimize pow(x,c), where n = 2c for some nonzero integer n, into
+  /* Optimize pow(x,c), where n = 2c for some nonzero integer n
+     and c not an integer, into
 
        sqrt(x) * powi(x, n/2),                n > 0;
        1.0 / (sqrt(x) * powi(x, abs(n/2))),   n < 0.
@@ -1233,10 +1235,13 @@ gimple_expand_builtin_pow (gimple_stmt_i
   real_arithmetic (&c2, MULT_EXPR, &c, &dconst2);
   n = real_to_integer (&c2);
   real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+  c2_is_int = real_identical (&c2, &cint);
 
   if (flag_unsafe_math_optimizations
       && sqrtfn
-      && real_identical (&c2, &cint))
+      && c2_is_int
+      && !c_is_int
+      && optimize_function_for_speed_p (cfun))
     {
       tree powi_x_ndiv2 = NULL_TREE;
 
@@ -1289,6 +1294,7 @@ gimple_expand_builtin_pow (gimple_stmt_i
       && cbrtfn
       && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
       && real_identical (&c2, &c)
+      && !c2_is_int
       && optimize_function_for_speed_p (cfun)
       && powi_cost (n / 3) <= POWI_MAX_MULTS)
     {
--- gcc/testsuite/gcc.dg/pr56125.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr56125.c	(revision 195507)
@@ -0,0 +1,21 @@
+/* PR tree-optimization/56125 */
+/* { dg-do run } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern void abort (void);
+extern double fabs (double);
+
+__attribute__((cold)) double
+foo (double x, double n)
+{
+  double u = x / (n * n);
+  return u;
+}
+
+int
+main ()
+{
+  if (fabs (foo (29, 2) - 7.25) > 0.001)
+    abort ();
+  return 0;
+}
diff mbox

Patch

--- gcc/cfgrtl.c	(revision 193469)
+++ gcc/cfgrtl.c	(revision 193470)
@@ -1424,14 +1424,46 @@  force_nonfallthru_and_redirect (edge e,
       && (note = extract_asm_operands (PATTERN (BB_END (e->src)))))
     {
       int i, n = ASM_OPERANDS_LABEL_LENGTH (note);
+      bool adjust_jump_target = false;
 
       for (i = 0; i < n; ++i)
 	{
 	  if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest))
-	    XEXP (ASM_OPERANDS_LABEL (note, i), 0) = block_label (target);
+	    {
+	      LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))--;
+	      XEXP (ASM_OPERANDS_LABEL (note, i), 0) = block_label (target);
+	      LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))++;
+	      adjust_jump_target = true;
+	    }
 	  if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (target))
 	    asm_goto_edge = true;
 	}
+      if (adjust_jump_target)
+	{
+	  rtx insn = BB_END (e->src), note;
+	  rtx old_label = BB_HEAD (e->dest);
+	  rtx new_label = BB_HEAD (target);
+
+	  if (JUMP_LABEL (insn) == old_label)
+	    {
+	      JUMP_LABEL (insn) = new_label;
+	      note = find_reg_note (insn, REG_LABEL_TARGET, new_label);
+	      if (note)
+		remove_note (insn, note);
+	    }
+	  else
+	    {
+	      note = find_reg_note (insn, REG_LABEL_TARGET, old_label);
+	      if (note)
+		remove_note (insn, note);
+	      if (JUMP_LABEL (insn) != new_label
+		  && !find_reg_note (insn, REG_LABEL_TARGET, new_label))
+		add_reg_note (insn, REG_LABEL_TARGET, new_label);
+	    }
+	  while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label))
+		 != NULL_RTX)
+	    XEXP (note, 0) = new_label;
+	}
     }
 
   if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || asm_goto_edge)
--- gcc/testsuite/gcc.dg/torture/pr54127.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr54127.c	(revision 193470)
@@ -0,0 +1,16 @@ 
+/* PR rtl-optimization/54127 */
+/* { dg-do compile } */
+
+extern void foo (void) __attribute__ ((__noreturn__));
+
+void
+bar (int x)
+{
+  if (x < 0)
+    foo ();
+  if (x == 0)
+    return;
+  __asm goto ("# %l[lab] %l[lab2]" : : : : lab, lab2);
+lab:;
+lab2:;
+}