[PATCH 00/29] rs6000: Auto-generate builtins from descriptions [V2]

Bill Schmidt wschmidt@Bills-MacBook-Pro.local
Mon Jul 27 14:13:46 GMT 2020


From: Bill Schmidt <wschmidt@linux.ibm.com>

This is a slight reworking of the patches posted on June 17.  I have
made a couple of improvements, but the general arrangement of the patches
is the same as before.  Two major things to call out:

 - I've introduced a uniform set of parsing error codes to make it easier
   to follow some of the logic when certain conditions occur during parsing.

 - I reorganized the treatment of built-in stanzas.  Before, the stanza
   conditions were checked prior to initializing entries in the built-in
   table.  Now, all built-ins are initialized, but we check the conditions
   at expand time to determine whether they should be enabled.  This
   addresses a frequent problem we have with the existing methods, where
   "#pragma target" doesn't work as expected when changing the target
   CPU for a single function.

As described before, the current built-in support in the rs6000 back end
requires at least a master's degree in spelunking to comprehend.  It's
full of cruft, redundancy, and unused bits of code, and long overdue for a
replacement.  This is the first part of my project to do that.

My intent is to make adding new built-in functions as simple as adding a
few lines to a couple of files, and automatically generating as much of
the initialization, overload resolution, and expansion logic as possible.
This patch series establishes the format of the input files and creates
a new program (rs600-gen-builtins) to:

 * Parse the input files into an internal representation;
 * Generate a file of #defines (rs6000-vecdefines.h) for eventual
   inclusion into altivec.h; and
 * Generate an initialization file to create and initialize tables of
   built-in functions and overloads.

Patches 1, 3-7, and 9-19 contain the logic for rs6000-gen-builtins.
Patch 8 provides balanced tree search support for parsing scalability.
Patches 2 and 21-27 provide a first cut at the input files.
Patch 20 incorporates the new code into the GCC build.
Patch 28 adds comments to some existing files that will help during the
transition from the previous built-in mechanism.
Patch 29 turns on the initialization logic, while leaving GCC's behavior
unchanged otherwise.

The patch series is constructed so that any prefix set of the patches
can be upstreamed without breaking anything.  There's still plenty of
work left, but I think it will be helpful to get this big chunk of
patches upstream to make further progress easier (translation: avoid
complex rebases like the one I just went through :-).

Following is some additional information about the present and future
design that may be of help.

The set of patches submitted upstream so far does the relatively
straightforward work of reading builtin descriptions from flat files and
generating initialization code for builtin and overload tables.  It also
generates an include file meant to be included in altivec.h, which produces
the #defines that map vec_* to __builtin_* functions for external consumption.

Data structures are automatically initialized in rs6000_builtins.c:
rs6000_autoinit_builtins.  Initialized data structures are:

 - rs6000_gen_builtins:  An enumeration of builtin identifiers, such as
RS6000_BIF_CPU_SUPPORTS.  These names are deliberately different from the
existing builtin identifiers so they can co-exist for a while.

 - rs6000_gen_overloads:  An enumeration of overload identifiers, such as
RS6000_OVLD_MAX.  Again, deliberately different from the old names.  Right
now I have the two enumerations using nonoverlapping numbers.  This is
because the two tables were part of one table in the old design, and I
haven't yet proven for sure that I can separate them without problems.
I think that I can, in which case I will have both enumerations start from
zero.

 - A number of filescope variables representing TREE_TYPEs of functions.
These are named <return-type>_ftype_<param1-type>_ ... _<paramN-type> and
initialized as tree lists from the prototypes in the input files.  The
naming scheme for types is described in the code. 

 - rs6000_builtin_info_x:  An array indexed by rs6000_gen_builtins containing
all the fun stuff for each builtin.  The "_x" is because we already have
rs6000_builtin_info as the old table, and they need to coexist for a while.

 - rs6000_overload_info:  An array indexed by rs6000_gen_overloads containing
all the fun stuff for each overload.

 - bif_hash:  A hash table mapping builtin function names to pointers to
their rs6000_builtin_info_x entries.

 - ovld_hash:  A hash table mapping overload names to pointers to their
rs6000_overload_info entries. 

The new initialization code is called from rs6000_init_builtins. Currently
this function continues to do its existing initialization work, but also
initializes the new tables (and then ignores them). 

The old initialization code contains a lot of ad hoc hackery to handle
different kinds of functions that require extra behavior. The new design
removes as much of that as possible, and instead uses syntax in the flat
file to generate flags and other information that allows initialization
to be done uniformly for all functions.  It also means that all
initialization is done as a single pass over the builtins, as opposed to
the current methods that require multiple passes over all the builtins
to find the particular special code required for a single one.

Now, it's important to keep both the old and the new initialization code
functional at once.  There is a static variable new_builtins_are_live
that's used to select which tables will be used during compilation.  Its
value can be set via a macro when building the compiler, or adjusted at
runtime under debugger control.  The important thing is to ensure that
all differences in supported builtins between the old methods and the new
ones are expected.  We do want some differences, because we are removing
a lot of long-deprecated functions.  It will be important to test for
differences on BE, LE, 64-bit, 32-bit, AIX, and Darwin, as I'm also
trying to remove dependences on the "long" integer types wherever possible.
We'll see how successful that is.

