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] Fix argument passing/return of small structs in big-endianARM mode for AAPCS


Hi,

This is a patch from the csl-arm-branch. The original thread is here:

http://gcc.gnu.org/ml/gcc-patches/2005-01/msg01889.html

With the patch applied, small aggregates and small complex values should be passed and returned correctly from functions in big-endian AAPCS mode (i.e., with correct alignment/padding for register and memory values). This obviously constitutes an ABI change for big-endian EABI, though other ABIs should be unaffected.

Tested on arm-none-elf and arm-none-eabi, in little- and big-endian modes. Additional compat tests have been run between "before" and "after" compilers in big and little endian modes for both ABIs.

The following test cases are now pass in big-endian EABI mode:

gcc.c-torture/execute/strct-stdarg-1.c execution, -O0
gcc.c-torture/execute/strct-stdarg-1.c execution, -O1
gcc.c-torture/execute/strct-stdarg-1.c execution, -O2
gcc.c-torture/execute/strct-stdarg-1.c execution, -O3 -fomit-frame-pointer
gcc.c-torture/execute/strct-stdarg-1.c execution, -O3 -fomit-frame-pointer -funroll-all-loops -finline-functions
gcc.c-torture/execute/strct-stdarg-1.c execution, -O3 -fomit-frame-pointer -funroll-loops
gcc.c-torture/execute/strct-stdarg-1.c execution, -O3 -g
gcc.c-torture/execute/strct-stdarg-1.c execution, -Os
gcc.dg/compat/struct-by-value-11 c_compat_x_tst.o-c_compat_y_tst.o execute
gcc.dg/compat/struct-by-value-2 c_compat_x_tst.o-c_compat_y_tst.o execute
gcc.dg/compat/struct-by-value-4 c_compat_x_tst.o-c_compat_y_tst.o execute
gcc.dg/compat/struct-return-2 c_compat_x_tst.o-c_compat_y_tst.o execute


OK to apply on head?

Julian

ChangeLog:

  * config/arm/arm.c (arm_return_in_msb): New function.
  (arm_must_pass_in_stack): New function.
  (TARGET_RETURN_IN_MSB): Define target hook.
  (TARGET_MUST_PASS_IN_STACK): Define target hook.
  (arm_function_value): Pad small aggregate return.
  (arm_pad_arg_upward): New function.
  (arm_pad_reg_upward): New function.
  * config/arm/arm.h (PROMOTE_FUNCTION_MODE): Include complex values.
  (FUNCTION_ARG_PADDING): Define macro.
  (BLOCK_REG_PADDING): Define macro.
  (PAD_VARARGS_DOWN): Correct padding for AAPCS.
  * config/arm/arm-protos.h (arm_pad_arg_upward): Declare function.
  (arm_pad_reg_upward): Declare function.
Only in ../gcc-head/gcc/CVS: Entries.Log
diff -c -p -r ../gcc-head/gcc/gcc/config/arm/arm.c gcc/gcc/config/arm/arm.c
*** ../gcc-head/gcc/gcc/config/arm/arm.c	2005-04-21 17:20:57.000000000 +0100
--- gcc/gcc/config/arm/arm.c	2005-04-25 18:21:17.067145920 +0100
*************** static bool arm_pass_by_reference (CUMUL
*** 165,170 ****
--- 165,172 ----
  static bool arm_promote_prototypes (tree);
  static bool arm_default_short_enums (void);
  static bool arm_align_anon_bitfield (void);
+ static bool arm_return_in_msb (tree);
+ static bool arm_must_pass_in_stack (enum machine_mode, tree);
  
  static tree arm_cxx_guard_type (void);
  static bool arm_cxx_guard_mask_bit (void);
*************** static unsigned HOST_WIDE_INT arm_shift_
*** 315,320 ****
--- 317,328 ----
  #undef TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT
  #define TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT arm_cxx_class_data_always_comdat
  
+ #undef TARGET_RETURN_IN_MSB
+ #define TARGET_RETURN_IN_MSB arm_return_in_msb
+ 
+ #undef TARGET_MUST_PASS_IN_STACK
+ #define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  /* Obstack for minipool constant handling.  */
*************** arm_function_value(tree type, tree func 
*** 2298,2308 ****
    int unsignedp ATTRIBUTE_UNUSED;
    rtx r ATTRIBUTE_UNUSED;
  
- 
    mode = TYPE_MODE (type);
    /* Promote integer types.  */
    if (INTEGRAL_TYPE_P (type))
      PROMOTE_FUNCTION_MODE (mode, unsignedp, type);
    return LIBCALL_VALUE(mode);
  }
  
--- 2306,2328 ----
    int unsignedp ATTRIBUTE_UNUSED;
    rtx r ATTRIBUTE_UNUSED;
  
    mode = TYPE_MODE (type);
    /* Promote integer types.  */
    if (INTEGRAL_TYPE_P (type))
      PROMOTE_FUNCTION_MODE (mode, unsignedp, type);
+ 
+   /* Promotes small structs returned in a register to full-word size
+      for big-endian AAPCS.  */
+   if (arm_return_in_msb (type))
+     {
+       HOST_WIDE_INT size = int_size_in_bytes (type);
+       if (size % UNITS_PER_WORD != 0)
+ 	{
+ 	  size += UNITS_PER_WORD - size % UNITS_PER_WORD;
+ 	  mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+ 	}
+     }
+   
    return LIBCALL_VALUE(mode);
  }
  
*************** vfp_secondary_reload_class (enum machine
*** 4901,4906 ****
--- 4921,4937 ----
    return GENERAL_REGS;
  }
  
