public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch] Tidy up RTL libfunc machinery
@ 2016-05-10 20:16 Eric Botcazou
  2016-05-11  9:47 ` Richard Biener
  0 siblings, 1 reply; 3+ messages in thread
From: Eric Botcazou @ 2016-05-10 20:16 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4466 bytes --]

Hi,

this patch is aimed at cleaning up the mess with the RTL libfunc machinery.

On the one hand you have comments like these in the RTL expander:

  /* It is incorrect to use the libcall calling conventions to call
     memcpy in this context.  This could be a user call to memcpy and
     the user may wish to examine the return value from memcpy.  For
     targets where libcalls and normal calls have different conventions
     for returning pointers, we could end up generating incorrect code.  */

  /* It is incorrect to use the libcall calling conventions to call
     memset in this context.  This could be a user call to memset and
     the user may wish to examine the return value from memset.  For
     targets where libcalls and normal calls have different conventions
     for returning pointers, we could end up generating incorrect code.  */

and on the other hand you have at the end of expand_builtin_memcmp:

  emit_library_call_value (memcmp_libfunc, result, LCT_PURE,
			   TYPE_MODE (integer_type_node), 3,
			   XEXP (arg1_rtx, 0), Pmode,
			   XEXP (arg2_rtx, 0), Pmode,
			   convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
					    TYPE_UNSIGNED (sizetype)),
			   TYPE_MODE (sizetype));

so the RTL expander is not allowed to call memcpy & memset libfuncs on its own 
but it is for __builtin_memcmp, which is rather inconsistent.

So the patch eliminates all the RTL libfuncs and replaces them by calls to the 
corresponding builtins, except for 3 of them:
  - synchronize_libfunc, which is used by the ARM and MIPS back-ends,
  - unwind_sjlj_register_libfunc, which is used by the SJLJ machinery,
  - unwind_sjlj_unregister_libfunc, likewise.

abort_libfunc and memcmp_libfunc are set by VMS to something else than the 
default but this looks like an optimization and can presumably be dropped.

Bootstrapped/regtested on x86-64/Linux and PowerPC/Linux, OK for mainline?


2016-05-10  Eric Botcazou  <ebotcazou@adacore.com>

	* builtins.c (expand_builtin_memcmp): Do not emit the call here.
	(expand_builtin_trap): Emit a regular call.
	(set_builtin_user_assembler_name): Remove obsolete cases.
	* dse.c (scan_insn): Adjust.
	* except.c: Include calls.h.
	(sjlj_emit_function_enter): If DONT_USE_BUILTIN_SETJMP is defined,
	emit a regular call to setjmp.
	* expr.c (emit_block_move_hints): Call emit_block_copy_via_libcall.
	(block_move_libcall_safe_for_call_parm): Use memcpy builtin.
	(emit_block_move_via_libcall): Delete.
	(block_move_fn): Delete.
	(init_block_move_fn): Likewise.
	(emit_block_move_libcall_fn): Likewise.
	(emit_block_op_via_libcall): New function.
	(set_storage_via_libcall): Tidy up and use memset builtin.
	(block_clear_fn): Delete.
	(init_block_clear_fn): Likewise.
	(clear_storage_libcall_fn): Likewise.
	(expand_assignment): Call emit_block_move_via_libcall.
	Do not include gt-expr.h.
	* expr.h (emit_block_op_via_libcall): Declare.
	(emit_block_copy_via_libcall): New inline function.
	(emit_block_move_via_libcall): Likewise.
	(emit_block_comp_via_libcall): Likewise.
	(block_clear_fn): Delete.
	(init_block_move_fn): Likewise.
	(init_block_clear_fn): Likewise.
	(emit_block_move_via_libcall): Likewise.
	(set_storage_via_libcall): Add default parameter value.
	* libfuncs.h (enum libfunc_index): Remove obsolete values.
	(abort_libfunc): Delete.
	(memcpy_libfunc): Likewise.
	(memmove_libfunc): Likewise.
	(memcmp_libfunc): Likewise.
	(memset_libfunc): Likewise.
	(setbits_libfunc): Likewise.
	(setjmp_libfunc): Likewise.
	(longjmp_libfunc): Likewise.
	(profile_function_entry_libfunc): Likewise.
	(profile_function_exit_libfunc): Likewise.
	(gcov_flush_libfunc): Likewise.
	* optabs-libfuncs.c (build_libfunc_function): Set DECL_ARTIFICIAL
	and DECL_VISIBILITY on the declaration.
	(init_optabs): Do not initialize obsolete libfuncs.
	* optabs.c (prepare_cmp_insn): Call emit_block_comp_via_libcall.
	* tree-core.h (ECF_RET1): Define.
	(ECF_TM_PURE): Adjust.
	(ECF_TM_BUILTIN): Likewise.
	* tree.c (set_call_expr_flags): Deal with ECF_RET1.
	(build_common_builtin_nodes): Initialize abort builtin.
	Add ECF_RET1 on memcpy, memmove and memset builtins.
	Pass final flags for alloca and alloca_with_align builtins.
	* config/alpha/alpha.c (alpha_init_libfuncs): Do not initialize
	obsolete builtins.
	* config/ia64/ia64.c (ia64_vms_init_libfuncs): Likewise.
	* config/i386/i386.c (ix86_expand_set_or_movmem): Adjust call to
	set_storage_via_libcall and call emit_block_copy_via_libcall.

-- 
Eric Botcazou

[-- Attachment #2: p.diff --]
[-- Type: text/x-patch, Size: 30006 bytes --]

Index: builtins.c
===================================================================
--- builtins.c	(revision 236072)
+++ builtins.c	(working copy)
@@ -3757,20 +3757,7 @@ expand_builtin_memcmp (tree exp, rtx tar
       return convert_to_mode (mode, result, 0);
     }
 
-  result = target;
-  if (! (result != 0
-	 && REG_P (result) && GET_MODE (result) == mode
-	 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
-    result = gen_reg_rtx (mode);
-
-  emit_library_call_value (memcmp_libfunc, result, LCT_PURE,
-			   TYPE_MODE (integer_type_node), 3,
-			   XEXP (arg1_rtx, 0), Pmode,
-			   XEXP (arg2_rtx, 0), Pmode,
-			   convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
-					    TYPE_UNSIGNED (sizetype)),
-			   TYPE_MODE (sizetype));
-  return result;
+  return NULL_RTX;
 }
 
 /* Expand expression EXP, which is a call to the strcmp builtin.  Return NULL_RTX
@@ -4455,7 +4442,12 @@ expand_builtin_trap (void)
 	add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
     }
   else
-    emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_ABORT);
+      tree call_expr = build_call_expr (fn, 0);
+      expand_call (call_expr, NULL_RTX, false);
+    }
+
   emit_barrier ();
 }
 
@@ -9888,42 +9880,19 @@ fold_call_stmt (gcall *stmt, bool ignore
 void
 set_builtin_user_assembler_name (tree decl, const char *asmspec)
 {
-  tree builtin;
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
 	      && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
 	      && asmspec != 0);
 
-  builtin = builtin_decl_explicit (DECL_FUNCTION_CODE (decl));
+  tree builtin = builtin_decl_explicit (DECL_FUNCTION_CODE (decl));
   set_user_assembler_name (builtin, asmspec);
-  switch (DECL_FUNCTION_CODE (decl))
+
+  if (DECL_FUNCTION_CODE (decl) == BUILT_IN_FFS
+      && INT_TYPE_SIZE < BITS_PER_WORD)
     {
-    case BUILT_IN_MEMCPY:
-      init_block_move_fn (asmspec);
-      memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec);
-      break;
-    case BUILT_IN_MEMSET:
-      init_block_clear_fn (asmspec);
-      memset_libfunc = set_user_assembler_libfunc ("memset", asmspec);
-      break;
-    case BUILT_IN_MEMMOVE:
-      memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec);
-      break;
-    case BUILT_IN_MEMCMP:
-      memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec);
-      break;
-    case BUILT_IN_ABORT:
-      abort_libfunc = set_user_assembler_libfunc ("abort", asmspec);
-      break;
-    case BUILT_IN_FFS:
-      if (INT_TYPE_SIZE < BITS_PER_WORD)
-	{
-	  set_user_assembler_libfunc ("ffs", asmspec);
-	  set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE,
-						       MODE_INT, 0), "ffs");
-	}
-      break;
-    default:
-      break;
+      set_user_assembler_libfunc ("ffs", asmspec);
+      set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE, MODE_INT, 0),
+			 "ffs");
     }
 }
 
Index: config/alpha/alpha.c
===================================================================
--- config/alpha/alpha.c	(revision 236072)
+++ config/alpha/alpha.c	(working copy)
@@ -9752,8 +9752,6 @@ alpha_init_libfuncs (void)
       set_optab_libfunc (smod_optab, DImode, "OTS$REM_L");
       set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI");
       set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL");
-      abort_libfunc = init_one_libfunc ("decc$abort");
-      memcmp_libfunc = init_one_libfunc ("decc$memcmp");
 #ifdef MEM_LIBFUNCS_INIT
       MEM_LIBFUNCS_INIT;
 #endif
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c	(revision 236072)
+++ config/i386/i386.c	(working copy)
@@ -26910,9 +26910,9 @@ ix86_expand_set_or_movmem (rtx dst, rtx
 				   1, hot_label);
 	  predict_jump (REG_BR_PROB_BASE * 90 / 100);
 	  if (issetmem)
-	    set_storage_via_libcall (dst, count_exp, val_exp, false);
+	    set_storage_via_libcall (dst, count_exp, val_exp);
 	  else
-	    emit_block_move_via_libcall (dst, src, count_exp, false);
+	    emit_block_copy_via_libcall (dst, src, count_exp);
 	  emit_jump (jump_around_label);
 	  emit_label (hot_label);
 	}
Index: config/ia64/ia64.c
===================================================================
--- config/ia64/ia64.c	(revision 236072)
+++ config/ia64/ia64.c	(working copy)
@@ -10624,8 +10624,6 @@ ia64_vms_init_libfuncs (void)
   set_optab_libfunc (smod_optab, DImode, "OTS$REM_L");
   set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI");
   set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL");
-  abort_libfunc = init_one_libfunc ("decc$abort");
-  memcmp_libfunc = init_one_libfunc ("decc$memcmp");
 #ifdef MEM_LIBFUNCS_INIT
   MEM_LIBFUNCS_INIT;
 #endif
Index: dse.c
===================================================================
--- dse.c	(revision 236072)
+++ dse.c	(working copy)
@@ -2269,6 +2269,7 @@ scan_insn (bb_info_t bb_info, rtx_insn *
   if (CALL_P (insn))
     {
       bool const_call;
+      rtx call, sym;
       tree memset_call = NULL_TREE;
 
       insn_info->cannot_delete = true;
@@ -2278,24 +2279,16 @@ scan_insn (bb_info_t bb_info, rtx_insn *
 	 been pushed onto the stack.
 	 memset and bzero don't read memory either.  */
       const_call = RTL_CONST_CALL_P (insn);
-      if (!const_call)
-	{
-	  rtx call = get_call_rtx_from (insn);
-	  if (call && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
-	    {
-	      rtx symbol = XEXP (XEXP (call, 0), 0);
-	      if (SYMBOL_REF_DECL (symbol)
-		  && TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL)
-		{
-		  if ((DECL_BUILT_IN_CLASS (SYMBOL_REF_DECL (symbol))
-		       == BUILT_IN_NORMAL
-		       && (DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol))
-			   == BUILT_IN_MEMSET))
-		      || SYMBOL_REF_DECL (symbol) == block_clear_fn)
-		    memset_call = SYMBOL_REF_DECL (symbol);
-		}
-	    }
-	}
+      if (!const_call
+	  && (call = get_call_rtx_from (insn))
+	  && (sym = XEXP (XEXP (call, 0), 0))
+	  && GET_CODE (sym) == SYMBOL_REF
+	  && SYMBOL_REF_DECL (sym)
+	  && TREE_CODE (SYMBOL_REF_DECL (sym)) == FUNCTION_DECL
+	  && DECL_BUILT_IN_CLASS (SYMBOL_REF_DECL (sym)) == BUILT_IN_NORMAL
+	  && DECL_FUNCTION_CODE (SYMBOL_REF_DECL (sym)) == BUILT_IN_MEMSET)
+	memset_call = SYMBOL_REF_DECL (sym);
+
       if (const_call || memset_call)
 	{
 	  insn_info_t i_ptr = active_local_stores;
Index: except.c
===================================================================
--- except.c	(revision 236072)
+++ except.c	(working copy)
@@ -130,6 +130,7 @@ along with GCC; see the file COPYING3.
 #include "explow.h"
 #include "stmt.h"
 #include "expr.h"
+#include "calls.h"
 #include "libfuncs.h"
 #include "except.h"
 #include "output.h"
@@ -1173,20 +1174,22 @@ sjlj_emit_function_enter (rtx_code_label
 
   if (dispatch_label)
     {
+      rtx addr = plus_constant (Pmode, XEXP (fc, 0), sjlj_fc_jbuf_ofs);
+
 #ifdef DONT_USE_BUILTIN_SETJMP
-      rtx x;
-      x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE,
-				   TYPE_MODE (integer_type_node), 1,
-				   plus_constant (Pmode, XEXP (fc, 0),
-						  sjlj_fc_jbuf_ofs), Pmode);
+      addr = copy_addr_to_reg (addr);
+      addr = convert_memory_address (ptr_mode, addr);
+      tree addr_tree = make_tree (ptr_type_node, addr);
+
+      tree fn = builtin_decl_implicit (BUILT_IN_SETJMP);
+      tree call_expr = build_call_expr (fn, 1, addr_tree);
+      rtx x = expand_call (call_expr, NULL_RTX, false);
 
       emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
 			       TYPE_MODE (integer_type_node), 0,
 			       dispatch_label, REG_BR_PROB_BASE / 100);
 #else
-      expand_builtin_setjmp_setup (plus_constant (Pmode, XEXP (fc, 0),
-						  sjlj_fc_jbuf_ofs),
-				   dispatch_label);
+      expand_builtin_setjmp_setup (addr, dispatch_label);
 #endif
     }
 
Index: expr.c
===================================================================
--- expr.c	(revision 236072)
+++ expr.c	(working copy)
@@ -109,14 +109,12 @@ static bool block_move_libcall_safe_for_
 static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT,
 					unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
 					unsigned HOST_WIDE_INT);
-static tree emit_block_move_libcall_fn (int);
 static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
 static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, machine_mode);
 static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
 static void store_by_pieces_1 (struct store_by_pieces_d *, unsigned int);
 static void store_by_pieces_2 (insn_gen_fn, machine_mode,
 			       struct store_by_pieces_d *);
-static tree clear_storage_libcall_fn (int);
 static rtx_insn *compress_float_constant (rtx, rtx);
 static rtx get_subtarget (rtx);
 static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
@@ -1132,7 +1130,7 @@ emit_block_move_hints (rtx x, rtx y, rtx
 	mark_addressable (y_expr);
       if (x_expr)
 	mark_addressable (x_expr);
-      retval = emit_block_move_via_libcall (x, y, size,
+      retval = emit_block_copy_via_libcall (x, y, size,
 					    method == BLOCK_OP_TAILCALL);
     }
 
@@ -1175,7 +1173,7 @@ block_move_libcall_safe_for_call_parm (v
   /* If registers go on the stack anyway, any argument is sure to clobber
      an outgoing argument.  */
 #if defined (REG_PARM_STACK_SPACE)
-  fn = emit_block_move_libcall_fn (false);
+  fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
   /* Avoid set but not used warning if *REG_PARM_STACK_SPACE doesn't
      depend on its argument.  */
   (void) fn;
@@ -1191,7 +1189,7 @@ block_move_libcall_safe_for_call_parm (v
     cumulative_args_t args_so_far;
     tree fn, arg;
 
-    fn = emit_block_move_libcall_fn (false);
+    fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
     INIT_CUMULATIVE_ARGS (args_so_far_v, TREE_TYPE (fn), NULL_RTX, 0, 3);
     args_so_far = pack_cumulative_args (&args_so_far_v);
 
@@ -1310,106 +1308,6 @@ emit_block_move_via_movmem (rtx x, rtx y
   return false;
 }
 
-/* A subroutine of emit_block_move.  Expand a call to memcpy.
-   Return the return value from memcpy, 0 otherwise.  */
-
-rtx
-emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall)
-{
-  rtx dst_addr, src_addr;
-  tree call_expr, fn, src_tree, dst_tree, size_tree;
-  machine_mode size_mode;
-  rtx retval;
-
-  /* Emit code to copy the addresses of DST and SRC and SIZE into new
-     pseudos.  We can then place those new pseudos into a VAR_DECL and
-     use them later.  */
-
-  dst_addr = copy_addr_to_reg (XEXP (dst, 0));
-  src_addr = copy_addr_to_reg (XEXP (src, 0));
-
-  dst_addr = convert_memory_address (ptr_mode, dst_addr);
-  src_addr = convert_memory_address (ptr_mode, src_addr);
-
-  dst_tree = make_tree (ptr_type_node, dst_addr);
-  src_tree = make_tree (ptr_type_node, src_addr);
-
-  size_mode = TYPE_MODE (sizetype);
-
-  size = convert_to_mode (size_mode, size, 1);
-  size = copy_to_mode_reg (size_mode, size);
-
-  /* It is incorrect to use the libcall calling conventions to call
-     memcpy in this context.  This could be a user call to memcpy and
-     the user may wish to examine the return value from memcpy.  For
-     targets where libcalls and normal calls have different conventions
-     for returning pointers, we could end up generating incorrect code.  */
-
-  size_tree = make_tree (sizetype, size);
-
-  fn = emit_block_move_libcall_fn (true);
-  call_expr = build_call_expr (fn, 3, dst_tree, src_tree, size_tree);
-  CALL_EXPR_TAILCALL (call_expr) = tailcall;
-
-  retval = expand_normal (call_expr);
-
-  return retval;
-}
-
-/* A subroutine of emit_block_move_via_libcall.  Create the tree node
-   for the function we use for block copies.  */
-
-static GTY(()) tree block_move_fn;
-
-void
-init_block_move_fn (const char *asmspec)
-{
-  if (!block_move_fn)
-    {
-      tree args, fn, attrs, attr_args;
-
-      fn = get_identifier ("memcpy");
-      args = build_function_type_list (ptr_type_node, ptr_type_node,
-				       const_ptr_type_node, sizetype,
-				       NULL_TREE);
-
-      fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args);
-      DECL_EXTERNAL (fn) = 1;
-      TREE_PUBLIC (fn) = 1;
-      DECL_ARTIFICIAL (fn) = 1;
-      TREE_NOTHROW (fn) = 1;
-      DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
-      DECL_VISIBILITY_SPECIFIED (fn) = 1;
-
-      attr_args = build_tree_list (NULL_TREE, build_string (1, "1"));
-      attrs = tree_cons (get_identifier ("fn spec"), attr_args, NULL);
-
-      decl_attributes (&fn, attrs, ATTR_FLAG_BUILT_IN);
-
-      block_move_fn = fn;
-    }
-
-  if (asmspec)
-    set_user_assembler_name (block_move_fn, asmspec);
-}
-
-static tree
-emit_block_move_libcall_fn (int for_call)
-{
-  static bool emitted_extern;
-
-  if (!block_move_fn)
-    init_block_move_fn (NULL);
-
-  if (for_call && !emitted_extern)
-    {
-      emitted_extern = true;
-      make_decl_rtl (block_move_fn);
-    }
-
-  return block_move_fn;
-}
-
 /* A subroutine of emit_block_move.  Copy the data via an explicit
    loop.  This is used only when libcalls are forbidden.  */
 /* ??? It'd be nice to copy in hunks larger than QImode.  */
@@ -1464,6 +1362,39 @@ emit_block_move_via_loop (rtx x, rtx y,
 			   true, top_label, REG_BR_PROB_BASE * 90 / 100);
 }
 \f
+/* Expand a call to memcpy or memmove or memcmp, and return the result.
+   TAILCALL is true if this is a tail call.  */
+
+rtx
+emit_block_op_via_libcall (enum built_in_function fncode, rtx dst, rtx src,
+			   rtx size, bool tailcall)
+{
+  rtx dst_addr, src_addr;
+  tree call_expr, dst_tree, src_tree, size_tree;
+  machine_mode size_mode;
+
+  dst_addr = copy_addr_to_reg (XEXP (dst, 0));
+  dst_addr = convert_memory_address (ptr_mode, dst_addr);
+  dst_tree = make_tree (ptr_type_node, dst_addr);
+
+  src_addr = copy_addr_to_reg (XEXP (src, 0));
+  src_addr = convert_memory_address (ptr_mode, src_addr);
+  src_tree = make_tree (ptr_type_node, src_addr);
+
+  size_mode = TYPE_MODE (sizetype);
+  size = convert_to_mode (size_mode, size, 1);
+  size = copy_to_mode_reg (size_mode, size);
+  size_tree = make_tree (sizetype, size);
+
+  /* It is incorrect to use the libcall calling conventions for calls to
+     memcpy/memmove/memcmp because they can be provided by the user.  */
+  tree fn = builtin_decl_implicit (fncode);
+  call_expr = build_call_expr (fn, 3, dst_tree, src_tree, size_tree);
+  CALL_EXPR_TAILCALL (call_expr) = tailcall;
+
+  return expand_call (call_expr, NULL_RTX, false);
+}
+\f
 /* Copy all or part of a value X into registers starting at REGNO.
    The number of registers to be filled is NREGS.  */
 
@@ -2784,85 +2715,26 @@ set_storage_via_libcall (rtx object, rtx
 {
   tree call_expr, fn, object_tree, size_tree, val_tree;
   machine_mode size_mode;
-  rtx retval;
-
-  /* Emit code to copy OBJECT and SIZE into new pseudos.  We can then
-     place those into new pseudos into a VAR_DECL and use them later.  */
 
   object = copy_addr_to_reg (XEXP (object, 0));
+  object_tree = make_tree (ptr_type_node, object);
+
+  if (!CONST_INT_P (val))
+    val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1);
+  val_tree = make_tree (integer_type_node, val);
 
   size_mode = TYPE_MODE (sizetype);
   size = convert_to_mode (size_mode, size, 1);
   size = copy_to_mode_reg (size_mode, size);
-
-  /* It is incorrect to use the libcall calling conventions to call
-     memset in this context.  This could be a user call to memset and
-     the user may wish to examine the return value from memset.  For
-     targets where libcalls and normal calls have different conventions
-     for returning pointers, we could end up generating incorrect code.  */
-
-  object_tree = make_tree (ptr_type_node, object);
-  if (!CONST_INT_P (val))
-    val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1);
   size_tree = make_tree (sizetype, size);
-  val_tree = make_tree (integer_type_node, val);
 
-  fn = clear_storage_libcall_fn (true);
+  /* It is incorrect to use the libcall calling conventions for calls to
+     memset because it can be provided by the user.  */
+  fn = builtin_decl_implicit (BUILT_IN_MEMSET);
   call_expr = build_call_expr (fn, 3, object_tree, val_tree, size_tree);
   CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
-  retval = expand_normal (call_expr);
-
-  return retval;
-}
-
-/* A subroutine of set_storage_via_libcall.  Create the tree node
-   for the function we use for block clears.  */
-
-tree block_clear_fn;
-
-void
-init_block_clear_fn (const char *asmspec)
-{
-  if (!block_clear_fn)
-    {
-      tree fn, args;
-
-      fn = get_identifier ("memset");
-      args = build_function_type_list (ptr_type_node, ptr_type_node,
-				       integer_type_node, sizetype,
-				       NULL_TREE);
-
-      fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args);
-      DECL_EXTERNAL (fn) = 1;
-      TREE_PUBLIC (fn) = 1;
-      DECL_ARTIFICIAL (fn) = 1;
-      TREE_NOTHROW (fn) = 1;
-      DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
-      DECL_VISIBILITY_SPECIFIED (fn) = 1;
-
-      block_clear_fn = fn;
-    }
-
-  if (asmspec)
-    set_user_assembler_name (block_clear_fn, asmspec);
-}
-
-static tree
-clear_storage_libcall_fn (int for_call)
-{
-  static bool emitted_extern;
-
-  if (!block_clear_fn)
-    init_block_clear_fn (NULL);
-
-  if (for_call && !emitted_extern)
-    {
-      emitted_extern = true;
-      make_decl_rtl (block_clear_fn);
-    }
-
-  return block_clear_fn;
+  return expand_call (call_expr, NULL_RTX, false);
 }
 \f
 /* Expand a setmem pattern; return true if successful.  */
@@ -5157,12 +5029,7 @@ expand_assignment (tree to, tree from, b
       size = expr_size (from);
       from_rtx = expand_normal (from);
 
-      emit_library_call (memmove_libfunc, LCT_NORMAL,
-			 VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
-			 XEXP (from_rtx, 0), Pmode,
-			 convert_to_mode (TYPE_MODE (sizetype),
-					  size, TYPE_UNSIGNED (sizetype)),
-			 TYPE_MODE (sizetype));
+      emit_block_move_via_libcall (XEXP (to_rtx, 0), XEXP (from_rtx, 0), size);
 
       preserve_temp_slots (to_rtx);
       pop_temp_slots ();
@@ -11653,5 +11520,3 @@ int_expr_size (tree exp)
 
   return tree_to_shwi (size);
 }
-
-#include "gt-expr.h"
Index: expr.h
===================================================================
--- expr.h	(revision 236072)
+++ expr.h	(working copy)
@@ -71,8 +71,29 @@ extern rtx convert_to_mode (machine_mode
 /* Convert an rtx to MODE from OLDMODE and return the result.  */
 extern rtx convert_modes (machine_mode, machine_mode, rtx, int);
 
-/* Emit code to move a block Y to a block X.  */
+/* Expand a call to memcpy or memmove or memcmp, and return the result.  */
+extern rtx emit_block_op_via_libcall (enum built_in_function, rtx, rtx, rtx,
+				      bool);
+
+static inline rtx
+emit_block_copy_via_libcall (rtx dst, rtx src, rtx size, bool tailcall = false)
+{
+  return emit_block_op_via_libcall (BUILT_IN_MEMCPY, dst, src, size, tailcall);
+}
+
+static inline rtx
+emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall = false)
+{
+  return emit_block_op_via_libcall (BUILT_IN_MEMMOVE, dst, src, size, tailcall);
+}
+
+static inline rtx
+emit_block_comp_via_libcall (rtx dst, rtx src, rtx size, bool tailcall = false)
+{
+  return emit_block_op_via_libcall (BUILT_IN_MEMCMP, dst, src, size, tailcall);
+}
 
+/* Emit code to move a block Y to a block X.  */
 enum block_op_methods
 {
   BLOCK_OP_NORMAL,
@@ -82,12 +103,7 @@ enum block_op_methods
   BLOCK_OP_TAILCALL
 };
 
-extern GTY(()) tree block_clear_fn;
-extern void init_block_move_fn (const char *);
-extern void init_block_clear_fn (const char *);
-
 extern rtx emit_block_move (rtx, rtx, rtx, enum block_op_methods);
-extern rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool);
 extern rtx emit_block_move_hints (rtx, rtx, rtx, enum block_op_methods,
 			          unsigned int, HOST_WIDE_INT,
 				  unsigned HOST_WIDE_INT,
@@ -166,7 +182,7 @@ extern rtx clear_storage_hints (rtx, rtx
 				unsigned HOST_WIDE_INT,
 				unsigned HOST_WIDE_INT);
 /* The same, but always output an library call.  */
-rtx set_storage_via_libcall (rtx, rtx, rtx, bool);
+extern rtx set_storage_via_libcall (rtx, rtx, rtx, bool = false);
 
 /* Expand a setmem pattern; return true if successful.  */
 extern bool set_storage_via_setmem (rtx, rtx, rtx, unsigned int,
Index: libfuncs.h
===================================================================
--- libfuncs.h	(revision 236072)
+++ libfuncs.h	(working copy)
@@ -24,25 +24,9 @@ along with GCC; see the file COPYING3.
 /* Enumeration of indexes into libfunc_table.  */
 enum libfunc_index
 {
-  LTI_abort,
-  LTI_memcpy,
-  LTI_memmove,
-  LTI_memcmp,
-  LTI_memset,
-  LTI_setbits,
-
-  LTI_setjmp,
-  LTI_longjmp,
   LTI_unwind_sjlj_register,
   LTI_unwind_sjlj_unregister,
-
-  LTI_profile_function_entry,
-  LTI_profile_function_exit,
-
   LTI_synchronize,
-
-  LTI_gcov_flush,
-
   LTI_MAX
 };
 
@@ -89,26 +73,11 @@ extern struct target_libfuncs *this_targ
 
 /* Accessor macros for libfunc_table.  */
 
-#define abort_libfunc	(libfunc_table[LTI_abort])
-#define memcpy_libfunc	(libfunc_table[LTI_memcpy])
-#define memmove_libfunc	(libfunc_table[LTI_memmove])
-#define memcmp_libfunc	(libfunc_table[LTI_memcmp])
-#define memset_libfunc	(libfunc_table[LTI_memset])
-#define setbits_libfunc	(libfunc_table[LTI_setbits])
-
-#define setjmp_libfunc	(libfunc_table[LTI_setjmp])
-#define longjmp_libfunc	(libfunc_table[LTI_longjmp])
 #define unwind_sjlj_register_libfunc (libfunc_table[LTI_unwind_sjlj_register])
 #define unwind_sjlj_unregister_libfunc \
   (libfunc_table[LTI_unwind_sjlj_unregister])
-
-#define profile_function_entry_libfunc	(libfunc_table[LTI_profile_function_entry])
-#define profile_function_exit_libfunc	(libfunc_table[LTI_profile_function_exit])
-
 #define synchronize_libfunc	(libfunc_table[LTI_synchronize])
 
-#define gcov_flush_libfunc	(libfunc_table[LTI_gcov_flush])
-
 /* In explow.c */
 extern void set_stack_check_libfunc (const char *);
 
Index: optabs-libfuncs.c
===================================================================
--- optabs-libfuncs.c	(revision 236072)
+++ optabs-libfuncs.c	(working copy)
@@ -731,14 +731,15 @@ static GTY (()) hash_table<libfunc_decl_
 tree
 build_libfunc_function (const char *name)
 {
+  /* ??? We don't have any type information; pretend this is "int foo ()".  */
   tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
 			  get_identifier (name),
 			  build_function_type (integer_type_node, NULL_TREE));
-  /* ??? We don't have any type information except for this is
-     a function.  Pretend this is "int foo ()".  */
-  DECL_ARTIFICIAL (decl) = 1;
   DECL_EXTERNAL (decl) = 1;
   TREE_PUBLIC (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+  DECL_VISIBILITY_SPECIFIED (decl) = 1;
   gcc_assert (DECL_ASSEMBLER_NAME (decl));
 
   /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
@@ -887,32 +888,10 @@ init_optabs (void)
     set_optab_libfunc (abs_optab, TYPE_MODE (complex_double_type_node),
 		       "cabs");
 
-  abort_libfunc = init_one_libfunc ("abort");
-  memcpy_libfunc = init_one_libfunc ("memcpy");
-  memmove_libfunc = init_one_libfunc ("memmove");
-  memcmp_libfunc = init_one_libfunc ("memcmp");
-  memset_libfunc = init_one_libfunc ("memset");
-  setbits_libfunc = init_one_libfunc ("__setbits");
-
-#ifndef DONT_USE_BUILTIN_SETJMP
-  setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
-  longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
-#else
-  setjmp_libfunc = init_one_libfunc ("setjmp");
-  longjmp_libfunc = init_one_libfunc ("longjmp");
-#endif
   unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
   unwind_sjlj_unregister_libfunc
     = init_one_libfunc ("_Unwind_SjLj_Unregister");
 
-  /* For function entry/exit instrumentation.  */
-  profile_function_entry_libfunc
-    = init_one_libfunc ("__cyg_profile_func_enter");
-  profile_function_exit_libfunc
-    = init_one_libfunc ("__cyg_profile_func_exit");
-
-  gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
-
   /* Allow the target to add more libcalls or rename some, etc.  */
   targetm.init_libfuncs ();
 }
Index: optabs.c
===================================================================
--- optabs.c	(revision 236072)
+++ optabs.c	(working copy)
@@ -3776,8 +3776,6 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx
     {
       machine_mode result_mode;
       enum insn_code cmp_code;
-      tree length_type;
-      rtx libfunc;
       rtx result;
       rtx opalign
 	= GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
@@ -3818,22 +3816,12 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx
       if (methods != OPTAB_LIB && methods != OPTAB_LIB_WIDEN)
 	goto fail;
 
-      /* Otherwise call a library function, memcmp.  */
-      libfunc = memcmp_libfunc;
-      length_type = sizetype;
-      result_mode = TYPE_MODE (integer_type_node);
-      cmp_mode = TYPE_MODE (length_type);
-      size = convert_to_mode (TYPE_MODE (length_type), size,
-			      TYPE_UNSIGNED (length_type));
-
-      result = emit_library_call_value (libfunc, 0, LCT_PURE,
-					result_mode, 3,
-					XEXP (x, 0), Pmode,
-					XEXP (y, 0), Pmode,
-					size, cmp_mode);
+      /* Otherwise call a library function.  */
+      result = emit_block_comp_via_libcall (XEXP (x, 0), XEXP (y, 0), size);
+
       x = result;
       y = const0_rtx;
-      mode = result_mode;
+      mode = TYPE_MODE (integer_type_node);
       methods = OPTAB_LIB_WIDEN;
       unsignedp = false;
     }
Index: tree-core.h
===================================================================
--- tree-core.h	(revision 236072)
+++ tree-core.h	(working copy)
@@ -81,11 +81,14 @@ struct die_struct;
 /* The function does not lead to calls within current function unit.  */
 #define ECF_LEAF		  (1 << 10)
 
+/* Nonzero if this call returns its first argument.  */
+#define ECF_RET1		  (1 << 11)
+
 /* Nonzero if this call does not affect transactions.  */
-#define ECF_TM_PURE		  (1 << 11)
+#define ECF_TM_PURE		  (1 << 12)
 
 /* Nonzero if this call is into the transaction runtime library.  */
-#define ECF_TM_BUILTIN		  (1 << 12)
+#define ECF_TM_BUILTIN		  (1 << 13)
 
 /* Call argument flags.  */
 /* Nonzero if the argument is not dereferenced recursively, thus only
Index: tree.c
===================================================================
--- tree.c	(revision 236072)
+++ tree.c	(working copy)
@@ -10451,6 +10451,11 @@ set_call_expr_flags (tree decl, int flag
   if (flags & ECF_LEAF)
     DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("leaf"),
 					NULL, DECL_ATTRIBUTES (decl));
+  if (flags & ECF_RET1)
+    DECL_ATTRIBUTES (decl)
+      = tree_cons (get_identifier ("fn spec"),
+		   build_tree_list (NULL_TREE, build_string (1, "1")),
+		   DECL_ATTRIBUTES (decl));
   if ((flags & ECF_TM_PURE) && flag_tm)
     apply_tm_attr (decl, get_identifier ("transaction_pure"));
   /* Looping const or pure is implied by noreturn.
@@ -10486,13 +10491,20 @@ build_common_builtin_nodes (void)
   tree tmp, ftype;
   int ecf_flags;
 
-  if (!builtin_decl_explicit_p (BUILT_IN_UNREACHABLE))
+  if (!builtin_decl_explicit_p (BUILT_IN_UNREACHABLE)
+      || !builtin_decl_explicit_p (BUILT_IN_ABORT))
     {
       ftype = build_function_type (void_type_node, void_list_node);
-      local_define_builtin ("__builtin_unreachable", ftype, BUILT_IN_UNREACHABLE,
-			    "__builtin_unreachable",
-			    ECF_NOTHROW | ECF_LEAF | ECF_NORETURN
-			    | ECF_CONST);
+      if (!builtin_decl_explicit_p (BUILT_IN_UNREACHABLE))
+	local_define_builtin ("__builtin_unreachable", ftype,
+			      BUILT_IN_UNREACHABLE,
+			      "__builtin_unreachable",
+			      ECF_NOTHROW | ECF_LEAF | ECF_NORETURN
+			      | ECF_CONST);
+      if (!builtin_decl_explicit_p (BUILT_IN_ABORT))
+	local_define_builtin ("__builtin_abort", ftype, BUILT_IN_ABORT,
+			      "abort",
+			      ECF_LEAF | ECF_NORETURN | ECF_CONST);
     }
 
   if (!builtin_decl_explicit_p (BUILT_IN_MEMCPY)
@@ -10504,10 +10516,10 @@ build_common_builtin_nodes (void)
 
       if (!builtin_decl_explicit_p (BUILT_IN_MEMCPY))
 	local_define_builtin ("__builtin_memcpy", ftype, BUILT_IN_MEMCPY,
-			      "memcpy", ECF_NOTHROW | ECF_LEAF);
+			      "memcpy", ECF_NOTHROW | ECF_LEAF | ECF_RET1);
       if (!builtin_decl_explicit_p (BUILT_IN_MEMMOVE))
 	local_define_builtin ("__builtin_memmove", ftype, BUILT_IN_MEMMOVE,
-			      "memmove", ECF_NOTHROW | ECF_LEAF);
+			      "memmove", ECF_NOTHROW | ECF_LEAF | ECF_RET1);
     }
 
   if (!builtin_decl_explicit_p (BUILT_IN_MEMCMP))
@@ -10525,15 +10537,19 @@ build_common_builtin_nodes (void)
 					ptr_type_node, integer_type_node,
 					size_type_node, NULL_TREE);
       local_define_builtin ("__builtin_memset", ftype, BUILT_IN_MEMSET,
-			    "memset", ECF_NOTHROW | ECF_LEAF);
+			    "memset", ECF_NOTHROW | ECF_LEAF | ECF_RET1);
     }
 
+  /* If we're checking the stack, `alloca' can throw.  */
+  const int alloca_flags
+    = ECF_MALLOC | ECF_LEAF | (flag_stack_check ? 0 : ECF_NOTHROW);
+
   if (!builtin_decl_explicit_p (BUILT_IN_ALLOCA))
     {
       ftype = build_function_type_list (ptr_type_node,
 					size_type_node, NULL_TREE);
       local_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA,
-			    "alloca", ECF_MALLOC | ECF_NOTHROW | ECF_LEAF);
+			    "alloca", alloca_flags);
     }
 
   ftype = build_function_type_list (ptr_type_node, size_type_node,
@@ -10541,14 +10557,7 @@ build_common_builtin_nodes (void)
   local_define_builtin ("__builtin_alloca_with_align", ftype,
 			BUILT_IN_ALLOCA_WITH_ALIGN,
 			"__builtin_alloca_with_align",
-			ECF_MALLOC | ECF_NOTHROW | ECF_LEAF);
-
-  /* If we're checking the stack, `alloca' can throw.  */
-  if (flag_stack_check)
-    {
-      TREE_NOTHROW (builtin_decl_explicit (BUILT_IN_ALLOCA)) = 0;
-      TREE_NOTHROW (builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN)) = 0;
-    }
+			alloca_flags);
 
   ftype = build_function_type_list (void_type_node,
 				    ptr_type_node, ptr_type_node,

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [patch] Tidy up RTL libfunc machinery
  2016-05-10 20:16 [patch] Tidy up RTL libfunc machinery Eric Botcazou
@ 2016-05-11  9:47 ` Richard Biener
  2016-05-13  8:49   ` Eric Botcazou
  0 siblings, 1 reply; 3+ messages in thread
From: Richard Biener @ 2016-05-11  9:47 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: GCC Patches

On Tue, May 10, 2016 at 10:12 PM, Eric Botcazou <ebotcazou@adacore.com> wrote:
> Hi,
>
> this patch is aimed at cleaning up the mess with the RTL libfunc machinery.
>
> On the one hand you have comments like these in the RTL expander:
>
>   /* It is incorrect to use the libcall calling conventions to call
>      memcpy in this context.  This could be a user call to memcpy and
>      the user may wish to examine the return value from memcpy.  For
>      targets where libcalls and normal calls have different conventions
>      for returning pointers, we could end up generating incorrect code.  */
>
>   /* It is incorrect to use the libcall calling conventions to call
>      memset in this context.  This could be a user call to memset and
>      the user may wish to examine the return value from memset.  For
>      targets where libcalls and normal calls have different conventions
>      for returning pointers, we could end up generating incorrect code.  */
>
> and on the other hand you have at the end of expand_builtin_memcmp:
>
>   emit_library_call_value (memcmp_libfunc, result, LCT_PURE,
>                            TYPE_MODE (integer_type_node), 3,
>                            XEXP (arg1_rtx, 0), Pmode,
>                            XEXP (arg2_rtx, 0), Pmode,
>                            convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
>                                             TYPE_UNSIGNED (sizetype)),
>                            TYPE_MODE (sizetype));
>
> so the RTL expander is not allowed to call memcpy & memset libfuncs on its own
> but it is for __builtin_memcmp, which is rather inconsistent.
>
> So the patch eliminates all the RTL libfuncs and replaces them by calls to the
> corresponding builtins, except for 3 of them:
>   - synchronize_libfunc, which is used by the ARM and MIPS back-ends,
>   - unwind_sjlj_register_libfunc, which is used by the SJLJ machinery,
>   - unwind_sjlj_unregister_libfunc, likewise.
>
> abort_libfunc and memcmp_libfunc are set by VMS to something else than the
> default but this looks like an optimization and can presumably be dropped.
>
> Bootstrapped/regtested on x86-64/Linux and PowerPC/Linux, OK for mainline?

