[PATCH] PR opt/6627: New target macro MINIMUM_FUNCTION_BOUNDARY

Roger Sayle roger@eyesopen.com
Sat Sep 28 21:01:00 GMT 2002


Rather than try to explain my proposal to fix high priority PR
optimization/6627, I thought a patch was worth a thousand words.

The problem is that on IA-32, although the processor allows functions
to start at any address, front-ends such as C++ and Java would prefer
to force the minimum function alignment to two bytes, so that they can
play clever tricks with the least significant bit of function pointers
in vtables.  This creates a conflict, as kernel developers writing in
C would like -Os to really mean no padding, but for C++ -Os should
provide atleast minimal alignment.

My proposed untangling of this Gordian knot is to observe that the
two requirements aren't really in conflict.  Rather than fight over
the single target macro FUNCTION_BOUNDARY, provide two macros (i)
MINIMUM_FUNCTION_BOUNDARY for the machine minimum function alignment
and (ii) FUNCTION_BOUNDARY for the "default" function alignment.
If the new MINIMUM_FUNCTION_BOUNDARY isn't defined by the backend,
it is assumed to be identical to FUNCTION_BOUNDARY.

Without specifying any command line options, function alignment is
FUNCTION_BOUNDARY, so there's no change.  However, if the user
specifies "-falign-functions=" or "-fno-align-functions" he can
set values lower than the default, provided they are atleast
MINIMUM_FUNCTION_BOUNDARY.

The final tweak is that language front-ends can place constraints
on the user specified alignments, but modifying align_functions
after command line processing in lang_hooks->init.  The patch
below causes the C++ and Java front-ends to always ensure code
is atleast FUNCTION_BOUNDARY aligned.

This works because the function pointers that appear in GCC's vtables
are always compiled by C++ or Java.  I believe there's no problem
linking C and C++, as my understanding is that a C compiled function
can't appear as a method in a vtable.  Even so, without specifying
-Os or -fno-align-functions, both C and C++ will use the same alignment
as they currently do.

This solution has the effect that the C++ and Java ABI's are completely
unchanged, but it is possible to get better code compaction in the C,
Fortran and Ada front-ends.

The test case from PR 6627

void foo(void) {}
void bar(void) {}

Compiling this with "g++ -Os" places a single nop byte between foo
and bar on IA-32, but compiling with "gcc -Os" results in no padding.


The following patch has been tested with a complete "make bootstrap"
and "make -k check", all languages except Ada and treelang, on
i686-pc-linux-gnu with no new regressions.  This patch only affects
non C++/Java front-ends on IA-32, but the target macro is there to
be used by anyone.  Indeed I suspect allowing the default function
alignment to be specified separately from the mimimum function
alignment is useful on most platforms.

Ok for mainline and to close high priority PR optimization/6627?


2002-09-28  Roger Sayle  <roger@eyesopen.com>

	* defaults.h (MINIMUM_FUNCTION_BOUNDARY): New macro.  Default
	its value to FUNCTION_BOUNDARY.
	* toplev.c (process_options): When processing align_functions
	the default value is FUNCTION_BOUNDARY/BITS_PER_UNIT, and the
	minimum value is MINIMUM_FUNCTION_BOUNDARY/BITS_PER_UNIT.
	* varasm.c (assemble_start_function):  Emit first alignment
	directive to either MINIMUM_FUNCTION_BOUNDARY or FUNCTION_BOUNDARY
	and then align to the user-specified alignment from there.

	* cp/decl.c (cxx_init_decl_processing): Adjust the minimum
	alignment for C++ functions and methods to FUNCTION_BOUNDARY.

	* java/lang.c (java_init): Adjust the minimum alignment for
	Java functions and methods to FUNCTION_BOUNDARY.

	* config/i386/i386.h:  Define MINIMUM_FUNCTION_BOUNDARY (8).

	* doc/tm.texi (TARGET MACROS): Update documentation for
	FUNCTION_BOUNDARY and new entry for MINIMUM_FUNCTION_BOUNDARY.


Index: defaults.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/defaults.h,v
retrieving revision 1.96
diff -c -3 -p -r1.96 defaults.h
*** defaults.h	22 Sep 2002 14:09:30 -0000	1.96
--- defaults.h	29 Sep 2002 00:48:45 -0000
*************** You Lose!  You must define PREFERRED_DEB
*** 617,620 ****
--- 617,625 ----
  #define EXTRA_ADDRESS_CONSTRAINT(C) 0
  #endif

+ /* By default, the minimum function alignment is FUNCTION_BOUNDARY.  */
+ #ifndef MINIMUM_FUNCTION_BOUNDARY
+ #define MINIMUM_FUNCTION_BOUNDARY  FUNCTION_BOUNDARY
+ #endif
+
  #endif  /* ! GCC_DEFAULTS_H */
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.677
diff -c -3 -p -r1.677 toplev.c
*** toplev.c	27 Sep 2002 12:48:03 -0000	1.677
--- toplev.c	29 Sep 2002 00:48:51 -0000
*************** process_options ()
*** 4995,5001 ****
    align_labels_log = floor_log2 (align_labels * 2 - 1);
    if (align_labels_max_skip > align_labels || !align_labels)
      align_labels_max_skip = align_labels - 1;
