diff mbox

Fix PR46399 - missing mode promotion for libcall args

Message ID 20110224180234.GA17914@bart
State New
Headers show

Commit Message

Andreas Krebbel Feb. 24, 2011, 6:02 p.m. UTC
Hi,

this is the second try to fix the missing mode promotion of libcall
args I see on s390x.

When calling the __dpd_floatsisd as a libcall function the SI mode
parameter currently is not zero extended to 64 bit as it is expected
by the s390x ABI.  Since the function is compiled from C code the code
relies on the upper 32 bit being zero and produces wrong results if
not.

I think the problem can occur on every target:
* which needs argument promotion like this
* which does not use the PROMOTE_MODE macro to promote everything
  copied into a register
* which uses C compiled library functions

One fix would be using the promote_function_mode function in
emit_library_call_value_1 and invoke it with a NULL TYPE value in
order to indicate the back-end that it is called for a libcall.
Unfortunately this would require to touch every single target
including the default implementations of the promote_function_mode
target hook.  So I decided to add a new target hook specifically for
promoting libcall arguments instead.

This fixes two s390x testsuite failues:

< FAIL: gcc.dg/dfp/pr41049.c execution test
< FAIL: decimal/comparison.cc execution test

Ok for mainline?

Bye,

-Andreas-

2011-02-24  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	PR middle-end/46399
	* calls.c (emit_library_call_value_1): Promote libcall arguments
	using promote_libcall_mode.
	* explow.c (promote_libcall_mode): New function.
	* expr.h (promote_libcall_mode): New prototype.
	* target.def (promote_libcall_mode): New target hook.
	* targhooks.c (default_promote_libcall_mode): New function.
	* targhooks.h (default_promote_libcall_mode): New prototype.
	* config/s390/s390.c (s390_promote_libcall_mode): New function.

	* doc/tm.texi.in: Document new target hook.
	* doc/tm.texi: Regenerate.

Comments

