Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 260550)
+++ gcc/target.def	(working copy)
@@ -3498,6 +3498,13 @@ If this hook allows @code{val} to have a
  hook_bool_mode_uhwi_false)
 
 DEFHOOK
+(default_widening_p,
+ "Return true if GCC can automatically widen from @var{from_mode} to\n\
+@var{to_mode}.  Conversions are unsigned if @var{unsigned_p} is true.",
+ bool, (machine_mode, machine_mode, bool),
+ hook_bool_mode_mode_bool_true)
+
+DEFHOOK
 (libgcc_floating_mode_supported_p,
  "Define this to return nonzero if libgcc provides support for the \n\
 floating-point mode @var{mode}, which is known to pass \n\
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 260550)
+++ gcc/targhooks.c	(working copy)
@@ -2345,4 +2345,12 @@ default_select_early_remat_modes (sbitma
 {
 }
 
+bool
+hook_bool_mode_mode_bool_true (machine_mode from_mode ATTRIBUTE_UNUSED,
+			       machine_mode to_mode ATTRIBUTE_UNUSED,
+			       bool unsigned_p ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
 #include "gt-targhooks.h"
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 260550)
+++ gcc/targhooks.h	(working copy)
@@ -289,5 +289,6 @@ extern enum flt_eval_method
 default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED);
 extern bool default_stack_clash_protection_final_dynamic_probe (rtx);
 extern void default_select_early_remat_modes (sbitmap);
+extern bool hook_bool_mode_mode_bool_true (machine_mode, machine_mode, bool);
 
 #endif /* GCC_TARGHOOKS_H */
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	(revision 260550)
+++ gcc/optabs.c	(working copy)
@@ -1284,14 +1284,15 @@ expand_binop (machine_mode mode, optab b
     FOR_EACH_WIDER_MODE (wider_mode, mode)
       {
 	machine_mode next_mode;
-	if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
-	    || (binoptab == smul_optab
-		&& GET_MODE_WIDER_MODE (wider_mode).exists (&next_mode)
-		&& (find_widening_optab_handler ((unsignedp
-						  ? umul_widen_optab
-						  : smul_widen_optab),
-						 next_mode, mode)
-		    != CODE_FOR_nothing)))
+	if ((optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
+	     || (binoptab == smul_optab
+		 && GET_MODE_WIDER_MODE (wider_mode).exists (&next_mode)
+		 && (find_widening_optab_handler ((unsignedp
+						   ? umul_widen_optab
+						   : smul_widen_optab),
+						  next_mode, mode)
+		     != CODE_FOR_nothing)))
+	    && targetm.default_widening_p (mode, wider_mode, unsignedp))
 	  {
 	    rtx xop0 = op0, xop1 = op1;
 	    int no_extend = 0;
@@ -1834,9 +1835,10 @@ expand_binop (machine_mode mode, optab b
       gcc_assert (!convert_optab_p (binoptab));
       FOR_EACH_WIDER_MODE (wider_mode, mode)
 	{
-	  if (optab_handler (binoptab, wider_mode)
-	      || (methods == OPTAB_LIB
-		  && optab_libfunc (binoptab, wider_mode)))
+	  if ((optab_handler (binoptab, wider_mode)
+	       || (methods == OPTAB_LIB
+		   && optab_libfunc (binoptab, wider_mode)))
+	      && targetm.default_widening_p (mode, wider_mode, unsignedp))
 	    {
 	      rtx xop0 = op0, xop1 = op1;
 	      int no_extend = 0;
@@ -1989,7 +1991,8 @@ expand_twoval_unop (optab unoptab, rtx o
     {
       FOR_EACH_WIDER_MODE (wider_mode, mode)
 	{
-	  if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
+	  if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing
+	      && targetm.default_widening_p (mode, wider_mode, unsignedp))
 	    {
 	      rtx t0 = gen_reg_rtx (wider_mode);
 	      rtx t1 = gen_reg_rtx (wider_mode);
@@ -2070,7 +2073,8 @@ expand_twoval_binop (optab binoptab, rtx
     {
       FOR_EACH_WIDER_MODE (wider_mode, mode)
 	{
-	  if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing)
+	  if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
+	      && targetm.default_widening_p (mode, wider_mode, unsignedp))
 	    {
 	      rtx t0 = gen_reg_rtx (wider_mode);
 	      rtx t1 = gen_reg_rtx (wider_mode);
@@ -2169,7 +2173,9 @@ widen_leading (scalar_int_mode mode, rtx
   FOR_EACH_WIDER_MODE (wider_mode_iter, mode)
     {
       scalar_int_mode wider_mode = wider_mode_iter.require ();
-      if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
+      bool unsignedp = unoptab != clrsb_optab;
+      if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing
+	  && targetm.default_widening_p (mode, wider_mode, unsignedp))
 	{
 	  rtx xop0, temp;
 	  rtx_insn *last;
@@ -2178,10 +2184,8 @@ widen_leading (scalar_int_mode mode, rtx
 
 	  if (target == 0)
 	    target = gen_reg_rtx (mode);
-	  xop0 = widen_operand (op0, wider_mode, mode,
-				unoptab != clrsb_optab, false);
-	  temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
-			      unoptab != clrsb_optab);
+	  xop0 = widen_operand (op0, wider_mode, mode, unsignedp, false);
+	  temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, unsignedp);
 	  if (temp != 0)
 	    temp = expand_binop
 	      (wider_mode, sub_optab, temp,
@@ -2333,9 +2337,12 @@ widen_bswap (scalar_int_mode mode, rtx o
   opt_scalar_int_mode wider_mode_iter;
 
   FOR_EACH_WIDER_MODE (wider_mode_iter, mode)
-    if (optab_handler (bswap_optab, wider_mode_iter.require ())
-	!= CODE_FOR_nothing)
-      break;
+    {
+      machine_mode wider_mode = wider_mode_iter.require ();
+      if (optab_handler (bswap_optab, wider_mode) != CODE_FOR_nothing
+	  && targetm.default_widening_p (mode, wider_mode, true))
+	break;
+    }
 
   if (!wider_mode_iter.exists ())
     return NULL_RTX;
@@ -2865,7 +2872,8 @@ expand_unop (machine_mode mode, optab un
   if (CLASS_HAS_WIDER_MODES_P (mclass))
     FOR_EACH_WIDER_MODE (wider_mode, mode)
       {
-	if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
+	if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing
+	    && targetm.default_widening_p (mode, wider_mode, unsignedp))
 	  {
 	    rtx xop0 = op0;
 	    rtx_insn *last = get_last_insn ();
@@ -3032,8 +3040,9 @@ expand_unop (machine_mode mode, optab un
     {
       FOR_EACH_WIDER_MODE (wider_mode, mode)
 	{
-	  if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing
-	      || optab_libfunc (unoptab, wider_mode))
+	  if ((optab_handler (unoptab, wider_mode) != CODE_FOR_nothing
+	       || optab_libfunc (unoptab, wider_mode))
+	      && targetm.default_widening_p (mode, wider_mode, unsignedp))
 	    {
 	      rtx xop0 = op0;
 	      rtx_insn *last = get_last_insn ();
Index: gcc/cse.c
===================================================================
--- gcc/cse.c	(revision 260550)
+++ gcc/cse.c	(working copy)
@@ -4885,6 +4885,9 @@ cse_insn (rtx_insn *insn)
 	      if (GET_MODE_PRECISION (wider_mode) > BITS_PER_WORD)
 		break;
 
+	      if (!targetm.default_widening_p (mode, wider_mode, false))
+		continue;
+
 	      struct table_elt *const_elt
 		= lookup (src_const, HASH (src_const, wider_mode), wider_mode);
 
@@ -4924,6 +4927,9 @@ cse_insn (rtx_insn *insn)
 	      if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
 		break;
 
+	      if (!targetm.default_widening_p (mode, tmode, false))
+		continue;
+
 	      rtx inner = gen_lowpart (tmode, XEXP (src, 0));
 	      struct table_elt *larger_elt;
 
@@ -4979,6 +4985,9 @@ cse_insn (rtx_insn *insn)
 	      if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
 		break;
 
+	      if (!targetm.default_widening_p (mode, tmode, false))
+		continue;
+
 	      PUT_MODE (memory_extend_rtx, tmode);
 	      larger_elt = lookup (memory_extend_rtx,
 				   HASH (memory_extend_rtx, tmode), tmode);
Index: gcc/combine.c
===================================================================
--- gcc/combine.c	(revision 260550)
+++ gcc/combine.c	(working copy)
@@ -12965,6 +12965,9 @@ simplify_comparison (enum rtx_code code,
 				  || (nonzero_bits (op1, tmode)
 				      & ~GET_MODE_MASK (mode)) == 0)));
 
+	    if (!targetm.default_widening_p (mode, tmode, zero_extended))
+	      continue;
+
 	    if (zero_extended
 		|| ((num_sign_bit_copies (op0, tmode)
 		     > (unsigned int) (GET_MODE_PRECISION (tmode)
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	(revision 260550)
+++ gcc/var-tracking.c	(working copy)
@@ -6347,10 +6347,14 @@ prepare_call_arguments (basic_block bb,
 		opt_scalar_int_mode mode_iter;
 		FOR_EACH_WIDER_MODE (mode_iter, mode)
 		  {
+		    machine_mode old_mode = mode;
 		    mode = mode_iter.require ();
 		    if (GET_MODE_BITSIZE (mode) > BITS_PER_WORD)
 		      break;
 
+		    if (!targetm.default_widening_p (old_mode, mode, false))
+		      continue;
+
 		    rtx reg = simplify_subreg (mode, x, GET_MODE (x), 0);
 		    if (reg == NULL_RTX || !REG_P (reg))
 		      continue;
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 260552)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1973,6 +1973,9 @@ static const struct attribute_spec rs600
 
 #undef TARGET_STARTING_FRAME_OFFSET
 #define TARGET_STARTING_FRAME_OFFSET rs6000_starting_frame_offset
+
+#undef TARGET_DEFAULT_WIDENING_P
+#define TARGET_DEFAULT_WIDENING_P rs6000_default_widening_p
 
 
 /* Processor table.  */
@@ -16502,6 +16505,29 @@ rs6000_init_builtins (void)
 #endif
 }
 
+/* Return true if FROM_MODE can be widened to TO_MODE automatically.  UNSIGNEDP
+   says the conversion is unsigned.
+
+   On PowerPC, don't allow IBM extended double to widen to an IEEE 128-bit
+   floating point value or vice versa.  */
+
+static bool
+rs6000_default_widening_p (machine_mode from_mode,
+			   machine_mode to_mode,
+			   bool unsignedp ATTRIBUTE_UNUSED)
+{
+  if (!TARGET_FLOAT128_TYPE)
+    return true;
+
+  if (FLOAT128_IEEE_P (from_mode) && FLOAT128_IBM_P (to_mode))
+    return false;
+
+  if (FLOAT128_IBM_P (from_mode) && FLOAT128_IEEE_P (to_mode))
+    return false;
+
+  return true;
+}
+
 /* Returns the rs6000 builtin decl for CODE.  */
 
 static tree
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 260550)
+++ gcc/doc/tm.texi	(working copy)
@@ -4315,6 +4315,11 @@ If this hook allows @code{val} to have a
 @code{int8x8x3_t}s in registers rather than forcing them onto the stack.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_DEFAULT_WIDENING_P (machine_mode, @var{machine_mode}, @var{bool})
+Return true if GCC can automatically widen from @var{from_mode} to
+@var{to_mode}.  Conversions are unsigned if @var{unsigned_p} is true.
+@end deftypefn
+
 @deftypefn {Target Hook} bool TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P (scalar_float_mode @var{mode})
 Define this to return nonzero if libgcc provides support for the 
 floating-point mode @var{mode}, which is known to pass 
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 260550)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -3344,6 +3344,8 @@ stack.
 
 @hook TARGET_ARRAY_MODE_SUPPORTED_P
 
+@hook TARGET_DEFAULT_WIDENING_P
+
 @hook TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P
 
 @hook TARGET_FLOATN_MODE
Index: gcc/testsuite/gcc.target/powerpc/pr85358.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr85358.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/pr85358.c	(working copy)
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { powerpc*-*-linux* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -mfloat128 -O2 -mabi=ieeelongdouble -Wno-psabi" } */
+
+/* Verify that __ibm128 does not get converted automatically to IEEE 128-bit on
+   machines with IEEE 128-bit hardware support.  */
+
+__ibm128
+add (__ibm128 a, __ibm128 b)
+{
+  return a + b;
+}
+
+/* { dg-final { scan-assembler-not {\mxsaddqp\M} } } */
