This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch,Fortran] PR 42958 - cleanup gfc_call_malloc


Dear all,

gfc_call_malloc is used to allocate memory for temporary variables. The
trunk version does first a simple overflow check: If the requested size,
e.g.  <array-size>*<sizeof(element)>, is negative (-> overflow) then an
error is printed. For systems with 64bit pointers it does not help and
for 32bit systems, it is also questionable (and not reliable). Thus,
this patch removes this check.

Additionally, this patch makes the malloc-success check optional,
depending on a the new -fcheck=mem check.

I think there is unnecessarily another condition:
  size1 = ubound-lbound
  size = size1 < 0 ? 0 : size
  malloc (MAX(1, size))
the check whether size is "< 0" is not needed. However, the conditional
is created at a different place (gfc_trans_create_temp_array) and as
that function returns "size", it requires some thinking about when one
can get rid of this conditional.

Build and regtested on x86-64-linux. OK for the trunk?

Tobias

PS: I have not done any performance tests; however, if
gfc_trans_create_temp_array is called in a deeply nested loop (e.g. when
the variable is used in a function all), there is some overhead involved
and as Richard puts it: "the introduced control-flow makes it very hard
to remove unnecessary temporaries in the middle-end later."
2010-02-19  Tobias Burnus  <burnus@net-b.de>

	PR fortran/42958
	* libgfortran.h: Add GFC_RTCHECK_MEM.
	* invoke.texi (-fcheck=): Document -fcheck=mem.
	* tranc.c (gfc_call_malloc): Remove negative-size run-time error
	and enable malloc-success check only with -fcheck=mem.
	* option.c (gfc_handle_runtime_check_option): Add -fcheck=mem.

Index: gcc/fortran/libgfortran.h
===================================================================
--- gcc/fortran/libgfortran.h	(Revision 156905)
+++ gcc/fortran/libgfortran.h	(Arbeitskopie)
@@ -48,9 +48,10 @@ along with GCC; see the file COPYING3.
 #define GFC_RTCHECK_RECURSION   (1<<2)
 #define GFC_RTCHECK_DO          (1<<3)
 #define GFC_RTCHECK_POINTER     (1<<4)
+#define GFC_RTCHECK_MEM         (1<<5)
 #define GFC_RTCHECK_ALL        (GFC_RTCHECK_BOUNDS | GFC_RTCHECK_ARRAY_TEMPS \
 				| GFC_RTCHECK_RECURSION | GFC_RTCHECK_DO \
-				| GFC_RTCHECK_POINTER)
+				| GFC_RTCHECK_POINTER | GFC_RTCHECK_MEM)
 
 
 /* Possible values for the CONVERT I/O specifier.  */