!   if (align_functions <= 0) align_functions = 1;
    align_functions_log = floor_log2 (align_functions * 2 - 1);

    /* Unrolling all loops implies that standard loop unrolling must also
--- 4995,5004 ----
    align_labels_log = floor_log2 (align_labels * 2 - 1);
    if (align_labels_max_skip > align_labels || !align_labels)
      align_labels_max_skip = align_labels - 1;
!   if (align_functions <= 0)
!     align_functions = FUNCTION_BOUNDARY / BITS_PER_UNIT;
!   if (align_functions < MINIMUM_FUNCTION_BOUNDARY / BITS_PER_UNIT)
!     align_functions = MINIMUM_FUNCTION_BOUNDARY / BITS_PER_UNIT;
    align_functions_log = floor_log2 (align_functions * 2 - 1);

    /* Unrolling all loops implies that standard loop unrolling must also
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.313
diff -c -3 -p -r1.313 varasm.c
*** varasm.c	27 Sep 2002 13:30:04 -0000	1.313
--- varasm.c	29 Sep 2002 00:48:56 -0000
*************** assemble_start_function (decl, fnname)
*** 1157,1163 ****
       tree decl;
       const char *fnname;
  {
!   int align;

    /* The following code does not need preprocessing in the assembler.  */

--- 1157,1163 ----
       tree decl;
       const char *fnname;
  {
!   int align, temp;

    /* The following code does not need preprocessing in the assembler.  */

*************** assemble_start_function (decl, fnname)
*** 1170,1176 ****
    function_section (decl);

    /* Tell assembler to move to target machine's alignment for functions.  */
!   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
    if (align > 0)
      {
        ASM_OUTPUT_ALIGN (asm_out_file, align);
--- 1170,1180 ----
    function_section (decl);

    /* Tell assembler to move to target machine's alignment for functions.  */
!   align = floor_log2 (MINIMUM_FUNCTION_BOUNDARY / BITS_PER_UNIT);
!   temp = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
!   if (align_functions_log >= temp)
!     align = temp;
!
    if (align > 0)
      {
        ASM_OUTPUT_ALIGN (asm_out_file, align);
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.936
diff -c -3 -p -r1.936 decl.c
*** cp/decl.c	21 Sep 2002 12:51:53 -0000	1.936
--- cp/decl.c	29 Sep 2002 00:49:13 -0000
*************** cxx_init_decl_processing ()
*** 6506,6511 ****
--- 6506,6517 ----
        flag_inline_trees = 2;
        flag_inline_functions = 0;
      }
+   if (align_functions < FUNCTION_BOUNDARY / BITS_PER_UNIT)
+     {
+       /* Minimum function alignment in C++ is FUNCTION_BOUNDARY.  */
+       align_functions = FUNCTION_BOUNDARY / BITS_PER_UNIT;
+       align_functions_log = floor_log2 (align_functions);
+     }

    /* Initially, C.  */
    current_lang_name = lang_name_c;
Index: java/lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/lang.c,v
retrieving revision 1.109
diff -c -3 -p -r1.109 lang.c
*** java/lang.c	21 Sep 2002 02:19:44 -0000	1.109
--- java/lang.c	29 Sep 2002 00:49:14 -0000
*************** java_init (filename)
*** 511,516 ****
--- 511,522 ----

    if (flag_inline_functions)
      flag_inline_trees = 1;
+   if (align_functions < FUNCTION_BOUNDARY / BITS_PER_UNIT)
+     {
+       /* Minimum function alignment in Java is FUNCTION_BOUNDARY.  */
+       align_functions = FUNCTION_BOUNDARY / BITS_PER_UNIT;
+       align_functions_log = floor_log2 (align_functions);
+     }

    /* Open input file.  */

Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.290
diff -c -3 -p -r1.290 i386.h
*** config/i386/i386.h	24 Sep 2002 12:48:55 -0000	1.290
--- config/i386/i386.h	29 Sep 2002 00:49:19 -0000
*************** extern int x86_prefetch_sse;
*** 691,698 ****
  #define FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN \
    (ix86_preferred_stack_boundary > STACK_BOUNDARY && !TARGET_64BIT)

! /* Allocation boundary for the code of a function.  */
  #define FUNCTION_BOUNDARY 16

  /* Alignment of field after `int : 0' in a structure.  */

--- 691,701 ----
  #define FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN \
    (ix86_preferred_stack_boundary > STACK_BOUNDARY && !TARGET_64BIT)

! /* Default allocation boundary for the code of a function.  */
  #define FUNCTION_BOUNDARY 16
+
+ /* Minimum allocation boundary for the code of a function.  */
+ #define MINIMUM_FUNCTION_BOUNDARY 8

  /* Alignment of field after `int : 0' in a structure.  */

Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.175
diff -c -3 -p -r1.175 tm.texi
*** doc/tm.texi	26 Sep 2002 12:29:45 -0000	1.175
--- doc/tm.texi	29 Sep 2002 00:49:34 -0000
*************** be momentarily unaligned while pushing a
*** 1047,1053 ****

  @findex FUNCTION_BOUNDARY
  @item FUNCTION_BOUNDARY
! Alignment required for a function entry point, in bits.

  @findex BIGGEST_ALIGNMENT
  @item BIGGEST_ALIGNMENT
--- 1047,1059 ----

  @findex FUNCTION_BOUNDARY
  @item FUNCTION_BOUNDARY
! Default alignment required for a function entry point, in bits.  This
! must be greater than or equal to MINIMUM_FUNCTION_BOUNDARY.
!
! @findex MINIMUM_FUNCTION_BOUNDARY
! @item MINIMUM_FUNCTION_BOUNDARY
! The minimum alignment for a function entry point, in bits, supported
! on this machine.   This value defaults to FUNCTION_BOUNDARY.

  @findex BIGGEST_ALIGNMENT
  @item BIGGEST_ALIGNMENT


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833



More information about the Gcc-patches mailing list