+ /* Values which must be returned in the most-significant end of the return
+    register.  */
+ 
+ static bool
+ arm_return_in_msb (tree valtype)
+ {
+   return (TARGET_AAPCS_BASED
+           && BYTES_BIG_ENDIAN
+           && (AGGREGATE_TYPE_P (valtype)
+               || TREE_CODE (valtype) == COMPLEX_TYPE));
+ }
  
  /* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
     Use by the Cirrus Maverick code which has to workaround
*************** arm_reload_out_hi (rtx *operands)
*** 6499,6504 ****
--- 6530,6588 ----
  			    gen_lowpart (QImode, scratch)));
      }
  }
+ 
+ /* Return true if a type must be passed in memory. For AAPCS, small aggregates
+    (padded to the size of a word) should be passed in a register.  */
+ 
+ static bool
+ arm_must_pass_in_stack (enum machine_mode mode, tree type)
+ {
+   if (TARGET_AAPCS_BASED)
+     return must_pass_in_stack_var_size (mode, type);
+   else
+     return must_pass_in_stack_var_size_or_pad (mode, type);
+ }
+ 
+ 
+ /* For use by FUNCTION_ARG_PADDING (MODE, TYPE).
+    Return true if an argument passed on the stack should be padded upwards,
+    i.e. if the least-significant byte has useful data.  */
+ 
+ bool
+ arm_pad_arg_upward (enum machine_mode mode, tree type)
+ {
+   if (!TARGET_AAPCS_BASED)
+     return DEFAULT_FUNCTION_ARG_PADDING(mode, type);
+ 
+   if (type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P (type))
+     return false;
+ 
+   return true;
+ }
+ 
+ 
+ /* Similarly, for use by BLOCK_REG_PADDING (MODE, TYPE, FIRST).
+    For non-AAPCS, return !BYTES_BIG_ENDIAN if the least significant
+    byte of the register has useful data, and return the opposite if the
+    most significant byte does.
+    For AAPCS, small aggregates and small complex types are always padded
+    upwards.  */
+ 
+ bool
+ arm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
+                     tree type, int first ATTRIBUTE_UNUSED)
+ {
+   if (TARGET_AAPCS_BASED
+       && BYTES_BIG_ENDIAN
+       && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
+       && int_size_in_bytes (type) <= 4)
+     return true;
+ 
+   /* Otherwise, use default padding.  */
+   return !BYTES_BIG_ENDIAN;
+ }
+ 
+ 
  
  /* Print a symbolic form of X to the debug file, F.  */
  static void
diff -c -p -r ../gcc-head/gcc/gcc/config/arm/arm.h gcc/gcc/config/arm/arm.h
*** ../gcc-head/gcc/gcc/config/arm/arm.h	2005-04-13 15:22:36.000000000 +0100
--- gcc/gcc/config/arm/arm.h	2005-04-21 20:43:34.000000000 +0100
*************** extern int arm_cpp_interwork;
*** 607,615 ****
      }
  
  #define PROMOTE_FUNCTION_MODE(MODE, UNSIGNEDP, TYPE)	\
!   if (GET_MODE_CLASS (MODE) == MODE_INT		\
!       && GET_MODE_SIZE (MODE) < 4)      	\
!     (MODE) = SImode;				\
  
  /* Define this if most significant bit is lowest numbered
     in instructions that operate on numbered bit-fields.  */
--- 607,616 ----
      }
  
  #define PROMOTE_FUNCTION_MODE(MODE, UNSIGNEDP, TYPE)	\
!   if ((GET_MODE_CLASS (MODE) == MODE_INT		\
!        || GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT)    \
!       && GET_MODE_SIZE (MODE) < 4)                      \
!     (MODE) = SImode;				        \
  
  /* Define this if most significant bit is lowest numbered
     in instructions that operate on numbered bit-fields.  */
*************** typedef struct
*** 1761,1766 ****
--- 1762,1778 ----
  #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
    arm_function_arg (&(CUM), (MODE), (TYPE), (NAMED))
  
+ #define FUNCTION_ARG_PADDING(MODE, TYPE) \
+   (arm_pad_arg_upward (MODE, TYPE) ? upward : downward)
+ 
+ #define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
+   (arm_pad_reg_upward (MODE, TYPE, FIRST) ? upward : downward)
+ 
+ /* For AAPCS, padding should never be below the argument. For other ABIs,
+  * mimic the default.  */
+ #define PAD_VARARGS_DOWN \
+   ((TARGET_AAPCS_BASED) ? 0 : BYTES_BIG_ENDIAN)
+ 
  /* Initialize a variable CUM of type CUMULATIVE_ARGS
     for a call to a function whose data type is FNTYPE.
     For a library call, FNTYPE is 0.
diff -c -p -r ../gcc-head/gcc/gcc/config/arm/arm-protos.h gcc/gcc/config/arm/arm-protos.h
*** ../gcc-head/gcc/gcc/config/arm/arm-protos.h	2005-04-13 15:22:34.000000000 +0100
--- gcc/gcc/config/arm/arm-protos.h	2005-04-21 20:52:10.000000000 +0100
*************** extern int arm_eliminable_register (rtx)
*** 121,126 ****
--- 121,128 ----
  #if defined TREE_CODE
  extern rtx arm_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
  extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
+ extern bool arm_pad_arg_upward (enum machine_mode, tree);
+ extern bool arm_pad_reg_upward (enum machine_mode, tree, int);
  extern bool arm_needs_doubleword_align (enum machine_mode, tree);
  extern rtx arm_function_value(tree, tree);
  #endif
Only in ../gcc-head/gcc/gcc/java: decl.c.orig

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