Index: gcc/fortran/invoke.texi
===================================================================
--- gcc/fortran/invoke.texi	(Revision 156905)
+++ gcc/fortran/invoke.texi	(Arbeitskopie)
@@ -166,7 +166,7 @@ and warnings}.
 @gccoptlist{-fno-automatic  -ff2c  -fno-underscoring @gol
 -fwhole-file -fsecond-underscore @gol
 -fbounds-check -fcheck-array-temporaries  -fmax-array-constructor =@var{n} @gol
--fcheck=@var{<all|array-temps|bounds|do|pointer|recursion>}
+-fcheck=@var{<all|array-temps|bounds|do|pointer|recursion|mem>}
 -fmax-stack-var-size=@var{n} @gol
 -fpack-derived  -frepack-arrays  -fshort-enums  -fexternal-blas @gol
 -fblas-matmul-limit=@var{n} -frecursive -finit-local-zero @gol
@@ -1216,6 +1216,7 @@ by use of the @option{-ff2c} option.
 @cindex array, bounds checking
 @cindex bounds checking
 @cindex pointer checking
+@cindex memory checking
 @cindex range checking
 @cindex subscript checking
 @cindex checking subscripts
@@ -1254,6 +1255,11 @@ checking substring references.
 Enable generation of run-time checks for invalid modification of loop
 iteration variables.
 
+@item @samp{mem}
+Enable generation of run-time checks for memory allocation.
+Note: This option does not affect explicit allocations using the
+@code{ALLOCATE} statement, which will be always checked.
+
 @item @samp{pointer}
 Enable generation of run-time checks for pointers and allocatables.
 
Index: gcc/fortran/trans.c
===================================================================
--- gcc/fortran/trans.c	(Revision 156905)
+++ gcc/fortran/trans.c	(Arbeitskopie)
@@ -497,13 +497,12 @@ gfc_trans_runtime_check (bool error, boo
 
 
 /* Call malloc to allocate size bytes of memory, with special conditions:
-      + if size < 0, generate a runtime error,
-      + if size == 0, return a malloced area of size 1,
+      + if size <= 0, return a malloced area of size 1,
       + if malloc returns NULL, issue a runtime error.  */
 tree
 gfc_call_malloc (stmtblock_t * block, tree type, tree size)
 {
-  tree tmp, msg, negative, malloc_result, null_result, res;
+  tree tmp, msg, malloc_result, null_result, res;
   stmtblock_t block2;
 
   size = gfc_evaluate_now (size, block);
@@ -514,18 +513,7 @@ gfc_call_malloc (stmtblock_t * block, tr
   /* Create a variable to hold the result.  */
   res = gfc_create_var (prvoid_type_node, NULL);
 
-  /* size < 0 ?  */
-  negative = fold_build2 (LT_EXPR, boolean_type_node, size,
-			  build_int_cst (size_type_node, 0));
-  msg = gfc_build_addr_expr (pchar_type_node, gfc_build_localized_cstring_const
-      ("Attempt to allocate a negative amount of memory."));
-  tmp = fold_build3 (COND_EXPR, void_type_node, negative,
-		     build_call_expr_loc (input_location,
-				      gfor_fndecl_runtime_error, 1, msg),
-		     build_empty_stmt (input_location));
-  gfc_add_expr_to_block (block, tmp);
-
-  /* Call malloc and check the result.  */
+  /* Call malloc.  */
   gfc_start_block (&block2);
 
   size = fold_build2 (MAX_EXPR, size_type_node, size,
@@ -535,15 +523,21 @@ gfc_call_malloc (stmtblock_t * block, tr
 		  fold_convert (prvoid_type_node,
 				build_call_expr_loc (input_location,
 				   built_in_decls[BUILT_IN_MALLOC], 1, size)));
-  null_result = fold_build2 (EQ_EXPR, boolean_type_node, res,
-			     build_int_cst (pvoid_type_node, 0));
-  msg = gfc_build_addr_expr (pchar_type_node, gfc_build_localized_cstring_const
-      ("Memory allocation failed"));
-  tmp = fold_build3 (COND_EXPR, void_type_node, null_result,
-		     build_call_expr_loc (input_location,
-				      gfor_fndecl_os_error, 1, msg),
-		     build_empty_stmt (input_location));
-  gfc_add_expr_to_block (&block2, tmp);
+
+  /* Optionally check whether malloc was successful.  */
+  if (gfc_option.rtcheck & GFC_RTCHECK_MEM)
+    {
+      null_result = fold_build2 (EQ_EXPR, boolean_type_node, res,
+				 build_int_cst (pvoid_type_node, 0));
+      msg = gfc_build_addr_expr (pchar_type_node,
+	      gfc_build_localized_cstring_const ("Memory allocation failed"));
+      tmp = fold_build3 (COND_EXPR, void_type_node, null_result,
+	      build_call_expr_loc (input_location,
+				   gfor_fndecl_os_error, 1, msg),
+				   build_empty_stmt (input_location));
+      gfc_add_expr_to_block (&block2, tmp);
+    }
+
   malloc_result = gfc_finish_block (&block2);
 
   gfc_add_expr_to_block (block, malloc_result);
@@ -553,6 +547,7 @@ gfc_call_malloc (stmtblock_t * block, tr
   return res;
 }
 
+
 /* Allocate memory, using an optional status argument.
  
    This function follows the following pseudo-code:
Index: gcc/fortran/options.c
===================================================================
--- gcc/fortran/options.c	(Revision 156905)
+++ gcc/fortran/options.c	(Arbeitskopie)
@@ -482,11 +482,12 @@ gfc_handle_runtime_check_option (const c
 {
   int result, pos = 0, n;
   static const char * const optname[] = { "all", "bounds", "array-temps",
-					  "recursion", "do", "pointer", NULL };
+					  "recursion", "do", "pointer",
+					  "mem", NULL };
   static const int optmask[] = { GFC_RTCHECK_ALL, GFC_RTCHECK_BOUNDS,
 				 GFC_RTCHECK_ARRAY_TEMPS,
 				 GFC_RTCHECK_RECURSION, GFC_RTCHECK_DO,
-				 GFC_RTCHECK_POINTER,
+				 GFC_RTCHECK_POINTER, GFC_RTCHECK_MEM,
 				 0 };
  
   while (*arg)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]