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]

fix for memcpy/memset bug



Here's the patch for the memcpy/memset bug I mentioned this morning.  

	* expr.c (emit_block_move): Properly handle case where one of the
	block move arguments has a queued increment or decrement.
	(clear_storage): Similarly.  Fix formatting goof.

Index: expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.144
diff -c -3 -p -r1.144 expr.c
*** expr.c	1999/05/17 07:21:14	1.144
--- expr.c	1999/06/29 07:35:33
*************** emit_block_move (x, y, size, align)
*** 1710,1715 ****
--- 1710,1746 ----
  	    }
  	}
  
+       /* X, Y, or SIZE may have been passed through protect_from_queue.
+ 
+ 	 It is unsafe to save the value generated by protect_from_queue
+ 	 and reuse it later.  Consider what happens if emit_queue is
+ 	 called before the return value from protect_from_queue is used.
+ 
+ 	 Expansion of the CALL_EXPR below will call emit_queue before
+ 	 we are finished emitting RTL for argument setup.  So if we are
+ 	 not careful we could get the wrong value for an argument.
+ 
+ 	 To avoid this problem we go ahead and emit code to copy X, Y &
+ 	 SIZE into new pseudos.  We can then place those new pseudos
+ 	 into an RTL_EXPR and use them later, even after a call to
+ 	 emit_queue. 
+ 
+ 	 Note this is not strictly needed for library calls since they
+ 	 do not call emit_queue before loading their arguments.  However,
+ 	 we may need to have library calls call emit_queue in the future
+ 	 since failing to do so could cause problems for targets which
+ 	 define SMALL_REGISTER_CLASSES and pass arguments in registers.  */
+       x = copy_to_mode_reg (Pmode, XEXP (x, 0));
+       y = copy_to_mode_reg (Pmode, XEXP (y, 0));
+ 
+ #ifdef TARGET_MEM_FUNCTIONS
+       size = copy_to_mode_reg (TYPE_MODE (sizetype), size);
+ #else
+       size = convert_to_mode (TYPE_MODE (integer_type_node), size,
+ 			      TREE_UNSIGNED (integer_type_node));
+       size = copy_to_reg (size);
+ #endif
+ 
  #ifdef TARGET_MEM_FUNCTIONS
        /* It is incorrect to use the libcall calling conventions to call
  	 memcpy in this context.
*************** emit_block_move (x, y, size, align)
*** 1748,1759 ****
  	 the last is a size_t byte count for the copy.  */
        arg_list
  	= build_tree_list (NULL_TREE,
! 			    make_tree (build_pointer_type (void_type_node),
! 				       XEXP (x, 0)));
        TREE_CHAIN (arg_list)
  	= build_tree_list (NULL_TREE,
! 			   make_tree (build_pointer_type (void_type_node),
! 				      XEXP (y, 0)));
        TREE_CHAIN (TREE_CHAIN (arg_list))
  	 = build_tree_list (NULL_TREE, make_tree (sizetype, size));
        TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
--- 1779,1788 ----
  	 the last is a size_t byte count for the copy.  */
        arg_list
  	= build_tree_list (NULL_TREE,
! 			   make_tree (build_pointer_type (void_type_node), x));
        TREE_CHAIN (arg_list)
  	= build_tree_list (NULL_TREE,
! 			   make_tree (build_pointer_type (void_type_node), y));
        TREE_CHAIN (TREE_CHAIN (arg_list))
  	 = build_tree_list (NULL_TREE, make_tree (sizetype, size));
        TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
*************** emit_block_move (x, y, size, align)
*** 1767,1774 ****
        retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
  #else
        emit_library_call (bcopy_libfunc, 0,
! 			 VOIDmode, 3, XEXP (y, 0), Pmode,
! 			 XEXP (x, 0), Pmode,
  			 convert_to_mode (TYPE_MODE (integer_type_node), size,
  					  TREE_UNSIGNED (integer_type_node)),
  			 TYPE_MODE (integer_type_node));
--- 1796,1802 ----
        retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
  #else
        emit_library_call (bcopy_libfunc, 0,
! 			 VOIDmode, 3, y, Pmode, x, Pmode
  			 convert_to_mode (TYPE_MODE (integer_type_node), size,
  					  TREE_UNSIGNED (integer_type_node)),
  			 TYPE_MODE (integer_type_node));
*************** clear_storage (object, size, align)
*** 2444,2512 ****
  		}
  	    }
  
  
  #ifdef TARGET_MEM_FUNCTIONS
!       /* 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. 
  
! 	 So instead of using a libcall sequence we build up a suitable
! 	 CALL_EXPR and expand the call in the normal fashion.  */
!       if (fn == NULL_TREE)
! 	{
! 	  tree fntype;
  
! 	  /* This was copied from except.c, I don't know if all this is
! 	     necessary in this context or not.  */
! 	  fn = get_identifier ("memset");
! 	  push_obstacks_nochange ();
! 	  end_temporary_allocation ();
! 	  fntype = build_pointer_type (void_type_node);
! 	  fntype = build_function_type (fntype, NULL_TREE);
! 	  fn = build_decl (FUNCTION_DECL, fn, fntype);
! 	  DECL_EXTERNAL (fn) = 1;
! 	  TREE_PUBLIC (fn) = 1;
! 	  DECL_ARTIFICIAL (fn) = 1;
! 	  make_decl_rtl (fn, NULL_PTR, 1);
! 	  assemble_external (fn);
! 	  pop_obstacks ();
! 	}
  
