Return slot optimization for stack protector strong

Stefan Schulze Frielinghaus stefansf@linux.ibm.com
Mon Jan 27 18:23:00 GMT 2020


Hi,

some function calls trigger the stack-protector-strong although such
calls are later on implemented via calls to internal functions.
Consider the following example:

    long double
    rintl_wrapper (long double x)
    {
      return rintl (x);
    }

On s390x a return value of type `long double` is passed via a return
slot.  Thus according to function `stack_protect_return_slot_p` a
function call like `rintl (x)` triggers the stack-protector-strong since
rintl is not an internal function.  However, in a later stage, during
`expand_call_stmt`, such a call is implemented via a call to an internal
function.  This means in the example, the call `rintl (x)` is expanded
into an assembler instruction with register operands only.  Thus this
late time decision renders the usage of the stack protector superfluous.

I am wondering if we can prevent this at least for calls to builtin
functions which are finally implemented via calls to internal functions.
The attached patch solves this for me. Any thoughts?

Successfully bootstrapped and regtested on s390x.

Cheers,
Stefan
-------------- next part --------------
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 9864e4344d2..452813efef1 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2003,6 +2003,20 @@ estimated_stack_frame_size (struct cgraph_node *node)
   return estimated_poly_value (size);
 }
 
+/* Return true, if CALL is a call to a BUILT_IN_NORMAL function which has no
+ * other effect than setting the lhs and which could be replaced on the current
+ * target by a call to an internal function. Otherwise, return false.  */
+
+static bool
+builtin_as_internal_p (gcall *call)
+{
+  tree decl = gimple_call_fndecl (call);
+  return (gimple_call_lhs (call)
+	  && !gimple_has_side_effects (call)
+	  && (optimize || (decl && called_as_built_in (decl)))
+	  && replacement_internal_fn (call) != IFN_LAST);
+}
+
 /* Check if the current function has calls that use a return slot.  */
 
 static bool
@@ -2018,7 +2032,8 @@ stack_protect_return_slot_p ()
 	/* This assumes that calls to internal-only functions never
 	   use a return slot.  */
 	if (is_gimple_call (stmt)
-	    && !gimple_call_internal_p (stmt)
+	    && !(gimple_call_internal_p (stmt)
+		 || builtin_as_internal_p (as_a <gcall *> (stmt)))
 	    && aggregate_value_p (TREE_TYPE (gimple_call_fntype (stmt)),
 				  gimple_call_fndecl (stmt)))
 	  return true;
@@ -2613,25 +2628,19 @@ expand_call_stmt (gcall *stmt)
       return;
     }
 
-  /* If this is a call to a built-in function and it has no effect other
-     than setting the lhs, try to implement it using an internal function
-     instead.  */
-  decl = gimple_call_fndecl (stmt);
-  if (gimple_call_lhs (stmt)
-      && !gimple_has_side_effects (stmt)
-      && (optimize || (decl && called_as_built_in (decl))))
+  /* If this is a call to a built-in function which could be implemented as a
+   * call to an internal function for the current target, then do so.  */
+  if (builtin_as_internal_p (stmt))
     {
       internal_fn ifn = replacement_internal_fn (stmt);
-      if (ifn != IFN_LAST)
-	{
-	  expand_internal_call (ifn, stmt);
-	  return;
-	}
+      expand_internal_call (ifn, stmt);
+      return;
     }
 
   exp = build_vl_exp (CALL_EXPR, gimple_call_num_args (stmt) + 3);
 
   CALL_EXPR_FN (exp) = gimple_call_fn (stmt);
+  decl = gimple_call_fndecl (stmt);
   builtin_p = decl && fndecl_built_in_p (decl);
 
   /* If this is not a builtin function, the function type through which the
diff --git a/gcc/testsuite/gcc.target/s390/ssp-builtin-return-slot.c b/gcc/testsuite/gcc.target/s390/ssp-builtin-return-slot.c
new file mode 100644
index 00000000000..a3c5eac7065
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/ssp-builtin-return-slot.c
@@ -0,0 +1,39 @@
+/* Check that we do not trigger the Stack Smashing Protector unnecessarily.
+ * Some built-ins as e.g. rintl make use of a return slot and are therefore
+ * subject to stack protection. However, some of those built-ins (including
+ * rintl) are finally implemented via internal functions which should not
+ * trigger the Stack Smashing Protector Strong.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=zEC12 -fstack-protector-strong" } */
+/* { dg-final { scan-assembler-not "brasl\t%r14,__stack_chk_fail" } } */
+
+long double ceill(long double x);
+long double copysignl(long double x, long double y);
+long double floorl(long double x);
+long double nearbyintl(long double x);
+long double rintl(long double x);
+long double roundl(long double x);
+long double truncl(long double x);
+
+#define UNARY(F) \
+  long double F ## _wrapper(long double x) \
+    { return F(x); } \
+  long double F ## _wrapper_builtin(long double x) \
+    { return __builtin_ ## F(x); }
+
+#define BINARY(F) \
+  long double F ## _wrapper(long double x, long double y) \
+    { return F(x, y); } \
+  long double F ## _wrapper_builtin(long double x, long double y) \
+    { return __builtin_ ## F(x, y); }
+
+UNARY(ceill)
+UNARY(floorl)
+UNARY(nearbyintl)
+UNARY(rintl)
+UNARY(roundl)
+UNARY(truncl)
+
+BINARY(copysignl)
+


More information about the Gcc-patches mailing list