A future patch will update the debug code to print out type signature
information for each initialized builtin, to make it easier to compare the
old and new functions for type equivalence.

So that explains stage 1 of the code, mostly done in the patches I've posted,
except as noted above.

There are three remaining stages to be completed:

 - Gimple folding
 - Overload resolution
 - Builtin expansion

The order above is the order that they take place during compilation.

Gimple folding changes will be simple.  The only change here is that the
builtin names are different, so we'll need to check the different names
depending on whether new_builtins_are_live is set or unset.

Overload resolution changes should be mostly simple also.  The new
rs6000_overload_info table will be used instead of the handwritten table in
rs6000-call.c.  The new table does not have any limits on the number of
operands, so all the hackery around unary, binary, ternary, quaternary, etc.
will go away.  The code for resolving an AltiVec builtin will be required to
use the new table, and there is still some special case code in there that
will need to be updated for the new naming scheme.  But all in all I don't
expect a lot of work here, except for adding all the new overload entries
into the input file (not yet started).

I have been working on the builtin expansion part next, which is the most
complicated.  rs6000_expand_builtin and its support functions are where all
the worst offenses in the code exist. Most of the changes here involve
removing as much of the special casing as possible, and replacing it with
table-driven logic.  In particular, this allows us to get rid of a lot of
hand-written code checking for constant arguments that have a restricted set
of allowable values.  I can't get rid of all the special cases, but I can
make them driven by flags in the builtin table instead of the ad hoc checking
for specific builtins that occurs today.  A lot of this has been written but
not yet tested.

My current plans are:

 - Get the first set of patches committed
 - Add debug code to make it easier to test which builtins (with type
   signatures) are created using the old and new methods
 - Test this on all the platforms that matter until I have everything matching
 - Complete writing the builtin expansion code
 - Write the Gimple folding and overload resolution pieces
 - Test and revise until the testsuite passes
 - Enable the new version of the code as the default
 - Let it burn in for a while and deal with bug reports
 - Remove the now-dead code supporting the old methods (around end of stage 3)

That's it!  Easy peasy. :-)

Thanks in advance for reviewing this code, and I welcome comments on the
overall design.  I'd really like to get these patches upstream soon, as
it's becoming clumsy to maintain them out of tree.

Thanks!

 -- Bill

Bill Schmidt (29):
  rs6000: Initial create of rs6000-gen-builtins.c
  rs6000: Add initial input files
  rs6000: Add file support and functions for diagnostic support
  rs6000: Add helper functions for parsing
  rs6000: Add functions for matching types, part 1 of 3
  rs6000: Add functions for matching types, part 2 of 3
  rs6000: Add functions for matching types, part 3 of 3
  rs6000: Red-black tree implementation for balanced tree search
  rs6000: Main function with stubs for parsing and output
  rs6000: Parsing built-in input file, part 1 of 3
  rs6000: Parsing built-in input file, part 2 of 3
  rs6000: Parsing built-in input file, part 3 of 3
  rs6000: Parsing of overload input file
  rs6000: Build and store function type identifiers
  rs6000: Write output to the vector definition include file
  rs6000: Write output to the builtins header file
  rs6000: Write output to the builtins init file, part 1 of 3
  rs6000: Write output to the builtins init file, part 2 of 3
  rs6000: Write output to the builtins init file, part 3 of 3
  rs6000: Incorporate new builtins code into the build machinery
  rs6000: Add remaining AltiVec builtins
  rs6000: Add VSX builtins
  rs6000: Add available-everywhere and ancient builtins
  rs6000: Add Power7 builtins
  rs6000: Add Power8 vector builtins
  rs6000: Add Power9 builtins
  rs6000: Add remaining builtins
  rs6000: Add comments to help with transition
  rs6000: Call rs6000_autoinit_builtins from rs6000_builtins

 gcc/config.gcc                           |    3 +-
 gcc/config/rs6000/rbtree.c               |  233 ++
 gcc/config/rs6000/rbtree.h               |   51 +
 gcc/config/rs6000/rs6000-builtin-new.def | 2967 ++++++++++++++++++++++
 gcc/config/rs6000/rs6000-builtin.def     |   15 +
 gcc/config/rs6000/rs6000-call.c          |  170 ++
 gcc/config/rs6000/rs6000-gen-builtins.c  | 2660 +++++++++++++++++++
 gcc/config/rs6000/rs6000-overload.def    |   57 +
 gcc/config/rs6000/t-rs6000               |   25 +-
 9 files changed, 6179 insertions(+), 2 deletions(-)
 create mode 100644 gcc/config/rs6000/rbtree.c
 create mode 100644 gcc/config/rs6000/rbtree.h
 create mode 100644 gcc/config/rs6000/rs6000-builtin-new.def
 create mode 100644 gcc/config/rs6000/rs6000-gen-builtins.c
 create mode 100644 gcc/config/rs6000/rs6000-overload.def

-- 
2.17.1



More information about the Gcc-patches mailing list