The middle-end parts are ok, I'm leaving backend parts for their
maintainers to comment
but those parts are ok as well if they do not comment within a
reasonable amount of time.

Did you check the internals manual if it needs adjustment?

Thanks,
Richard.

>
> 2016-05-10  Eric Botcazou  <ebotcazou@adacore.com>
>
>         * builtins.c (expand_builtin_memcmp): Do not emit the call here.
>         (expand_builtin_trap): Emit a regular call.
>         (set_builtin_user_assembler_name): Remove obsolete cases.
>         * dse.c (scan_insn): Adjust.
>         * except.c: Include calls.h.
>         (sjlj_emit_function_enter): If DONT_USE_BUILTIN_SETJMP is defined,
>         emit a regular call to setjmp.
>         * expr.c (emit_block_move_hints): Call emit_block_copy_via_libcall.
>         (block_move_libcall_safe_for_call_parm): Use memcpy builtin.
>         (emit_block_move_via_libcall): Delete.
>         (block_move_fn): Delete.
>         (init_block_move_fn): Likewise.
>         (emit_block_move_libcall_fn): Likewise.
>         (emit_block_op_via_libcall): New function.
>         (set_storage_via_libcall): Tidy up and use memset builtin.
>         (block_clear_fn): Delete.
>         (init_block_clear_fn): Likewise.
>         (clear_storage_libcall_fn): Likewise.
>         (expand_assignment): Call emit_block_move_via_libcall.
>         Do not include gt-expr.h.
>         * expr.h (emit_block_op_via_libcall): Declare.
>         (emit_block_copy_via_libcall): New inline function.
>         (emit_block_move_via_libcall): Likewise.
>         (emit_block_comp_via_libcall): Likewise.
>         (block_clear_fn): Delete.
>         (init_block_move_fn): Likewise.
>         (init_block_clear_fn): Likewise.
>         (emit_block_move_via_libcall): Likewise.
>         (set_storage_via_libcall): Add default parameter value.
>         * libfuncs.h (enum libfunc_index): Remove obsolete values.
>         (abort_libfunc): Delete.
>         (memcpy_libfunc): Likewise.
>         (memmove_libfunc): Likewise.
>         (memcmp_libfunc): Likewise.
>         (memset_libfunc): Likewise.
>         (setbits_libfunc): Likewise.
>         (setjmp_libfunc): Likewise.
>         (longjmp_libfunc): Likewise.
>         (profile_function_entry_libfunc): Likewise.
>         (profile_function_exit_libfunc): Likewise.
>         (gcov_flush_libfunc): Likewise.
>         * optabs-libfuncs.c (build_libfunc_function): Set DECL_ARTIFICIAL
>         and DECL_VISIBILITY on the declaration.
>         (init_optabs): Do not initialize obsolete libfuncs.
>         * optabs.c (prepare_cmp_insn): Call emit_block_comp_via_libcall.
>         * tree-core.h (ECF_RET1): Define.
>         (ECF_TM_PURE): Adjust.
>         (ECF_TM_BUILTIN): Likewise.
>         * tree.c (set_call_expr_flags): Deal with ECF_RET1.
>         (build_common_builtin_nodes): Initialize abort builtin.
>         Add ECF_RET1 on memcpy, memmove and memset builtins.
>         Pass final flags for alloca and alloca_with_align builtins.
>         * config/alpha/alpha.c (alpha_init_libfuncs): Do not initialize
>         obsolete builtins.
>         * config/ia64/ia64.c (ia64_vms_init_libfuncs): Likewise.
>         * config/i386/i386.c (ix86_expand_set_or_movmem): Adjust call to
>         set_storage_via_libcall and call emit_block_copy_via_libcall.
>
> --
> Eric Botcazou

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [patch] Tidy up RTL libfunc machinery
  2016-05-11  9:47 ` Richard Biener
@ 2016-05-13  8:49   ` Eric Botcazou
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Botcazou @ 2016-05-13  8:49 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

> The middle-end parts are ok, I'm leaving backend parts for their
> maintainers to comment
> but those parts are ok as well if they do not comment within a
> reasonable amount of time.

Thanks, I have applied the patch.

> Did you check the internals manual if it needs adjustment?

The only related section I found is "17.12 Implicit Calls to Library Routines" 
but there is nothing to change as far as I can see.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-05-13  8:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-10 20:16 [patch] Tidy up RTL libfunc machinery Eric Botcazou
2016-05-11  9:47 ` Richard Biener
2016-05-13  8:49   ` Eric Botcazou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).