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 ARM]: Fix untyped calls on arm/Linux + elsewhere


This patch fixes a bunch of problems with untyped calls on arm, 
particularly on Linux (where we were generating an ICE).  It does the 
following

- Handles values larger than a word (ie returned in r0, r1, ...).
- Handles potential type-trapping conversions of floating point values (if 
a value is a trapping NaN and we use stfx/ldfx on it then we might get a 
conversion trap; by using sfm/lfm instructions we can guarantee to avoid 
this problem).
- Adds a framework for other floating-point marshalling rules in this area.

- Fixes the first of the above cases for Thumb as well.

Tested on arm/linux arm-elf and arm-netbsd.

2005-02-16  Richard Earnshaw  <rearnsha@arm.com>

	* PR target/19162
	* arm.c (arm_apply_result_size): New function.
	* arm.h (APPLY_RESULT_SIZE): Define.
	* arm-protos.h (arm_apply_result_size): Add prototype.
	* arm.md (RO_REGNUM, FPA_F0_REGNUM, FPA_F7_REGNUM): New constants.
	(movxf): New expand.
	(ldmsi_postinc4_thumb, stmsi_postinc4_thumb): New patterns for Thumb.
	(call_value_symbol): Remove predicate for operand 0.
	(call_value_insn, sibcall_value, sibcall_value_insn): Likewise.
	(untyped_call): Rework to correclty return values for any type.
	(untyped_return): New expand.
	* fpa.md (movxf_fpa): Simplify and use sfm/lfm when appropriate.