!       /* We need to make an argument list for the function call. 
  
! 	 memset has three arguments, the first is a void * addresses, the
! 	 second a integer with the initialization value, the last is a size_t
! 	 byte count for the copy.  */
!       arg_list
! 	= build_tree_list (NULL_TREE,
! 			    make_tree (build_pointer_type (void_type_node),
! 				       XEXP (object, 0)));
!       TREE_CHAIN (arg_list)
! 	= build_tree_list (NULL_TREE,
! 			   make_tree (integer_type_node, const0_rtx));
!       TREE_CHAIN (TREE_CHAIN (arg_list))
! 	 = build_tree_list (NULL_TREE, make_tree (sizetype, size));
!       TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
  
!       /* Now we have to build up the CALL_EXPR itself.  */
!       call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), 
fn);
!       call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
! 			 call_expr, arg_list, NULL_TREE);
!       TREE_SIDE_EFFECTS (call_expr) = 1;
  
!       retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
  #else
  	  emit_library_call (bzero_libfunc, 0,
! 			     VOIDmode, 2,
! 			     XEXP (object, 0), Pmode,	
! 			     convert_to_mode
! 			     (TYPE_MODE (integer_type_node), size,
! 			      TREE_UNSIGNED (integer_type_node)),
  			     TYPE_MODE (integer_type_node));
  #endif
  	}
--- 2472,2568 ----
  		}
  	    }
  
+ 	  /* OBJECT or SIZE may have been passed through protect_from_queue.
  
+ 	     It is unsafe to save the value generated by protect_from_queue
+ 	     and reuse it later.  Consider what happens if emit_queue is
+ 	     called before the return value from protect_from_queue is used.
+ 
+ 	     Expansion of the CALL_EXPR below will call emit_queue before
+ 	     we are finished emitting RTL for argument setup.  So if we are
+ 	     not careful we could get the wrong value for an argument.
+ 
+ 	     To avoid this problem we go ahead and emit code to copy OBJECT
+ 	     and SIZE into new pseudos.  We can then place those new pseudos
+ 	     into an RTL_EXPR and use them later, even after a call to
+ 	     emit_queue.
+ 
+ 	     Note this is not strictly needed for library calls since they
+ 	     do not call emit_queue before loading their arguments.  However,
+ 	     we may need to have library calls call emit_queue in the future
+ 	     since failing to do so could cause problems for targets which
+ 	     define SMALL_REGISTER_CLASSES and pass arguments in registers.  */
+ 	  object = copy_to_mode_reg (Pmode, XEXP (object, 0));
+ 
  #ifdef TARGET_MEM_FUNCTIONS
! 	  size = copy_to_mode_reg (TYPE_MODE (sizetype), size);
! #else
! 	  size = convert_to_mode (TYPE_MODE (integer_type_node), size,
! 				  TREE_UNSIGNED (integer_type_node));
! 	  size = copy_to_reg (size);
! #endif
  
  
! #ifdef TARGET_MEM_FUNCTIONS
! 	  /* 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. 
! 
! 	     So instead of using a libcall sequence we build up a suitable
! 	     CALL_EXPR and expand the call in the normal fashion.  */
! 	  if (fn == NULL_TREE)
! 	    {
! 	      tree fntype;
  
! 	      /* This was copied from except.c, I don't know if all this is
! 		 necessary in this context or not.  */
! 	      fn = get_identifier ("memset");
! 	      push_obstacks_nochange ();
! 	      end_temporary_allocation ();
! 	      fntype = build_pointer_type (void_type_node);
! 	      fntype = build_function_type (fntype, NULL_TREE);
! 	      fn = build_decl (FUNCTION_DECL, fn, fntype);
! 	      DECL_EXTERNAL (fn) = 1;
! 	      TREE_PUBLIC (fn) = 1;
! 	      DECL_ARTIFICIAL (fn) = 1;
! 	      make_decl_rtl (fn, NULL_PTR, 1);
! 	      assemble_external (fn);
! 	      pop_obstacks ();
! 	    }
  
! 	  /* We need to make an argument list for the function call. 
  
! 	     memset has three arguments, the first is a void * addresses, the
! 	     second a integer with the initialization value, the last is a
! 	     size_t byte count for the copy.  */
! 	  arg_list
! 	    = build_tree_list (NULL_TREE,
! 			       make_tree (build_pointer_type (void_type_node),
! 					  object));
! 	  TREE_CHAIN (arg_list)
! 	    = build_tree_list (NULL_TREE,
! 			        make_tree (integer_type_node, const0_rtx));
! 	  TREE_CHAIN (TREE_CHAIN (arg_list))
! 	    = build_tree_list (NULL_TREE, make_tree (sizetype, size));
! 	  TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
! 
! 	  /* Now we have to build up the CALL_EXPR itself.  */
! 	  call_expr = build1 (ADDR_EXPR,
! 			      build_pointer_type (TREE_TYPE (fn)), fn);
! 	  call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
! 			     call_expr, arg_list, NULL_TREE);
! 	  TREE_SIDE_EFFECTS (call_expr) = 1;
  
! 	  retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
  #else
  	  emit_library_call (bzero_libfunc, 0,
! 			     VOIDmode, 2, object, Pmode, size
  			     TYPE_MODE (integer_type_node));
  #endif
  	}
'


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