This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH ARM]: Fix untyped calls on arm/Linux + elsewhere
- From: Richard Earnshaw <Richard dot Earnshaw at buzzard dot freeserve dot co dot uk>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Richard dot Earnshaw at buzzard dot freeserve dot co dot uk
- Date: Wed, 16 Feb 2005 22:08:27 +0000
- Subject: [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 ----