Index: config/arm/arm-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm-protos.h,v
retrieving revision 1.81
diff -p -p -r1.81 arm-protos.h
*** config/arm/arm-protos.h	1 Feb 2005 14:07:02 -0000	1.81
--- config/arm/arm-protos.h	16 Feb 2005 21:46:49 -0000
*************** extern void arm_init_cumulative_args (CU
*** 123,128 ****
--- 123,129 ----
  extern bool arm_needs_doubleword_align (enum machine_mode, tree);
  extern rtx arm_function_value(tree, tree);
  #endif
+ extern int arm_apply_result_size (void);
  
  #if defined AOF_ASSEMBLER
  extern rtx aof_pic_entry (rtx);
Index: config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.428
diff -p -p -r1.428 arm.c
*** config/arm/arm.c	1 Feb 2005 14:06:51 -0000	1.428
--- config/arm/arm.c	16 Feb 2005 21:46:52 -0000
*************** arm_canonicalize_comparison (enum rtx_co
*** 2283,2289 ****
  
  /* Define how to find the value returned by a function.  */
  
! rtx arm_function_value(tree type, tree func ATTRIBUTE_UNUSED)
  {
    enum machine_mode mode;
    int unsignedp ATTRIBUTE_UNUSED;
--- 2283,2290 ----
  
  /* Define how to find the value returned by a function.  */
  
! rtx
! arm_function_value(tree type, tree func ATTRIBUTE_UNUSED)
  {
    enum machine_mode mode;
    int unsignedp ATTRIBUTE_UNUSED;
*************** rtx arm_function_value(tree type, tree f
*** 2297,2302 ****
--- 2298,2325 ----
    return LIBCALL_VALUE(mode);
  }
  
+ /* Determine the amount of memory needed to store the possible return 
+    registers of an untyped call.  */
+ int
+ arm_apply_result_size (void)
+ {
+   int size = 16;
+ 
+   if (TARGET_ARM)
+     {
+       if (TARGET_HARD_FLOAT_ABI)
+ 	{
+ 	  if (TARGET_FPA)
+ 	    size += 12;
+ 	  if (TARGET_MAVERICK)
+ 	    size += 8;
+ 	}
+       if (TARGET_IWMMXT_ABI)
+ 	size += 8;
+     }
+ 
+   return size;
+ }
  
  /* Decide whether a type should be returned in memory (true)
     or in a register (false).  This is called by the macro
Index: config/arm/arm.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.266
diff -p -p -r1.266 arm.h
*** config/arm/arm.h	23 Jan 2005 15:05:38 -0000	1.266
--- config/arm/arm.h	16 Feb 2005 21:46:53 -0000
*************** enum reg_class
*** 1617,1622 ****
--- 1617,1626 ----
     || (TARGET_ARM && ((REGNO) == FIRST_FPA_REGNUM)			\
         && TARGET_HARD_FLOAT_ABI && TARGET_FPA))
  
+ /* Amount of memory needed for an untyped call to save all possible return
+    registers.  */
+ #define APPLY_RESULT_SIZE arm_apply_result_size()
+ 
  /* How large values are returned */
  /* A C expression which can inhibit the returning of certain function values
     in registers, based on the type of value.  */
Index: config/arm/arm.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.190
diff -p -p -r1.190 arm.md
*** config/arm/arm.md	20 Jan 2005 21:27:27 -0000	1.190
--- config/arm/arm.md	16 Feb 2005 21:46:55 -0000
***************
*** 30,41 ****
  
  ;; Register numbers
  (define_constants
!   [(IP_REGNUM	    12)		; Scratch register
     (SP_REGNUM	    13)		; Stack pointer
     (LR_REGNUM       14)		; Return address register
     (PC_REGNUM	    15)		; Program counter
     (CC_REGNUM       24)		; Condition code pseudo register
!    (LAST_ARM_REGNUM 15)
    ]
  )
  ;; 3rd operand to select_dominance_cc_mode
--- 30,44 ----
  
  ;; Register numbers
  (define_constants
!   [(R0_REGNUM        0)		; First CORE register
!    (IP_REGNUM	    12)		; Scratch register
     (SP_REGNUM	    13)		; Stack pointer
     (LR_REGNUM       14)		; Return address register
     (PC_REGNUM	    15)		; Program counter
     (CC_REGNUM       24)		; Condition code pseudo register
!    (LAST_ARM_REGNUM 15)		;
!    (FPA_F0_REGNUM   16)		; FIRST_FPA_REGNUM
!    (FPA_F7_REGNUM   23)		; LAST_FPA_REGNUM
    ]
  )
  ;; 3rd operand to select_dominance_cc_mode
***************
*** 5216,5221 ****
--- 5219,5234 ----
     (set_attr "pool_range" "*,*,*,1020,*,*")]
  )
  
+ (define_expand "movxf"
+   [(set (match_operand:XF 0 "general_operand" "")
+ 	(match_operand:XF 1 "general_operand" ""))]
+   "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+   "
+   if (GET_CODE (operands[0]) == MEM)
+     operands[1] = force_reg (XFmode, operands[1]);
+   "
+ )
+ 
  ;; Vector Moves
  (define_expand "movv2si"
    [(set (match_operand:V2SI 0 "nonimmediate_operand" "")
***************
*** 5288,5293 ****
--- 5301,5324 ----
     (set_attr "predicable" "yes")]
  )
  
+ (define_insn "*ldmsi_postinc4_thumb"
+   [(match_parallel 0 "load_multiple_operation"
+     [(set (match_operand:SI 1 "s_register_operand" "=l")
+ 	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
+ 		   (const_int 16)))
+      (set (match_operand:SI 3 "arm_hard_register_operand" "")
+ 	  (mem:SI (match_dup 2)))
+      (set (match_operand:SI 4 "arm_hard_register_operand" "")
+ 	  (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+      (set (match_operand:SI 5 "arm_hard_register_operand" "")
+ 	  (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+      (set (match_operand:SI 6 "arm_hard_register_operand" "")
+ 	  (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
+   "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
+   "ldmia\\t%1!, {%3, %4, %5, %6}"
+   [(set_attr "type" "load4")]
+ )
+ 
  (define_insn "*ldmsi_postinc3"
    [(match_parallel 0 "load_multiple_operation"
      [(set (match_operand:SI 1 "s_register_operand" "=r")
***************
*** 5409,5414 ****
--- 5440,5463 ----
     (set_attr "type" "store4")]
  )
  
+ (define_insn "*stmsi_postinc4_thumb"
+   [(match_parallel 0 "store_multiple_operation"
+     [(set (match_operand:SI 1 "s_register_operand" "=l")
+ 	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
+ 		   (const_int 16)))
+      (set (mem:SI (match_dup 2))
+ 	  (match_operand:SI 3 "arm_hard_register_operand" ""))
+      (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
+ 	  (match_operand:SI 4 "arm_hard_register_operand" ""))
+      (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
+ 	  (match_operand:SI 5 "arm_hard_register_operand" ""))
+      (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
+ 	  (match_operand:SI 6 "arm_hard_register_operand" ""))])]
+   "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
+   "stmia\\t%1!, {%3, %4, %5, %6}"
+   [(set_attr "type" "store4")]
+ )
+ 
  (define_insn "*stmsi_postinc3"
    [(match_parallel 0 "store_multiple_operation"
      [(set (match_operand:SI 1 "s_register_operand" "=r")
***************
*** 7560,7566 ****
  )
  
  (define_insn "*call_value_symbol"
!   [(set (match_operand 0 "s_register_operand" "")
  	(call (mem:SI (match_operand:SI 1 "" ""))
  	(match_operand:SI 2 "" "")))
     (use (match_operand 3 "" ""))
--- 7609,7615 ----
  )
  
  (define_insn "*call_value_symbol"
!   [(set (match_operand 0 "" "")
  	(call (mem:SI (match_operand:SI 1 "" ""))
  	(match_operand:SI 2 "" "")))
     (use (match_operand 3 "" ""))
***************
*** 7589,7595 ****
  )
  
  (define_insn "*call_value_insn"
!   [(set (match_operand 0 "register_operand" "")
  	(call (mem:SI (match_operand 1 "" ""))
  	      (match_operand 2 "" "")))
     (use (match_operand 3 "" ""))
--- 7638,7644 ----
  )
  
  (define_insn "*call_value_insn"
!   [(set (match_operand 0 "" "")
  	(call (mem:SI (match_operand 1 "" ""))
  	      (match_operand 2 "" "")))
     (use (match_operand 3 "" ""))
***************
*** 7617,7623 ****
  )
  
  (define_expand "sibcall_value"
!   [(parallel [(set (match_operand 0 "register_operand" "")
  		   (call (match_operand 1 "memory_operand" "")
  			 (match_operand 2 "general_operand" "")))
  	      (return)
--- 7666,7672 ----
  )
  
  (define_expand "sibcall_value"
!   [(parallel [(set (match_operand 0 "" "")
  		   (call (match_operand 1 "memory_operand" "")
  			 (match_operand 2 "general_operand" "")))
  	      (return)
***************
*** 7643,7649 ****
  )
  
  (define_insn "*sibcall_value_insn"
!  [(set (match_operand 0 "s_register_operand" "")
         (call (mem:SI (match_operand:SI 1 "" "X"))
  	     (match_operand 2 "" "")))
    (return)
--- 7692,7698 ----
  )
  
  (define_insn "*sibcall_value_insn"
!  [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "" "X"))
  	     (match_operand 2 "" "")))
    (return)
***************
*** 7749,7766 ****
  		    (const_int 0))
  	      (match_operand 1 "" "")
  	      (match_operand 2 "" "")])]
!   "TARGET_ARM"
    "
    {
      int i;
  
!     emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
  
      for (i = 0; i < XVECLEN (operands[2], 0); i++)
        {
! 	rtx set = XVECEXP (operands[2], 0, i);
  
! 	emit_move_insn (SET_DEST (set), SET_SRC (set));
        }
  
      /* The optimizer does not know that the call sets the function value
--- 7798,7856 ----
  		    (const_int 0))
  	      (match_operand 1 "" "")
  	      (match_operand 2 "" "")])]
!   "TARGET_EITHER"
    "
    {
      int i;
+     rtx par = gen_rtx_PARALLEL (VOIDmode,
+ 				rtvec_alloc (XVECLEN (operands[2], 0)));
+     rtx addr = gen_reg_rtx (Pmode);
+     rtx mem;
+     int size = 0;
  
!     emit_move_insn (addr, XEXP (operands[1], 0));
!     mem = change_address (operands[1], BLKmode, addr);
  
      for (i = 0; i < XVECLEN (operands[2], 0); i++)
        {
! 	rtx src = SET_SRC (XVECEXP (operands[2], 0, i));
  
! 	/* Default code only uses r0 as a return value, but we could
! 	   be using anything up to 4 registers.  */
! 	if (REGNO (src) == R0_REGNUM)
! 	  src = gen_rtx_REG (TImode, R0_REGNUM);
! 
!         XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, src,
! 						 GEN_INT (size));
!         size += GET_MODE_SIZE (GET_MODE (src));
!       }
! 
!     emit_call_insn (GEN_CALL_VALUE (par, operands[0], const0_rtx, NULL,
! 				    const0_rtx));
! 
!     size = 0;
! 
!     for (i = 0; i < XVECLEN (par, 0); i++)
!       {
! 	HOST_WIDE_INT offset = 0;
! 	rtx reg = XEXP (XVECEXP (par, 0, i), 0);
! 
! 	if (size != 0)
! 	  emit_move_insn (addr, plus_constant (addr, size));
! 
! 	mem = change_address (mem, GET_MODE (reg), NULL);
! 	if (REGNO (reg) == R0_REGNUM)
! 	  {
! 	    /* On thumb we have to use a write-back instruction.  */
! 	    emit_insn (arm_gen_store_multiple (R0_REGNUM, 4, addr, TRUE,
! 			TARGET_THUMB ? TRUE : FALSE, mem, &offset));
! 	    size = TARGET_ARM ? 16 : 0;
! 	  }
! 	else
! 	  {
! 	    emit_move_insn (mem, reg);
! 	    size = GET_MODE_SIZE (GET_MODE (reg));
! 	  }
        }
  
      /* The optimizer does not know that the call sets the function value
***************
*** 7773,7778 ****
--- 7863,7917 ----
    }"
  )
  
+ (define_expand "untyped_return"
+   [(match_operand:BLK 0 "memory_operand" "")
+    (match_operand 1 "" "")]
+   "TARGET_EITHER"
+   "
+   {
+     int i;
+     rtx addr = gen_reg_rtx (Pmode);
+     rtx mem;
+     int size = 0;
+ 
+     emit_move_insn (addr, XEXP (operands[0], 0));
+     mem = change_address (operands[0], BLKmode, addr);
+ 
+     for (i = 0; i < XVECLEN (operands[1], 0); i++)
+       {
+ 	HOST_WIDE_INT offset = 0;
+ 	rtx reg = SET_DEST (XVECEXP (operands[1], 0, i));
+ 
+ 	if (size != 0)
+ 	  emit_move_insn (addr, plus_constant (addr, size));
+ 
+ 	mem = change_address (mem, GET_MODE (reg), NULL);
+ 	if (REGNO (reg) == R0_REGNUM)
+ 	  {
+ 	    /* On thumb we have to use a write-back instruction.  */
+ 	    emit_insn (arm_gen_load_multiple (R0_REGNUM, 4, addr, TRUE,
+ 			TARGET_THUMB ? TRUE : FALSE, mem, &offset));
+ 	    size = TARGET_ARM ? 16 : 0;
+ 	  }
+ 	else
+ 	  {
+ 	    emit_move_insn (reg, mem);
+ 	    size = GET_MODE_SIZE (GET_MODE (reg));
+ 	  }
+       }
+ 
+     /* Emit USE insns before the return.  */
+     for (i = 0; i < XVECLEN (operands[1], 0); i++)
+       emit_insn (gen_rtx_USE (VOIDmode,
+ 			      SET_DEST (XVECEXP (operands[1], 0, i))));
+ 
+     /* Construct the return.  */
+     expand_naked_return ();
+ 
+     DONE;
+   }"
+ )
+ 
  ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
  ;; all of memory.  This blocks insns from being moved across this point.
  
Index: config/arm/fpa.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/fpa.md,v
retrieving revision 1.4
diff -p -p -r1.4 fpa.md
*** config/arm/fpa.md	4 Feb 2004 19:15:23 -0000	1.4
--- config/arm/fpa.md	16 Feb 2005 21:46:55 -0000
***************
*** 581,613 ****
     (set_attr "neg_pool_range" "*,*,*,*,1008,*,*,1008,*,*,*")]
  )
  
! ;; Saving and restoring the floating point registers in the prologue should
! ;; be done in XFmode, even though we don't support that for anything else
! ;; (Well, strictly it's 'internal representation', but that's effectively
! ;; XFmode).
! 
  (define_insn "*movxf_fpa"
!   [(set (match_operand:XF 0 "nonimmediate_operand" "=f,f,f,m,f,r,r")
! 	(match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))]
!   "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA && reload_completed"
    "*
    switch (which_alternative)
      {
      default:
      case 0: return \"mvf%?e\\t%0, %1\";
!     case 1: return \"mnf%?e\\t%0, #%N1\";
!     case 2: return \"ldf%?e\\t%0, %1\";
!     case 3: return \"stf%?e\\t%1, %0\";
!     case 4: return output_mov_long_double_fpa_from_arm (operands);
!     case 5: return output_mov_long_double_arm_from_fpa (operands);
!     case 6: return output_mov_long_double_arm_from_arm (operands);
      }
    "
!   [(set_attr "length" "4,4,4,4,8,8,12")
     (set_attr "predicable" "yes")
!    (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*")
!    (set_attr "pool_range" "*,*,1024,*,*,*,*")
!    (set_attr "neg_pool_range" "*,*,1004,*,*,*,*")]
  )
  
  (define_insn "*cmpsf_fpa"
--- 581,611 ----
     (set_attr "neg_pool_range" "*,*,*,*,1008,*,*,1008,*,*,*")]
  )
  
! ;; We treat XFmode as meaning 'internal format'.  It's the right size and we
! ;; don't use it for anything else.  We only support moving between FPA
! ;; registers and moving an FPA register to/from memory.
  (define_insn "*movxf_fpa"
!   [(set (match_operand:XF 0 "nonimmediate_operand" "=f,f,m")
! 	(match_operand:XF 1 "general_operand" "f,m,f"))]
!   "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA
!    && (register_operand (operands[0], XFmode)
!        || register_operand (operands[1], XFmode))"
    "*
    switch (which_alternative)
      {
      default:
      case 0: return \"mvf%?e\\t%0, %1\";
!     case 1: if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
! 	      return \"ldf%?e\\t%0, %1\";
! 	    return \"lfm%?\\t%0, 1, %1\";
!     case 2: if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
! 	      return \"stf%?e\\t%1, %0\";
! 	    return \"sfm%?\\t%1, 1, %0\";
      }
    "
!   [(set_attr "length" "4,4,4")
     (set_attr "predicable" "yes")
!    (set_attr "type" "ffarith,f_load,f_store")]
  )
  
  (define_insn "*cmpsf_fpa"
***************
*** 749,752 ****
     (set_attr "type" "ffarith")
     (set_attr "conds" "use")]
  )
- 
--- 747,749 ----

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