Nathan Froyd Feb. 24, 2011, 6:05 p.m. UTC | #1
On Thu, Feb 24, 2011 at 07:02:34PM +0100, Andreas Krebbel wrote:
> Index: gcc/doc/tm.texi.in
> ===================================================================
> --- gcc/doc/tm.texi.in.orig
> +++ gcc/doc/tm.texi.in
> @@ -968,6 +968,15 @@ also define the hook to @code{default_pr
>  if you would like to apply the same rules given by @code{PROMOTE_MODE}.
>  @end deftypefn
>  
> +@hook TARGET_PROMOTE_LIBCALL_MODE
> +Like @code{TARGET_PROMOTE_FUNCTION_MODE}, but it is applied to libcall
> +arguments only.  Define this if your target requires function
> +arguments to be promoted to a larger mode and uses C compiled libcall
> +routines (e.g. libdecnumber).
> +
> +The default is not promote arguments and return values.
> +@end deftypefn

No comments about the rest of the patch, but please put the
documentation in target.def for new hooks.

-Nathan
diff mbox

Patch

Index: gcc/calls.c
===================================================================
--- gcc/calls.c.orig
+++ gcc/calls.c
@@ -3481,6 +3481,7 @@  emit_library_call_value_1 (int retval, r
     {
       rtx val = va_arg (p, rtx);
       enum machine_mode mode = (enum machine_mode) va_arg (p, int);
+      int unsigned_p = 0;
 
       /* We cannot convert the arg value to the mode the library wants here;
 	 must do it earlier where we know the signedness of the arg.  */
@@ -3528,9 +3529,9 @@  emit_library_call_value_1 (int retval, r
 	  val = force_operand (XEXP (slot, 0), NULL_RTX);
 	}
 
-      argvec[count].value = val;
+      mode = promote_libcall_mode (mode, &unsigned_p, fntype, 1);
       argvec[count].mode = mode;
-
+      argvec[count].value = convert_modes (mode, GET_MODE (val), val, unsigned_p);
       argvec[count].reg = targetm.calls.function_arg (&args_so_far, mode,
 						      NULL_TREE, true);
 
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in.orig
+++ gcc/doc/tm.texi.in
@@ -968,6 +968,15 @@  also define the hook to @code{default_pr
 if you would like to apply the same rules given by @code{PROMOTE_MODE}.
 @end deftypefn
 
+@hook TARGET_PROMOTE_LIBCALL_MODE
+Like @code{TARGET_PROMOTE_FUNCTION_MODE}, but it is applied to libcall
+arguments only.  Define this if your target requires function
+arguments to be promoted to a larger mode and uses C compiled libcall
+routines (e.g. libdecnumber).
+
+The default is not promote arguments and return values.
+@end deftypefn
+
 @defmac PARM_BOUNDARY
 Normal alignment required for function parameters on the stack, in
 bits.  All stack parameters receive at least this much alignment
Index: gcc/explow.c
===================================================================
--- gcc/explow.c.orig
+++ gcc/explow.c
@@ -783,6 +783,25 @@  promote_function_mode (const_tree type, 
       return mode;
     }
 }
+
+/* Return the mode to use to pass or return a scalar of MODE for a libcall.
+   PUNSIGNEDP points to the signedness of the type and may be adjusted
+   to show what signedness to use on extension operations.
+
+   FOR_RETURN is nonzero if the caller is promoting the return value
+   of FNDECL, else it is for promoting args.  */
+
+enum machine_mode
+promote_libcall_mode (enum machine_mode mode, int *punsignedp,
+		      const_tree funtype, int for_return)
+{
+  if (INTEGRAL_MODE_P (mode))
+    return targetm.calls.promote_libcall_mode (mode, punsignedp, funtype,
+					       for_return);
+  else
+    return mode;
+}
+
 /* Return the mode to use to store a scalar of TYPE and MODE.
    PUNSIGNEDP points to the signedness of the type and may be adjusted
    to show what signedness to use on extension operations.  */
Index: gcc/expr.h
===================================================================
--- gcc/expr.h.orig
+++ gcc/expr.h
@@ -613,6 +613,11 @@  extern rtx force_not_mem (rtx);
 extern enum machine_mode promote_function_mode (const_tree, enum machine_mode, int *,
 					        const_tree, int);
 
+/* Return mode and signedness to use when an libcall argument or
+   result in the given mode is promoted.  */
+extern enum machine_mode promote_libcall_mode (enum machine_mode, int *,
+					       const_tree, int);
+
 /* Return mode and signedness to use when an object in the given mode
    is promoted.  */
 extern enum machine_mode promote_mode (const_tree, enum machine_mode, int *);
Index: gcc/target.def
===================================================================
--- gcc/target.def.orig
+++ gcc/target.def
@@ -1918,6 +1918,13 @@  DEFHOOK
  default_promote_function_mode)
 
 DEFHOOK
+(promote_libcall_mode,
+ "",
+ enum machine_mode, (enum machine_mode mode, int *punsignedp,
+		     const_tree funtype, int for_return),
+ default_promote_libcall_mode)
+
+DEFHOOK
 (promote_prototypes,
  "",
  bool, (const_tree fntype),
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c.orig
+++ gcc/targhooks.c
@@ -139,6 +139,15 @@  default_promote_function_mode_always_pro
   return promote_mode (type, mode, punsignedp);
 }
 
+enum machine_mode
+default_promote_libcall_mode (enum machine_mode mode,
+			      int *punsignedp ATTRIBUTE_UNUSED,
+			      const_tree funtype ATTRIBUTE_UNUSED,
+			      int for_return ATTRIBUTE_UNUSED)
+{
+  return mode;
+}
+
 
 enum machine_mode
 default_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h.orig
+++ gcc/targhooks.h
@@ -28,6 +28,8 @@  extern enum machine_mode default_promote
 							int *, const_tree, int);
 extern enum machine_mode default_promote_function_mode_always_promote
 			(const_tree, enum machine_mode, int *, const_tree, int);
+extern enum machine_mode default_promote_libcall_mode (enum machine_mode,
+						       int *, const_tree, int);
 
 extern enum machine_mode default_cc_modes_compatible (enum machine_mode,
 						      enum machine_mode);
Index: gcc/config/s390/s390.c
===================================================================
--- gcc/config/s390/s390.c.orig
+++ gcc/config/s390/s390.c
@@ -8687,6 +8687,20 @@  s390_promote_function_mode (const_tree t
   return mode;
 }
 
+/* Libcall arguments and return values are promoted to word size.  */
+
+static enum machine_mode
+s390_promote_libcall_mode (enum machine_mode mode,
+			   int *punsignedp ATTRIBUTE_UNUSED,
+			   const_tree fntype ATTRIBUTE_UNUSED,
+			   int for_return ATTRIBUTE_UNUSED)
+{
+  if (GET_MODE_SIZE (mode) < UNITS_PER_LONG)
+    return Pmode;
+
+  return mode;
+}
+
 /* Define where to return a (scalar) value of type TYPE.
    If TYPE is null, define where to return a (scalar)
    value of mode MODE from a libcall.  */
@@ -10685,6 +10699,9 @@  s390_loop_unroll_adjust (unsigned nunrol
 
 #undef TARGET_PROMOTE_FUNCTION_MODE
 #define TARGET_PROMOTE_FUNCTION_MODE s390_promote_function_mode
+#undef TARGET_PROMOTE_LIBCALL_MODE
+#define TARGET_PROMOTE_LIBCALL_MODE s390_promote_libcall_mode
+
 #undef TARGET_PASS_BY_REFERENCE
 #define TARGET_PASS_BY_REFERENCE s390_pass_by_reference
 
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi.orig
+++ gcc/doc/tm.texi
@@ -978,6 +978,15 @@  also define the hook to @code{default_pr
 if you would like to apply the same rules given by @code{PROMOTE_MODE}.
 @end deftypefn
 
+@deftypefn {Target Hook} {enum machine_mode} TARGET_PROMOTE_LIBCALL_MODE (enum machine_mode @var{mode}, int *@var{punsignedp}, const_tree @var{funtype}, int @var{for_return})
+Like @code{TARGET_PROMOTE_FUNCTION_MODE}, but it is applied to libcall
+arguments only.  Define this if your target requires function
+arguments to be promoted to a larger mode and uses C compiled libcall
+routines (e.g. libdecnumber).
+
+The default is not promote arguments and return values.
+@end deftypefn
+
 @defmac PARM_BOUNDARY
 Normal alignment required for function parameters on the stack, in
 bits.  All stack parameters receive at least this much alignment