This is the mail archive of the gcc@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]

First cut on outputing gimple for LTO using DWARF3. Discussion invited!!!!


This posting is a progress report of my task of encoding and decoding
the GIMPLE stream into LTO.   Included in this posting is a patch that
encodes functions and dumps the result to files.  

The purpose of this mail is threefold:

1) To solicit comments from the GIMPLE elite of the GCC community as
to what is missing or just plain wrong with my interpretation of
GIMPLE.  Everything I know has been gleaned from the GCC's legendary
documentation and from talking to StevenB, DannyB, Honza, Diego and
Pinskia.

There are clearly things that I am either doing wrong or are just
missing and it would be useful if the people who know (or think that
they know) GIMPLE to comment on my code.  In particular, it would be
useful to have comments about fields or attributes that I am missing
and cannot be easily recovered on the reading side.

2) To have a discussion about the use of DWARF3.  I am now against the
use of DWARF3 for encoding the GIMPLE.  Most of the rest of the mail
gives my arguments on this subject.  Before I start writing the other
side of this code, I would like to settle this issue once and for all.
The enclosed patch only performs the encoding into DWARF3 side of the
problem.

3) To get some one to tell me what option we are going to add to the
compiler to tell it to write this information.  

THE STATE OF THIS CODE:

1) The current patch can process an entire bootstrap on x86-64 of c,
c++ and Fortran on the current LTO branch without iceing.

2) The code is, by design, fragile.  It takes nothing for granted.
Every case statement has gcc_unreachable as it's default case.  It
either encodes a GIMPLE form or it crashes.  In order to be correct,
the code cannot pun or skip cases as the majority of the compilation
passes can.

3) The code currently ignores the line numbers, the types and
decls and GOMP.  The line numbers will happen after a find and debrief
a line number specialist.  The types and decls are Mark Mitchell's
part.  GOMP is just not documented to a level where any one can deal
with it except Diego and I do not need to do it to demonstrate the
points here.

4) The code does not put the DWARF3 GIMPLE into .o files, it dumps it
to files in the /tmp/LTOtest.  If you are not on a Unix machine, you
may not be able to play with this version.  However, this is a demo,
not a long term plan.  This was done to be able to measure things,
there is no representation that the code that dumps it files is at all
the kind of code we want in the compiler.

MY VIEWS ON DWARF3:

>From a high level, DWARF3, seems like a good match for this task.  The
problem is that when you get down to the low level details, it does
not look so good.  I was on board with DWARF3 when the suggestion was
made, but now that I actually have taken the time to
understand the spec and have written the code, I can stand on high
ground to say why this is the wrong direction.

1) Abbrev tables: solve a problem that we are not interested in
do not solve any of the problems we are interested in and
introduce problems of their own.

2) The DWARF3 stack machine is not usable for GIMPLE.

3) There is no compression in DWARF3.

4) I cheated to get the compression that we got.


1) ABBREV TABLES ARE BAD FOR LTO.

The abbrev table is a mechanism for making a DWARF3 file self
descriptive.  It contains a set of templates that are used to describe
the records and attributes that are written to describe the object
module.

This self description mechanism is much weaker (an therefor much more
compact) than an XML file's schemata because it depends on a common
understanding of the meaning of the tags and attributes that describe
the pieces of the data.  The tags them selves can be thought of as
characters, and an abbrev entry is a magic cookie that tells you how
to break the characters into words.

However, this mechanism is only self descriptive if you do not extend
the set of tags.  That is not an option for LTO.  While the DWARF3
designers seem to have added every conceivable tag to describe object
code, it is not be surprising that this comes up short when describing
GIMPLE.  While some of GIMPLE could be shoe-horned into the existing
tags, all of it will not fit, so anyone who wants to understand
GIMPLE, will need to use the GCC headers.

Using the abbrev tables also add a lot of complexity. It should be
understood that while the abbrev table for two separate files encodes
the same information, the way that the abbrev tables are generated
almost guarantees that the abbrev table will be encoded differently for each
file.  The abbrev table is a sequential list of record
descriptors. The way that the list is generated is first needed, first
output, and you only output the records you need.  Each of these
records is numbered sequentially.  So the numbering of the abbrev
records will generally be different for the two created object files since
they reference different GIMPLE nodes.

I strongly believe that for LTO to work, we are going to have to
implement some mechanism where the function bodies are loaded into the
compiler on demand (possibly kept in cache, but maybe not).  This
will be more cumbersome if we have to keep reloading each object
file's abbrev table just to tear apart a single function in that .o
file.  While the abbrev sections average slightly less than %2 of the
of the size of the GIMPLE encoding for an entire file, each abbrev table
averages about the same size as a single function.  Thus, we will either
have to keep all the abbrev entries for an entire compilation, implement
a second caching mechanism, or do about twice the file reading to load
a single function.

The alternative is to just have static records that are hard coded
into the reader and writer.  The records will be the same as the records
used a abbrev file, but the record schemata's will be hard coded
rather than assigned on a file by file basis.

A lot of my design decisions are biased by wanting to be able to load
pieces of an object file without touching large parts of it.  I think
that if we cannot do this, LTO will be a toy for specmarking and
nothing more.


2) I PROMISED TO USE THE DWARF3 STACK MACHINE AND I DID NOT.

Rumsfield thought we would be out of Iraq in a few months.  He was
wrong too.  

It sounded good from a high level but the devil is in the details.
The problem is that GIMPLE has a lot of hair.  Each tree node has a
type, a bunch of flags, perhaps a line number, and God only knows what
else I have missed.  There is no place in the DWARF3 stack machine to
shove that stuff.


3) THERE IS NO COMPRESSION IN DWARF3.

Despite what I was told about abbrev tables providing some compaction
(see point 1), there are no mechanisms in DWARF3 for compressing the
data.  The only mechanism that is suggested in the spec is to use a
lot of sections, and then if you have a smart linker, it can notice
that many of these sections are duplicates.  This is most likely quite
useful for C++ templates and if it is, we can play the same game with
our own encoding, by putting each function or template in its own
section and depending on our smart linker to purge duplicates.  There
is nothing in DWARF3 that aids in doing this, the spec simply has a
section on how to name things so that this could work if you have a
good linker.

The enclosed patch writes the LTO information to a series of files in
/tmp/LTOtest.  By defining preprocessor symbols it is possible to
either print 1 function per file or 1 file per file.  

In 1 file per mode, zlib -9 compression is almost 6:1.  In 1 function
per mode, zlib -9 compression averages about 3:1.  The later mode,
with the smaller compression, is what would be the most useful,
because it allows the functions to be manipulated without reading
the entire object file.  zlib, as with most compressors, has a significant
startup cost.  Compressing small things is not as effective as compressing
large things.

The abbrev tables take less than 2% of the space and compress about 3:1.
It is not surprising that the abbrev tables compress so much because
DWARF3 requires that extension tags have large ids.  Since these tag
values only live in the abbrev table, all of that air is there, not in
the part
that encodes the GIMPLE.

4) I CHEATED TO GET THE COMPRESSION THAT I GOT.

I must confess that I have actually extended the mechanisms further
than the DWARF3 standard allows.  I added record forms which is not an
allowed extension.  The forms that I added were for vectors of
things. DWARF3's design seems to have been influenced by the GCC design
that everything can be expressed as a tree.  While this is true, I
simply applied the same observation that is being done in our tree
cleanup that vectors are a more compact representation that tree
lists.  This can be undone, but it will bulk up the representation
even more.  

To give a concrete example, the successor edge list of a basic block
is encoded as n + 1 uleb128 numbers.  The first one tells how many
edges there are and the rest are the block numbers of the successors.
To do this in DWARF3 without extension, would take almost double the
space, for each edge, one uleb128 number would be required to
reference the abbrev entry, and a second one for the successor block.
The list is then terminated with a 0.  And if we abandon DWARF3, as I
am advocating, my encoding is the right way to go.

In truth, my code is pretty carefully written.  I squeezed out all of
the air that I could.

REMAINING PIECES

1) LINE NUMBERS

DWARF3 has a line number table.  I assume that it is relatively well
thought (out as is most of the rest of DWARF3).  For LTO to work well,
we will need to make sure that the line number info is broken into
separate sections, one for each function so that functions can be
accessed without loading the entire table for the object module.  I
have not checked this. However, whether it is done or not, I can add
references to it my code and if that has to change, my code should
still work.

2) LOCAL DECLARATIONS  

Mark was going to do all of the types and all of the declarations.
His plan was to use the existing DWARF3 and enhance it where it was
necessary eventually replacing the GCC type trees with direct
references to the DWARF3 symbol table.  This could still work for the
types and the global variables.  However, I do not see how this could
work for the local decls, especially when we move to SSA form.  The
timing of when the declarations are written for debugging is, by
definition, quite late so that the debugging info actually contains
instructions to the debugger to access each of the variables.  Some
variables, especially SSA names do not last that long.  Thus, I feel
that I am going to at least have to put out my own local variable
table.  The types and global variables are likely OK, or at least Mark
should be able to add any missing info.

3) ADDING COMPRESSION

I have been using zlib as my measurements because I just always use
zlib.  Furthermore, I know there is a zlib subdirectory in the GCC
tree so I assume it is available in some form.  I know there are other
compressors and I leave it to a compression specialist to suggest a
better alternative.

I should point out that there is a good reasons why DWARF3 is not
compressed:  there are mechanisms for cross linking the DWARF3 trees
and if you are either going to rely on the assembler to fix up these
cross references or expect to memory map the debugging info in and
just walk around in it, compression is not for you.

However, the LTO information is not GIMPLE, it is an encoding of
GIMPLE and needs to be decoded in order to be used by the compiler.
So passing it through an expander on loading is not an issue.  I also
do not cross link the DWARF3 trees.  Labels, decls, types, and strings
all are indirected thru side tables.  This keeps their offsets
compact.  Thus there is nothing hard about running my sections thru a
compressor before dumping the binary into the assembly stream.

4) OTHER INFO

We will also need to add other structures to the object files.  We
will need to have a version of the cgraph, in a separate section, that
is in a form so that all of the cgraphs from all of the object files
can be read a processed without looking at the actual function bodies.

Likewise, we will have to restructure the existing IPA passes into two
parts: one part computes the local information and the second part
does some interprocedural closure on that information.  The first part
of the information can be written in so form into the object files and
the during LTO processing, read back in so that the interprocedural
closure can be done.  

For example, the current pure and constant function determination pass
first determines which functions are locally pure or constant and then
does a closure over the call graph to make sure that each pure
function only calls other pure functions and so on...  If we simply
label the call graph with the locally pure and locally constant
attributes, the closure phase can be done for all of the functions in
the LTO compilation without having to reprocess their bodies.
Virtually all inteprocedural optimizations, including aliasing, can
and must be structured this way.

5) ADDING THE READER.

I will add this when we reach a consensus on DWARF3.


IF I RULED THE EARTH, THIS IS WHAT I WOULD DO

I would strip out the DWARF3 from this patch.  It is about 1/3 of the
code, but basically leave the encoding as it is with the exception that
the abbrev table references would be changes to hard coded record type
numbers in an include file.  Then run each function through a
compressor and write it a separate ELF section.  

I have not done this because I do not rule the earth.  That was not
what I was assigned to do, and I agreed that DWARF3 sounded like a
reasonable way to go.  Now that I understand the details of DWARF3, I
have changed my mind about the correct direction.  Now is the time to
make that change before there is a lot of infrastructure built that
assumes the DWARF3 encoding.

I understand that this should be a community decision.  I believe that
attached patch will let anyone play with this so the discussion can
avoid being just idle speculation.  In particular, the amount of
compression may change if there are found to be significant problems
with my understanding of GIMPLE.  Adding the line number info will
also change the compression ratios though I expect it will only make
them larger.

I invite your discussion, comments and general venting of personal
frustrations.  

Let the games begin!

Kenny.

Index: lto-tree-flags.def
===================================================================
--- lto-tree-flags.def	(revision 0)
+++ lto-tree-flags.def	(revision 0)
@@ -0,0 +1,670 @@
+/* Code to decode the gimple tree flags. 
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* This file is designed to be inlined into both the writing and the
+   reading of the lto information.  What it does depends on the glue
+   that put in front and at the end of this and how ADD_BASE_FLAG is
+   defined. 
+
+   For those interested in extra credit, this could also be used as
+   the checking code to see if each flag is used correctly.  10 extra
+   credit points will be given for the intrepid programmer who does
+   this and is able to removes the comment that this was generated
+   from in tree.h.  */
+{
+  unsigned int code = TREE_CODE (expr);
+  
+  switch (TREE_CODE_CLASS (code))
+    {
+    case tcc_binary:
+    case tcc_comparison:
+    case tcc_expression:
+    case tcc_reference:
+    case tcc_statement:
+    case tcc_unary:
+    case tcc_vl_exp:
+      ADD_BASE_FLAG (side_effects_flag)
+      ADD_BASE_FLAG (volatile_flag)
+      ADD_BASE_FLAG (readonly_flag)
+      ADD_BASE_FLAG (constant_flag)
+      ADD_BASE_FLAG (used_flag)
+      ADD_BASE_FLAG (invariant_flag)
+      ADD_BASE_FLAG (nowarning_flag)
+      break;
+
+    case tcc_constant:
+      ADD_BASE_FLAG (side_effects_flag)
+      ADD_BASE_FLAG (readonly_flag)
+      ADD_BASE_FLAG (constant_flag)
+      break;
+
+    case tcc_declaration:
+      ADD_BASE_FLAG (private_flag)
+      ADD_BASE_FLAG (protected_flag)
+      ADD_BASE_FLAG (side_effects_flag)
+      ADD_BASE_FLAG (readonly_flag)
+      ADD_BASE_FLAG (constant_flag)
+      ADD_BASE_FLAG (unsigned_flag)
+      ADD_BASE_FLAG (deprecated_flag)
+      break;
+
+    case tcc_exceptional:
+      break;
+
+    case tcc_type:
+      ADD_BASE_FLAG (addressable_flag)
+      ADD_BASE_FLAG (public_flag)
+      ADD_BASE_FLAG (volatile_flag)
+      ADD_BASE_FLAG (readonly_flag)
+      ADD_BASE_FLAG (constant_flag)
+      ADD_BASE_FLAG (unsigned_flag)
+      ADD_BASE_FLAG (nothrow_flag)
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  switch (code)
+    {
+    case ABS_EXPR:
+      break;
+      
+    case ADDR_EXPR:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+    case ALIGN_INDIRECT_REF:
+      break;
+      
+      ADD_BASE_FLAG (nothrow_flag)
+    case ARRAY_RANGE_REF:
+      break;
+      
+      ADD_BASE_FLAG (nothrow_flag)
+    case ARRAY_REF:
+      break;
+      
+      ADD_BASE_FLAG (nothrow_flag)
+    case ARRAY_TYPE:
+      break;
+      
+    case ASM_EXPR:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+      ADD_BASE_FLAG (public_flag)
+    case ASSERT_EXPR:
+      break;
+      
+    case BIND_EXPR:
+      break;
+      
+    case BIT_AND_EXPR:
+      break;
+      
+    case BIT_FIELD_REF:
+      break;
+      
+      ADD_BASE_FLAG (unsigned_flag)
+    case BIT_IOR_EXPR:
+      break;
+      
+    case BIT_NOT_EXPR:
+      break;
+      
+    case BIT_XOR_EXPR:
+      break;
+      
+    case BLOCK:
+      break;
+      
+      ADD_BASE_FLAG (asm_written_flag)
+    case BOOLEAN_TYPE:
+      break;
+      
+    case CALL_EXPR:
+      break;
+      
+      ADD_BASE_FLAG (addressable_flag)
+      ADD_BASE_FLAG (private_flag)
+      ADD_BASE_FLAG (protected_flag)
+      ADD_BASE_FLAG (nothrow_flag)
+    case CASE_LABEL_EXPR:
+      break;
+      
+    case CATCH_EXPR:
+      break;
+      
+    case CEIL_DIV_EXPR:
+      break;
+      
+    case CEIL_MOD_EXPR:
+      break;
+      
+    case CLEANUP_POINT_EXPR:
+      break;
+      
+    case COMPLEX_CST:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+      ADD_BASE_FLAG (public_flag)
+    case COMPLEX_EXPR:
+      break;
+      
+    case COMPLEX_TYPE:
+      break;
+      
+    case COMPONENT_REF:
+      break;
+      
+    case COMPOUND_EXPR:
+      break;
+      
+    case COND_EXPR:
+      break;
+      
+    case CONJ_EXPR:
+      break;
+      
+    case CONST_DECL:
+      break;
+      
+    case CONSTRUCTOR:
+      break;
+      
+      ADD_BASE_FLAG (addressable_flag)
+      ADD_BASE_FLAG (static_flag)
+    case CONVERT_EXPR:
+      break;
+      
+    case DECL_EXPR:
+      break;
+      
+    case DOT_PROD_EXPR:
+      break;
+      
+    case EH_FILTER_EXPR:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+    case ENUMERAL_TYPE:
+      break;
+      
+    case EQ_EXPR:
+      break;
+      
+    case ERROR_MARK:
+      break;
+      
+    case EXACT_DIV_EXPR:
+      break;
+      
+    case EXC_PTR_EXPR:
+      break;
+      
+    case EXIT_EXPR:
+      break;
+      
+    case FDESC_EXPR:
+      break;
+      
+    case FIELD_DECL:
+      break;
+      
+      ADD_BASE_FLAG (addressable_flag)
+    case FILTER_EXPR:
+      break;
+      
+    case FIX_CEIL_EXPR:
+      break;
+      
+    case FIX_FLOOR_EXPR:
+      break;
+      
+    case FIX_ROUND_EXPR:
+      break;
+      
+    case FIX_TRUNC_EXPR:
+      break;
+      
+    case FLOAT_EXPR:
+      break;
+      
+    case FLOOR_DIV_EXPR:
+      break;
+      
+    case FLOOR_MOD_EXPR:
+      break;
+      
+    case FUNCTION_DECL:
+      break;
+      
+      ADD_BASE_FLAG (addressable_flag)
+      ADD_BASE_FLAG (static_flag)
+      ADD_BASE_FLAG (public_flag)
+      ADD_BASE_FLAG (nothrow_flag)
+    case FUNCTION_TYPE:
+      break;
+      
+    case GE_EXPR:
+      break;
+      
+    case GOTO_EXPR:
+      break;
+      
+    case GT_EXPR:
+      break;
+      
+    case IDENTIFIER_NODE:
+      break;
+      
+      ADD_BASE_FLAG (addressable_flag)
+      ADD_BASE_FLAG (static_flag)
+      ADD_BASE_FLAG (public_flag)
+      ADD_BASE_FLAG (used_flag)
+      ADD_BASE_FLAG (deprecated_flag)
+    case IMAGPART_EXPR:
+      break;
+      
+    case INDIRECT_REF:
+      break;
+      
+    case INIT_EXPR:
+      break;
+      
+    case INTEGER_CST:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+      ADD_BASE_FLAG (public_flag)
+    case INTEGER_TYPE:
+      break;
+      
+    case LABEL_DECL:
+      break;
+      
+      ADD_BASE_FLAG (addressable_flag)
+      ADD_BASE_FLAG (side_effects_flag)
+    case LABEL_EXPR:
+      break;
+      
+    case LANG_TYPE:
+      break;
+      
+    case LE_EXPR:
+      break;
+      
+    case LOOP_EXPR:
+      break;
+      
+    case LROTATE_EXPR:
+      break;
+      
+    case LSHIFT_EXPR:
+      break;
+      
+    case LT_EXPR:
+      break;
+      
+    case LTGT_EXPR:
+      break;
+      
+    case MAX_EXPR:
+      break;
+      
+    case METHOD_TYPE:
+      break;
+      
+    case MIN_EXPR:
+      break;
+      
+    case MINUS_EXPR:
+      break;
+      
+    case MISALIGNED_INDIRECT_REF:
+      break;
+      
+      ADD_BASE_FLAG (nothrow_flag)
+    case MODIFY_EXPR:
+      break;
+      
+    case MULT_EXPR:
+      break;
+      
+    case NAME_MEMORY_TAG:
+      break;
+      
+    case NAMESPACE_DECL:
+      break;
+      
+    case NE_EXPR:
+      break;
+      
+    case NEGATE_EXPR:
+      break;
+      
+    case NON_LVALUE_EXPR:
+      break;
+      
+    case NOP_EXPR:
+      break;
+      
+    case OBJ_TYPE_REF:
+      break;
+      
+    case OFFSET_TYPE:
+      break;
+      
+    case OMP_ATOMIC:
+      break;
+      
+    case OMP_CLAUSE:
+      break;
+      
+      ADD_BASE_FLAG (public_flag)
+    case OMP_CONTINUE:
+      break;
+      
+    case OMP_CRITICAL:
+      break;
+      
+    case OMP_FOR:
+      break;
+      
+    case OMP_MASTER:
+      break;
+      
+    case OMP_ORDERED:
+      break;
+      
+    case OMP_PARALLEL:
+      break;
+      
+      ADD_BASE_FLAG (private_flag)
+    case OMP_RETURN:
+      break;
+      
+      ADD_BASE_FLAG (private_flag)
+    case OMP_SECTION:
+      break;
+      
+      ADD_BASE_FLAG (private_flag)
+    case OMP_SECTIONS:
+      break;
+      
+    case OMP_SINGLE:
+      break;
+      
+    case ORDERED_EXPR:
+      break;
+      
+    case PARM_DECL:
+      break;
+      
+    case PHI_NODE:
+      break;
+      
+    case PLACEHOLDER_EXPR:
+      break;
+      
+    case PLUS_EXPR:
+      break;
+      
+    case POINTER_TYPE:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+    case POLYNOMIAL_CHREC:
+      break;
+      
+    case POSTDECREMENT_EXPR:
+      break;
+      
+    case POSTINCREMENT_EXPR:
+      break;
+      
+    case PREDECREMENT_EXPR:
+      break;
+      
+    case PREINCREMENT_EXPR:
+      break;
+      
+    case QUAL_UNION_TYPE:
+      break;
+      
+      ADD_BASE_FLAG (asm_written_flag)
+    case RANGE_EXPR:
+      break;
+      
+    case RDIV_EXPR:
+      break;
+      
+    case REAL_CST:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+      ADD_BASE_FLAG (public_flag)
+    case REALIGN_LOAD_EXPR:
+      break;
+      
+    case REALPART_EXPR:
+      break;
+      
+    case REAL_TYPE:
+      break;
+      
+    case RECORD_TYPE:
+      break;
+      
+      ADD_BASE_FLAG (asm_written_flag)
+    case REDUC_MAX_EXPR:
+      break;
+      
+    case REDUC_MIN_EXPR:
+      break;
+      
+    case REDUC_PLUS_EXPR:
+      break;
+      
+    case REFERENCE_TYPE:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+    case RESULT_DECL:
+      break;
+      
+    case RESX_EXPR:
+      break;
+      
+    case RETURN_EXPR:
+      break;
+      
+    case ROUND_DIV_EXPR:
+      break;
+      
+    case ROUND_MOD_EXPR:
+      break;
+      
+    case RROTATE_EXPR:
+      break;
+      
+    case RSHIFT_EXPR:
+      break;
+      
+    case SAVE_EXPR:
+      break;
+      
+      ADD_BASE_FLAG (public_flag)
+    case SCEV_KNOWN:
+      break;
+      
+    case SCEV_NOT_KNOWN:
+      break;
+      
+    case SSA_NAME:
+      break;
+      
+      ADD_BASE_FLAG (asm_written_flag)
+    case STATEMENT_LIST:
+      break;
+      
+    case STRING_CST:
+      break;
+      
+    case STRUCT_FIELD_TAG:
+      break;
+      
+    case SWITCH_EXPR:
+      break;
+      
+    case SYMBOL_MEMORY_TAG:
+      break;
+      
+    case TARGET_EXPR:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+    case TARGET_MEM_REF:
+      break;
+      
+    case TRANSLATION_UNIT_DECL:
+      break;
+      
+    case TREE_BINFO:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+    case TREE_LIST:
+      break;
+      
+    case TREE_VEC:
+      break;
+      
+    case TRUNC_DIV_EXPR:
+      break;
+      
+    case TRUNC_MOD_EXPR:
+      break;
+      
+    case TRUTH_AND_EXPR:
+      break;
+      
+    case TRUTH_ANDIF_EXPR:
+      break;
+      
+    case TRUTH_NOT_EXPR:
+      break;
+      
+    case TRUTH_OR_EXPR:
+      break;
+      
+    case TRUTH_ORIF_EXPR:
+      break;
+      
+    case TRUTH_XOR_EXPR:
+      break;
+      
+    case TRY_CATCH_EXPR:
+      break;
+      
+    case TRY_FINALLY_EXPR:
+      break;
+      
+    case TYPE_DECL:
+      break;
+      
+    case UNEQ_EXPR:
+      break;
+      
+    case UNGE_EXPR:
+      break;
+      
+    case UNGT_EXPR:
+      break;
+      
+    case UNION_TYPE:
+      break;
+      
+      ADD_BASE_FLAG (asm_written_flag)
+    case UNLE_EXPR:
+      break;
+      
+    case UNLT_EXPR:
+      break;
+      
+    case UNORDERED_EXPR:
+      break;
+      
+    case VA_ARG_EXPR:
+      break;
+      
+    case VALUE_HANDLE:
+      break;
+      
+    case VAR_DECL:
+      break;
+      
+      ADD_BASE_FLAG (addressable_flag)
+      ADD_BASE_FLAG (static_flag)
+      ADD_BASE_FLAG (public_flag)
+      ADD_BASE_FLAG (asm_written_flag)
+    case VEC_COND_EXPR:
+      break;
+      
+    case VEC_LSHIFT_EXPR:
+      break;
+      
+    case VEC_RSHIFT_EXPR:
+      break;
+      
+    case VECTOR_CST:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+      ADD_BASE_FLAG (public_flag)
+    case VECTOR_TYPE:
+      break;
+      
+    case VIEW_CONVERT_EXPR:
+      break;
+      
+    case VOID_TYPE:
+      break;
+      
+    case WIDEN_MULT_EXPR:
+      break;
+      
+    case WIDEN_SUM_EXPR:
+      break;
+      
+    case WITH_CLEANUP_EXPR:
+      break;
+      
+      ADD_BASE_FLAG (static_flag)
+    case WITH_SIZE_EXPR:
+      break;
+      
+    default:
+      gcc_unreachable ();
+    }
+}
Index: cgraph.c
===================================================================
--- cgraph.c	(revision 116385)
+++ cgraph.c	(working copy)
@@ -1009,17 +1009,22 @@ cgraph_clone_node (struct cgraph_node *n
 /* Return true if N is an master_clone, (see cgraph_master_clone).  */
 
 bool
-cgraph_is_master_clone (struct cgraph_node *n)
+cgraph_is_master_clone (struct cgraph_node *n, bool check_overwrite)
 {
-  return (n == cgraph_master_clone (n));
+  return (n == cgraph_master_clone (n, check_overwrite));
 }
 
+
+/* Return the master clone node of N if it is available and if
+   CHECK_OVERWRITE is true, not overwritable.  */ 
+
 struct cgraph_node *
-cgraph_master_clone (struct cgraph_node *n)
+cgraph_master_clone (struct cgraph_node *n, bool check_overwrite)
 {
   enum availability avail = cgraph_function_body_availability (n);
 
-  if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
+  if (avail == AVAIL_NOT_AVAILABLE || 
+      (check_overwrite && (avail == AVAIL_OVERWRITABLE)))
     return NULL;
 
   if (!n->master_clone)
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 116385)
+++ cgraph.h	(working copy)
@@ -292,8 +292,8 @@ bool decide_is_variable_needed (struct c
 
 enum availability cgraph_function_body_availability (struct cgraph_node *);
 enum availability cgraph_variable_initializer_availability (struct cgraph_varpool_node *);
-bool cgraph_is_master_clone (struct cgraph_node *);
-struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
+bool cgraph_is_master_clone (struct cgraph_node *, bool);
+struct cgraph_node *cgraph_master_clone (struct cgraph_node *, bool);
 void cgraph_add_new_function (tree);
 
 /* In cgraphunit.c  */
Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 116385)
+++ tree-pass.h	(working copy)
@@ -308,6 +308,7 @@ extern struct tree_opt_pass pass_reset_c
 
 /* IPA Passes */
 extern struct tree_opt_pass pass_ipa_cp;
+extern struct tree_opt_pass pass_ipa_lto_out;
 extern struct tree_opt_pass pass_ipa_inline;
 extern struct tree_opt_pass pass_early_ipa_inline;
 extern struct tree_opt_pass pass_ipa_reference;
Index: ipa-reference.c
===================================================================
--- ipa-reference.c	(revision 116385)
+++ ipa-reference.c	(working copy)
@@ -622,7 +622,7 @@ propagate_bits (struct cgraph_node *x)
       struct cgraph_node *y = e->callee;
 
       /* Only look at the master nodes and skip external nodes.  */
-      y = cgraph_master_clone (y);
+      y = cgraph_master_clone (y, true);
       if (y)
 	{
 	  if (get_reference_vars_info_from_cgraph (y))
@@ -707,7 +707,7 @@ merge_callee_local_info (struct cgraph_n
 	  ipa_reference_local_vars_info_t y_l;
 	  struct cgraph_node* orig_y = y;
 	 
-	  y = cgraph_master_clone (y);
+	  y = cgraph_master_clone (y, true);
 	  if (y)
 	    {
 	      y_info = get_reference_vars_info_from_cgraph (y);
@@ -920,7 +920,7 @@ static_execute (void)
   */
   for (node = cgraph_nodes; node; node = node->next)
     if (node->analyzed 
-	&& (cgraph_is_master_clone (node)
+	&& (cgraph_is_master_clone (node, true)
 	    || (cgraph_function_body_availability (node) 
 		== AVAIL_OVERWRITABLE)))
       analyze_function (node);
Index: lto-out-dwarf.c
===================================================================
--- lto-out-dwarf.c	(revision 0)
+++ lto-out-dwarf.c	(revision 0)
@@ -0,0 +1,2291 @@
+/* Writing gimple to .o file.
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "toplev.h"
+#include "tree.h"
+#include "expr.h"
+#include "flags.h"
+#include "params.h"
+#include "input.h"
+#include "varray.h"
+#include "hashtab.h"
+#include "langhooks.h"
+#include "basic-block.h"
+#include "tree-iterator.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
+#include "cgraph.h"
+#include "function.h"
+#include "ggc.h"
+#include "diagnostic.h"
+#include "except.h"
+#include "debug.h"
+#include "timevar.h"
+#include "dwarf2.h"
+#include "lto-dwarf.h"
+
+/* Various abbrev offsets that have been generated.  */
+static unsigned int eh_form_abbrev_table[DW_TAG_gimple_eh_table_count * 2 * 2];
+static unsigned int expr_form_abbrev_table[DW_TAG_gimple_expr_table_count];
+static unsigned int stmt_form_abbrev_table[DW_TAG_gimple_stmt_table_count];
+static unsigned int complex_cst_form_abbrev_table[2];
+static unsigned int vector_cst_form_abbrev_table[2];
+static unsigned int call_form_abbrev_table[2];
+static unsigned int return_form_abbrev_table[3];
+static unsigned int case_label_form_abbrev_table[4];
+static unsigned int bit_field_ref_form_abbrev_table[2];
+static unsigned int bb_form_abbrev_table[2];
+static unsigned int set_eh_form_abbrev_table[2];
+static unsigned int expr_to_tag[NUM_TREE_CODES];
+static unsigned int stmt_to_tag[NUM_TREE_CODES];
+static unsigned int eh_main_abbrev_entry;
+static unsigned int main_abbrev_entry;
+
+
+/* The index of the last eh_region seen for an instruction.  The
+   eh_region for an instruction is only emitted if it different from
+   the last instruction.  */
+
+static int last_eh_region_seen;
+
+struct decl_slot {
+  tree t;
+  unsigned int slot_num;
+};
+
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_decl_slot_node (const void *p)
+{
+  const struct decl_slot *ds = (const struct decl_slot *) p;
+  return (hashval_t) DECL_UID (ds->t);
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+
+static int
+eq_decl_slot_node (const void *p1, const void *p2)
+{
+  const struct decl_slot *ds1 =
+    (const struct decl_slot *) p1;
+  const struct decl_slot *ds2 =
+    (const struct decl_slot *) p2;
+
+  return DECL_UID (ds1->t) == DECL_UID (ds2->t);
+}
+
+
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_type_slot_node (const void *p)
+{
+  const struct decl_slot *ds = (const struct decl_slot *) p;
+  return (hashval_t) TYPE_UID (ds->t);
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+
+static int
+eq_type_slot_node (const void *p1, const void *p2)
+{
+  const struct decl_slot *ds1 =
+    (const struct decl_slot *) p1;
+  const struct decl_slot *ds2 =
+    (const struct decl_slot *) p2;
+
+  return TYPE_UID (ds1->t) == TYPE_UID (ds2->t);
+}
+
+
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_label_slot_node (const void *p)
+{
+  const struct decl_slot *ds = (const struct decl_slot *) p;
+  return (hashval_t) LABEL_DECL_UID (ds->t);
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+
+static int
+eq_label_slot_node (const void *p1, const void *p2)
+{
+  const struct decl_slot *ds1 =
+    (const struct decl_slot *) p1;
+  const struct decl_slot *ds2 =
+    (const struct decl_slot *) p2;
+
+  return LABEL_DECL_UID (ds1->t) == LABEL_DECL_UID (ds2->t);
+}
+
+
+struct char_ptr_base
+{
+  char *ptr;
+};
+
+
+/* An incore byte stream to buffer the various parts of the
+function. The entire structure should be zeroed when created.  The
+record consists of a set of blocks.  The first sizeof (ptr) bytes are
+used as a chain, and the rest store the bytes to be written.  */
+
+struct output_stream
+{
+  /* The pointer to the first block in the stream.  */
+  struct char_ptr_base * first_block;
+  /* The pointer to the last and current block in the stream.  */
+  struct char_ptr_base * current_block;
+  /* The pointer to where the next char should be written.  */
+  char * current_pointer;
+  /* The number of characters left in the current block.  */
+  unsigned int left_in_block;
+  /* The block size of the last block allocated.  */
+  unsigned int block_size;
+  /* The total number of characters written.  */
+  unsigned int total_size;
+};
+
+struct output_block
+{
+  /* The stream that the header is written to.  */
+  struct output_stream header_stream;
+  /* The stream that the main tree codes are written to.  */
+  struct output_stream main_stream;
+  /* The stream that contains the string table.  */
+  struct output_stream string_stream;
+  /* The stream that contains the name table.  */
+  struct output_stream name_stream;
+  /* The stream that contains the type table.  */
+  struct output_stream type_stream;
+
+  /* The hash table that contains the set of variable names we have
+     seen so far and the indexs assigned to them.  */
+  htab_t name_hash_table;
+  unsigned int next_name_index;
+
+  /* The hash table that contains the set of type we have seen so far
+     and the indexs assigned to them.  */
+  htab_t type_hash_table;
+  unsigned int next_type_index;
+
+  /* The hash table that contains the set of labels we have seen so
+     far and the indexs assigned to them.  */
+  htab_t label_hash_table;
+  unsigned int next_label_index;
+};
+
+/* The output stream that contains the abbrev table for all of the
+   functions in this compilation unit.  */
+static struct output_stream abbrev_stream;
+static unsigned int next_abbrev_index;
+static void output_expr_operand (struct output_block *, tree);
+
+/* Write all of the chars in OBS to F.  Recycle the blocks in obs as
+   this is being done.  */
+
+static void
+write_stream (struct output_stream *obs, FILE *f)
+{
+  unsigned int block_size = 1024;
+  unsigned int num_chars;
+  struct char_ptr_base *block;
+  if (!obs->first_block)
+    return;
+
+  block = obs->first_block;
+  while (block)
+    {
+      const char *base = ((char *)block) + sizeof (struct char_ptr_base);
+      struct char_ptr_base *old_block = block;
+      block = (struct char_ptr_base *)block->ptr;
+      /* If there is a next block, then this one is full, if there is
+	 not a next block, then the left_in_block field says how many
+	 chars there are in this block.  */
+      num_chars = block_size - sizeof (struct char_ptr_base);
+      if (!block)
+	num_chars = num_chars - obs->left_in_block;
+      fwrite (base, num_chars, 1, f);
+
+      free (old_block);
+      block_size *= 2;
+    }
+}
+
+
+/* Write a character to the output block.  */
+
+static void
+output_1_stream (struct output_stream *obs, char c)
+{
+  /* No space left.  */
+  if (obs->left_in_block == 0)
+    {
+      struct char_ptr_base *new_block;
+
+      if (obs->first_block == NULL)
+	{
+	  /* This is the first time the stream has been written
+	     into.  */
+	  obs->block_size = 1024;
+	  new_block = (struct char_ptr_base*) xmalloc (obs->block_size);
+	  obs->first_block = new_block;
+	}
+      else
+	{
+	  struct char_ptr_base *tptr;
+	  /* Get a new block that is twice as big as the last block
+	     and link it into the list.  */
+	  obs->block_size *= 2;
+	  new_block = (struct char_ptr_base*) xmalloc (obs->block_size);
+	  /* The first bytes of the block are reserved as a pointer to
+	     the next block.  Set the chain of the full block to the
+	     pointer to the new block.  */
+	  tptr = obs->current_block;
+	  tptr->ptr = (char *)new_block;
+	}
+
+      /* Set the place for the next char at the first position after the
+	 chain to the next block.  */
+      obs->current_pointer = ((char *)new_block) + sizeof (struct char_ptr_base);
+      obs->current_block = new_block;
+      /* Null out the newly allocated block's pointer to the next block.  */
+      new_block->ptr = NULL;
+      obs->left_in_block = obs->block_size - sizeof (struct char_ptr_base);
+    }
+
+  /* Write the actual character.  */
+  *obs->current_pointer = c;
+  obs->current_pointer++;
+  obs->total_size++;
+  obs->left_in_block--;
+}
+
+
+/* Output a two byte integer I to OBS.  */
+
+static void
+output_2_stream (struct output_stream *obs, unsigned int i)
+{
+  if (BYTES_BIG_ENDIAN)
+    {
+      output_1_stream (obs, (i >> 8) & 0xff);
+      output_1_stream (obs, i & 0xff);
+    }
+  else
+    {
+      output_1_stream (obs, i & 0xff);
+      output_1_stream (obs, (i >> 8) & 0xff);
+    }
+}
+
+
+/* Output a two byte integer I to OBS.  */
+
+static void
+output_4_stream (struct output_stream *obs, unsigned long i)
+{
+  if (BYTES_BIG_ENDIAN)
+    {
+      output_1_stream (obs, (i >> 24) & 0xff);
+      output_1_stream (obs, (i >> 16) & 0xff);
+      output_1_stream (obs, (i >> 8) & 0xff);
+      output_1_stream (obs, i & 0xff);
+    }
+  else
+    {
+      output_1_stream (obs, i & 0xff);
+      output_1_stream (obs, (i >> 8) & 0xff);
+      output_1_stream (obs, (i >> 16) & 0xff);
+      output_1_stream (obs, (i >> 24) & 0xff);
+    }
+}
+
+
+/* Write a zero to the output stream.  */
+
+static void
+output_zero (struct output_block *ob)
+{
+  output_1_stream (&ob->main_stream, 0);
+}
+
+
+/* Output a unsigned LEB128 quantity to OBS.  */
+
+static void
+output_uleb128_stream (struct output_stream *obs, unsigned HOST_WIDE_INT work)
+{
+  do
+    {
+      int byte = (work & 0x7f);
+      work >>= 7;
+      if (work != 0)
+	/* More bytes to follow.  */
+	byte |= 0x80;
+
+      output_1_stream (obs, byte);
+    }
+  while (work != 0);
+}
+
+
+/* Output a unsigned LEB128 quantity to OB->main_stream.  */
+
+static void
+output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work)
+{
+  output_uleb128_stream (&ob->main_stream, work);
+}
+
+
+/* Output a signed LEB128 quantity.  */
+
+static void
+output_sleb128_stream (struct output_stream *obs, HOST_WIDE_INT work)
+{
+  int more, byte;
+  do
+    {
+      byte = (work & 0x7f);
+      /* arithmetic shift */
+      work >>= 7;
+      more = !((work == 0 && (byte & 0x40) == 0)
+	       || (work == -1 && (byte & 0x40) != 0));
+      if (more)
+	byte |= 0x80;
+
+      output_1_stream (obs, byte);
+    }
+  while (more);
+}
+
+
+/* Output STRING of LEN to the string table in OB and return the
+   offset in the table.  */
+
+static unsigned int
+output_string (struct output_block *ob, const char *string, unsigned int len)
+{
+  struct output_stream *string_stream = &ob->string_stream;
+  unsigned int start = string_stream->total_size;
+  unsigned int i;
+
+  output_uleb128_stream (string_stream, len);
+  for (i=0; i<len; i++)
+    output_1_stream (string_stream, string[i]);
+  return start;
+}
+
+
+/* Put out a real constant.  */
+
+static void
+output_real (struct output_block *ob, tree t)
+{
+  static char real_buffer[1000];
+  const REAL_VALUE_TYPE *r = &TREE_REAL_CST (t);
+  unsigned int index;
+
+  real_to_hexadecimal (real_buffer, r, 1000, 0, 1);
+  index = output_string (ob, real_buffer, strlen (real_buffer));
+  output_uleb128 (ob, index);
+}
+
+
+/* Put out a integer constant.  These are stored as two HOST_WIDE_INTS
+   so games may have to be played to shift the data from the high to
+   the low value.  */
+
+static void
+output_integer (struct output_block *ob, tree t)
+{
+  struct output_stream *obs = &ob->main_stream;
+  HOST_WIDE_INT low = TREE_INT_CST_LOW (t);
+  HOST_WIDE_INT high = TREE_INT_CST_HIGH (t);
+  int more, byte;
+
+  /* Of course if the high value is just sign bits for the signed low
+     value, we can just punt and call output_sleb128 and be done with
+     it.  */
+  if (((high == -1) && (low < 0))
+      || ((high == 0) && (low >= 0)))
+    {
+      output_sleb128_stream (obs, low);
+      return;
+    }
+
+  /* This is just a copy of the output_sleb128 code with extra
+     operations to transfer the low 7 bits of the high value to the
+     top 7 bits of the low value, shift the high down by 7 and then do
+     a slightly more complex exit test.  */
+  do
+    {
+      int transfer = (high & 0x7f);
+      high >>= 7;
+      transfer <<= (HOST_BITS_PER_INT - 7);
+
+      byte = (low & 0x7f);
+
+      /* Logical shift.  */
+      low = ((unsigned HOST_WIDE_INT)low) >> 7;
+      low |= transfer;
+      more = !((high == 0 && low == 0 && (byte & 0x40) == 0)
+	       || (high == -1 && low == -1 && (byte & 0x40) != 0));
+      if (more)
+	byte |= 0x80;
+
+      output_1_stream (obs, byte);
+    }
+  while (more);
+}
+
+
+/* Generate the start of an abbrev entry for TAG with HAS_CHILDREN.
+   Note that the 0 abbrev is reserved.  */
+
+static unsigned int
+gen_abbrev_entry_tag (unsigned int tag, unsigned int has_children)
+{
+  output_uleb128_stream (&abbrev_stream, ++next_abbrev_index);
+  output_uleb128_stream (&abbrev_stream, tag);
+  output_uleb128_stream (&abbrev_stream, has_children);
+  return next_abbrev_index;
+}
+
+
+/* Generate a record in an a abbrev table entry for attribute AT of
+   FORM.  */
+static void
+gen_abbrev_entry_attr (unsigned int at, unsigned int form)
+{
+  output_uleb128_stream (&abbrev_stream, at);
+  output_uleb128_stream (&abbrev_stream, form);
+}
+
+
+/* Generate the start of an abbrev entry for TAG with HAS_CHILDREN.
+   Note that the 0 abbrev is reserved.  */
+
+static void
+gen_abbrev_entry_end (void)
+{
+  output_1_stream (&abbrev_stream, 0);
+  output_1_stream (&abbrev_stream, 0);
+}
+
+
+/* Output the abbrev reference VALUE to the main stream of OB.  */
+
+static void
+output_abbrev_ref (struct output_block *ob, unsigned int value)
+{
+  output_uleb128 (ob, value);
+}
+
+
+/* Lookup NAME in TABLE.  If NAME is not found, create a new entry in
+   TABLE for NAME with NEXT_INDEX and increment NEXT_INDEX.  Then
+   print the index to OBS.  True is returned if NAME was added to the
+   table.  */
+
+static bool
+output_decl_index (struct output_stream * obs, htab_t table,
+		   unsigned int *next_index, tree name)
+{
+  void **slot;
+  struct decl_slot d_slot;
+  d_slot.t = name;
+
+  slot = htab_find_slot (table, &d_slot, INSERT);
+  if (*slot == NULL)
+    {
+      struct decl_slot *new_slot = xmalloc (sizeof (struct decl_slot));
+      int index = *next_index++;
+      new_slot->t = name;
+      new_slot->slot_num = index;
+      *slot = new_slot;
+      output_uleb128_stream (obs, index);
+      return true;
+    }
+  else
+    {
+      struct decl_slot *old_slot = (struct decl_slot *)*slot;
+      output_uleb128_stream (obs, old_slot->slot_num);
+      return false;
+    }
+}
+
+
+/* Build a densely packed word that contains only the flags that are
+   used for this type of tree EXPR and write the word in uleb128 to
+   the OB.  */
+
+
+static void
+output_tree_flags (struct output_block *ob, tree expr)
+{
+  int flags = 0;
+
+#define ADD_BASE_FLAG(flag_name) { flags <<= 1; if (expr->common. flag_name ) flags |= 1; }
+#include "lto-tree-flags.def"
+#undef ADD_BASE_FLAG
+
+  output_uleb128 (ob, flags);
+}
+
+
+/* Look up TYPE in the type table and write the uleb128 index for it.
+   This is a hack and will be replaced with a real reference to the
+   type.  */
+
+static void
+output_type_ref (struct output_block *ob, tree node)
+{
+  bool new = output_decl_index (&ob->main_stream, ob->type_hash_table,
+				&ob->next_type_index, node);
+  if (new)
+    {
+      unsigned int index = 0;
+      if (TYPE_NAME (node))
+	{
+	  if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
+	    index = output_string (ob,
+				   IDENTIFIER_POINTER (TYPE_NAME (node)),
+				   IDENTIFIER_LENGTH (TYPE_NAME (node)));
+	  else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
+		   && DECL_NAME (TYPE_NAME (node)))
+	    index = output_string (ob,
+				   IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))),
+				   IDENTIFIER_LENGTH (DECL_NAME (TYPE_NAME (node))));
+	  else
+	    gcc_unreachable ();
+	}
+      else
+	{
+	  char * buffer = xmalloc (100);
+	  sprintf (buffer, "type.%d", TYPE_UID (node));
+	  index = output_string (ob, buffer, strlen (buffer));
+	  free (buffer);
+	}
+      output_uleb128_stream (&ob->type_stream, index);
+    }
+}
+
+
+/* Look up NAME in the type table and write the uleb128 index for it.  */
+
+static void
+output_name_ref (struct output_block *ob, tree name)
+{
+  bool new = output_decl_index (&ob->main_stream, ob->name_hash_table,
+				&ob->next_name_index, name);
+  if (new)
+    {
+      unsigned int index;
+      if (DECL_NAME (name))
+	{
+	  const char * sname = IDENTIFIER_POINTER (DECL_NAME (name));
+	  index = output_string (ob, sname, strlen (sname));
+	}
+      else
+	{
+	  char * buffer = xmalloc (100);
+	  sprintf (buffer, "%c.%u",
+		   TREE_CODE (name) == CONST_DECL ? 'C' : 'D',
+		   DECL_UID (name));
+	  index = output_string (ob, buffer, strlen (buffer));
+	  free (buffer);
+	}
+      output_uleb128_stream (&ob->name_stream, index);
+    }
+}
+
+
+/* Look up LABEL in the type table and write the uleb128 index for it.  */
+
+static void
+output_label_ref (struct output_block *ob, tree label)
+{
+  output_decl_index (&ob->main_stream, ob->label_hash_table,
+		     &ob->next_label_index, label);
+}
+
+
+/* Output a LIST of TYPE_DECLS.  */
+
+static void
+output_type_list (struct output_block *ob, tree list)
+{
+  tree tl;
+  int count = 0;
+  if (list)
+    {
+      gcc_assert (TREE_CODE (list) == TREE_LIST);
+      for (tl = list; tl; tl = TREE_CHAIN (tl))
+	count++;
+      
+      output_uleb128 (ob, count);
+      for (tl = list; tl; tl = TREE_CHAIN (tl))
+	output_type_ref (ob, TREE_VALUE (tl));
+    }
+  else
+    output_zero (ob);
+}
+
+
+/* Find, or generate, if there is not one already, the abbrev table
+   entries for the various eh_table forms.  There are possibly four
+   entries for each form depending on the values HAS_INNER and
+   MAY_CONTAIN_THROW.  */
+
+static int
+get_eh_form (unsigned int tag, bool has_inner, bool may_contain_throw)
+{
+  int index = ((tag - DW_TAG_gimple_eh_table_first) << 2)
+    + (has_inner?2:0) + (may_contain_throw);
+  int entry = eh_form_abbrev_table[index];
+
+  if (entry)
+    return entry;
+  entry = gen_abbrev_entry_tag (tag, has_inner ? DW_children_yes: DW_children_no);
+  gen_abbrev_entry_attr (DF_AT_gimple_eh_region_number, DW_FORM_udata);
+  if (may_contain_throw)
+    gen_abbrev_entry_attr (DF_AT_gimple_eh_may_contain_throw, DW_FORM_const_true);
+  else
+    gen_abbrev_entry_attr (DF_AT_gimple_eh_may_contain_throw, DW_FORM_const_false);
+
+  switch (tag)
+    {
+    case DW_TAG_gimple_eh_table_cleanup:
+      gen_abbrev_entry_attr (DF_AT_gimple_eh_prev_try, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_eh_table_try:
+      gen_abbrev_entry_attr (DF_AT_gimple_eh_catch, DW_FORM_udata);
+      gen_abbrev_entry_attr (DF_AT_gimple_eh_last_catch, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_eh_table_catch:
+      gen_abbrev_entry_attr (DF_AT_gimple_eh_next_catch, DW_FORM_udata);
+      gen_abbrev_entry_attr (DF_AT_gimple_eh_prev_catch, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_eh_table_allowed:
+      gen_abbrev_entry_attr (DF_AT_gimple_eh_allowed_exceptions,
+			     DW_FORM_udata_list);
+      break;
+
+    case DW_TAG_gimple_eh_table_must_not_throw:
+      break;
+
+    default:
+      gcc_unreachable ();
+      break;
+    }
+  gen_abbrev_entry_end ();
+
+  eh_form_abbrev_table[index] = entry;
+  return entry;
+}
+
+
+/* Find, or generate, if there is not one already, the abbrev table
+   entries for the various expr_table forms.  The forms in the case
+   statement here must EXACTLY MATCH the forms in the case statement
+   in output_expr_operands.  */
+
+static int
+get_expr_form (unsigned int tag)
+{
+  int index = tag - DW_TAG_gimple_expr_table_first;
+  int entry = expr_form_abbrev_table[index];
+
+  if (entry)
+    return entry;
+
+  switch (tag)
+    {
+    case DW_TAG_gimple_integer_cst:
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_cst_int, DW_FORM_sdata);
+      break;
+
+    case DW_TAG_gimple_real_cst:
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_cst_real, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_string_cst:
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_cst_string, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_ssa_name:
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      gen_abbrev_entry_attr (DW_AT_gimple_ssa_name, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_ssa_name_version, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_constructor:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      break;
+
+    case DW_TAG_gimple_constructor_range:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      gen_abbrev_entry_attr (DW_AT_gimple_range_low, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_range_high, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_const_decl:
+    case DW_TAG_gimple_field_decl:
+    case DW_TAG_gimple_function_decl:
+    case DW_TAG_gimple_parm_decl:
+    case DW_TAG_gimple_var_decl:
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_decl, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_result_decl:
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_label_decl:
+    case DW_TAG_gimple_label_expr:
+      /* Labels do not have a type.  */
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_label, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_component_ref:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      /* Operand 1.  */
+      gen_abbrev_entry_attr (DW_AT_gimple_decl, DW_FORM_udata);
+      /* Ignore operand 2 because it can be recomputed.  */
+      break;
+
+    case DW_TAG_gimple_nop_expr:
+    case DW_TAG_gimple_convert_expr:
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_exc_ptr_expr:
+    case DW_TAG_gimple_filter_expr:
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_abs_expr:
+    case DW_TAG_gimple_addr_expr:
+    case DW_TAG_gimple_align_indirect_ref:
+    case DW_TAG_gimple_bit_not_expr:
+    case DW_TAG_gimple_conj_expr:
+    case DW_TAG_gimple_fix_ceil_expr:
+    case DW_TAG_gimple_fix_floor_expr:
+    case DW_TAG_gimple_fix_round_expr:
+    case DW_TAG_gimple_fix_trunc_expr:
+    case DW_TAG_gimple_float_expr:
+    case DW_TAG_gimple_goto_expr:
+    case DW_TAG_gimple_imagpart_expr:
+    case DW_TAG_gimple_indirect_ref:
+    case DW_TAG_gimple_misaligned_indirect_ref:
+    case DW_TAG_gimple_negate_expr:
+    case DW_TAG_gimple_non_lvalue_expr:
+    case DW_TAG_gimple_realpart_expr:
+    case DW_TAG_gimple_reduc_max_expr:
+    case DW_TAG_gimple_reduc_min_expr:
+    case DW_TAG_gimple_reduc_plus_expr:
+    case DW_TAG_gimple_truth_not_expr:
+    case DW_TAG_gimple_view_convert_expr:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_array_ref:
+    case DW_TAG_gimple_array_range_ref:
+      /* Ignore operands 3 and 4 for ARRAY_REF and ARRAY_RANGE REF
+	 because they can be recomputed.  */
+
+    case DW_TAG_gimple_with_size_expr:
+      /* WITH_SIZE_EXPR is a pass-through reference to its first
+	 argument, and an rvalue reference to its second argument.  */
+
+      /* All of the binary expressions and their friends.  */
+    case DW_TAG_gimple_assert_expr:
+    case DW_TAG_gimple_bit_and_expr:
+    case DW_TAG_gimple_bit_ior_expr:
+    case DW_TAG_gimple_bit_xor_expr:
+    case DW_TAG_gimple_ceil_div_expr:
+    case DW_TAG_gimple_ceil_mod_expr:
+    case DW_TAG_gimple_complex_expr:
+    case DW_TAG_gimple_compound_expr:
+    case DW_TAG_gimple_eq_expr:
+    case DW_TAG_gimple_exact_div_expr:
+    case DW_TAG_gimple_floor_div_expr:
+    case DW_TAG_gimple_floor_mod_expr:
+    case DW_TAG_gimple_ge_expr:
+    case DW_TAG_gimple_gt_expr:
+    case DW_TAG_gimple_le_expr:
+    case DW_TAG_gimple_lrotate_expr:
+    case DW_TAG_gimple_lshift_expr:
+    case DW_TAG_gimple_lt_expr:
+    case DW_TAG_gimple_ltgt_expr:
+    case DW_TAG_gimple_max_expr:
+    case DW_TAG_gimple_min_expr:
+    case DW_TAG_gimple_minus_expr:
+    case DW_TAG_gimple_mult_expr:
+    case DW_TAG_gimple_ne_expr:
+    case DW_TAG_gimple_obj_type_ref:
+    case DW_TAG_gimple_ordered_expr:
+    case DW_TAG_gimple_plus_expr:
+    case DW_TAG_gimple_range_expr:
+    case DW_TAG_gimple_rdiv_expr:
+    case DW_TAG_gimple_round_div_expr:
+    case DW_TAG_gimple_round_mod_expr:
+    case DW_TAG_gimple_rrotate_expr:
+    case DW_TAG_gimple_rshift_expr:
+    case DW_TAG_gimple_trunc_div_expr:
+    case DW_TAG_gimple_trunc_mod_expr:
+    case DW_TAG_gimple_truth_and_expr:
+    case DW_TAG_gimple_truth_or_expr:
+    case DW_TAG_gimple_truth_xor_expr:
+    case DW_TAG_gimple_uneq_expr:
+    case DW_TAG_gimple_unge_expr:
+    case DW_TAG_gimple_ungt_expr:
+    case DW_TAG_gimple_unle_expr:
+    case DW_TAG_gimple_unlt_expr:
+    case DW_TAG_gimple_unordered_expr:
+    case DW_TAG_gimple_vec_lshift_expr:
+    case DW_TAG_gimple_vec_rshift_expr:
+    case DW_TAG_gimple_widen_mult_expr:
+    case DW_TAG_gimple_widen_sum_expr:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      break;
+
+      /* For BIT field ref, generate the default abbrev which assumes
+	 that operands 1 and 2 are trees and let the case DW_TAG_gimple_try to
+	 optimize this.  */
+    case DW_TAG_gimple_bit_field_ref:
+    case DW_TAG_gimple_cond_expr:
+    case DW_TAG_gimple_dot_prod_expr:
+    case DW_TAG_gimple_realign_load_expr:
+    case DW_TAG_gimple_vec_cond_expr:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      break;
+
+    default:
+      gcc_unreachable ();
+      break;
+    }
+
+  gen_abbrev_entry_end ();
+
+  expr_form_abbrev_table[index] = entry;
+  return entry;
+}
+
+
+/* Find, or generate, if there is not one already, the abbrev table
+   entries for the various stmt_table forms.  The forms in the case
+   statement here must EXACTLY MATCH the forms in the case statement
+   in output_stmt_operands.  */
+
+static int
+get_stmt_form (unsigned int tag)
+{
+  int index = tag - DW_TAG_gimple_stmt_table_first;
+  int entry = stmt_form_abbrev_table[index];
+
+  if (entry)
+    return entry;
+
+  switch (tag)
+    {
+    case DW_TAG_gimple_asm_expr:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_cst_string, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_asm_inputs:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      break;
+
+    case DW_TAG_gimple_asm_outputs:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      break;
+
+    case DW_TAG_gimple_asm_clobbers:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      break;
+
+    case DW_TAG_gimple_case_label_expr:
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_label, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_modify_expr:
+    case DW_TAG_gimple_return_expr:
+    case DW_TAG_gimple_switch_expr:
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      break;
+
+    case DW_TAG_gimple_resx_expr:
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      gen_abbrev_entry_attr (DW_AT_gimple_cst_int, DW_FORM_udata);
+      break;
+
+    default:
+      gcc_unreachable ();
+      break;
+    }
+  gen_abbrev_entry_end ();
+
+  stmt_form_abbrev_table[index] = entry;
+  return entry;
+}
+
+
+/* Find, or generate, if there is not one already, the abbrev table
+   entries for two expr_table forms.  In each of these cases, there is
+   a general (worst case form) and a SPECIAL form where some of the
+   inputs can be omitted.  */
+
+static int
+get_form_special (unsigned int tag, unsigned int variant)
+{
+  unsigned int entry = 0;
+  switch (tag)
+    {
+    case DW_TAG_gimple_case_label_expr:
+      entry = case_label_form_abbrev_table[variant];
+      if (entry)
+	return entry;
+
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      if (variant & 0x1)
+	gen_abbrev_entry_attr (DW_AT_gimple_case_low, DW_FORM_sdata);
+      if (variant & 0x2)
+	gen_abbrev_entry_attr (DW_AT_gimple_case_high, DW_FORM_sdata);
+
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      case_label_form_abbrev_table[variant] = entry;
+      break;
+
+    case DW_TAG_gimple_complex_cst:
+      entry = complex_cst_form_abbrev_table[variant];
+      if (entry)
+	return entry;
+
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      if (variant)
+	{
+	  gen_abbrev_entry_attr (DW_AT_gimple_is_real, DW_FORM_const_true);
+	  gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_cst_real, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_cst_real, DW_FORM_udata);
+	}
+      else
+	{
+	  gen_abbrev_entry_attr (DW_AT_gimple_is_real, DW_FORM_const_false);
+	  gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_cst_int, DW_FORM_sdata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_cst_int, DW_FORM_sdata);
+	}
+
+      complex_cst_form_abbrev_table[variant] = entry;
+      break;
+
+    case DW_TAG_gimple_vector_cst:
+      entry = vector_cst_form_abbrev_table[variant];
+      if (entry)
+	return entry;
+
+      entry = gen_abbrev_entry_tag (tag, DW_children_no);
+      if (variant)
+	{
+	  gen_abbrev_entry_attr (DW_AT_gimple_is_real, DW_FORM_const_true);
+	  gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_cst_real, DW_FORM_udata_list);
+	}
+      else
+	{
+	  gen_abbrev_entry_attr (DW_AT_gimple_is_real, DW_FORM_const_false);
+	  gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_cst_int, DW_FORM_sdata_list);
+	}
+
+      vector_cst_form_abbrev_table[variant] = entry;
+      break;
+
+    case DW_TAG_gimple_call_expr:
+      entry = call_form_abbrev_table[variant];
+
+      if (entry)
+	return entry;
+
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      if (variant == 0)
+	gen_abbrev_entry_attr (DW_AT_gimple_decl, DW_FORM_udata);
+      call_form_abbrev_table[variant] = entry;
+      break;
+
+    case DW_TAG_gimple_bit_field_ref:
+      entry = bit_field_ref_form_abbrev_table[variant];
+
+      if (entry)
+	return entry;
+
+      entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+#if STUPID_TYPE_SYSTEM
+      gen_abbrev_entry_attr (DW_AT_gimple_type, DW_FORM_udata);
+#endif
+      gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+      if (variant)
+	{
+	  gen_abbrev_entry_attr (DW_AT_gimple_bit_num, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DW_AT_gimple_bit_start, DW_FORM_udata);
+	}
+      bit_field_ref_form_abbrev_table[variant] = entry;
+      break;
+
+    case DW_TAG_gimple_return_expr:
+      entry = return_form_abbrev_table[variant];
+
+      if (entry)
+	return entry;
+
+      switch (variant)
+	{
+	case 0:
+	  /* Return nothing.  */
+	  entry = gen_abbrev_entry_tag (tag, DW_children_no);
+	  gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+	  break;
+	case 1:
+	  /* Return x.  */
+	  entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+	  gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DF_AT_gimple_return_assign,
+				 DW_FORM_const_false);
+	  break;
+	case 2:
+	  /* Return x = y.  */
+	  entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+	  gen_abbrev_entry_attr (DW_AT_gimple_tree_flags, DW_FORM_udata);
+	  gen_abbrev_entry_attr (DF_AT_gimple_return_assign,
+				 DW_FORM_const_true);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      return_form_abbrev_table[variant] = entry;
+
+      break;
+
+    case DW_TAG_gimple_bb:
+      entry = bb_form_abbrev_table[variant];
+
+      if (entry)
+	return entry;
+
+      if (variant)
+	entry
+	  = gen_abbrev_entry_tag (tag,
+				  variant ? DW_children_yes : DW_children_no);
+
+      /* There are two counted lists for the edges, the first is the
+	 successor index and the next is the edge flags.  */
+      gen_abbrev_entry_attr (DF_AT_gimple_bb_succs, DW_FORM_udata_list);
+      gen_abbrev_entry_attr (DF_AT_gimple_bb_edge_flags, DW_FORM_udata_list);
+      bb_form_abbrev_table[variant] = entry;
+
+      break;
+
+    case DW_TAG_gimple_eh_table:
+      if (eh_main_abbrev_entry)
+	return eh_main_abbrev_entry;
+
+      eh_main_abbrev_entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      break;
+
+    case DW_TAG_gimple_function_top:
+      /* Make the abbrev entry for the top level.  */
+      if (main_abbrev_entry)
+	return main_abbrev_entry;
+
+      main_abbrev_entry = gen_abbrev_entry_tag (tag, DW_children_yes);
+      /* These are not encoded in uleb128 because it would be hard to do
+	 the math.  */
+      gen_abbrev_entry_attr (DW_AT_main_offset,   DW_FORM_data4);
+      gen_abbrev_entry_attr (DW_AT_main_size,     DW_FORM_data4);
+      gen_abbrev_entry_attr (DW_AT_string_offset, DW_FORM_data4);
+      gen_abbrev_entry_attr (DW_AT_string_size,   DW_FORM_data4);
+      gen_abbrev_entry_attr (DW_AT_name_offset,   DW_FORM_data4);
+      gen_abbrev_entry_attr (DW_AT_name_size,     DW_FORM_data4);
+      gen_abbrev_entry_attr (DW_AT_type_offset,   DW_FORM_data4);
+      gen_abbrev_entry_attr (DW_AT_type_size,     DW_FORM_data4);
+      break;
+
+
+    default:
+      gcc_unreachable ();
+    }
+
+  gen_abbrev_entry_end ();
+
+  return entry;
+}
+
+
+/* Find, or generate, if there is not one already, the abbrev table
+   entries for setting the eh_region of stmt.  There are two flavors,
+   depending on if the region is 0 or not.  */
+
+static int
+get_set_eh_form (unsigned int region)
+{
+  int index = region?1:0;
+  if (set_eh_form_abbrev_table[index])
+    return set_eh_form_abbrev_table[index];
+
+  set_eh_form_abbrev_table[index]
+    = gen_abbrev_entry_tag (DW_TAG_gimple_set_eh, DW_children_no);
+  if (region)
+    gen_abbrev_entry_attr (DF_AT_gimple_eh_region_number, DW_FORM_udata);
+  gen_abbrev_entry_end ();
+
+  return set_eh_form_abbrev_table[index];
+}
+
+
+/* Output an eh_cleanup region with REGION_NUMBER.  HAS_INNER is true if
+   there are children of this node and HAS_PEER is true if there are
+   siblings of this node.  MAY_CONTAIN_THROW and PREV_TRY are the
+   fields of the eh_region.  */
+
+static void
+output_eh_cleanup (void *obv,
+		   unsigned int region_number,
+		   bool has_inner, bool has_peer,
+		   bool may_contain_throw, unsigned int prev_try)
+{
+  struct output_block *ob = (struct output_block*)obv;
+  output_abbrev_ref (ob, get_eh_form (DW_TAG_gimple_eh_table_cleanup,
+				      has_inner,
+				      may_contain_throw));
+  output_uleb128 (ob, region_number);
+  output_uleb128 (ob, prev_try);
+  if (!has_peer)
+    output_zero (ob);
+}
+
+
+/* Output an eh_try region with REGION_NUMBER.  HAS_INNER is true if
+   there are children of this node and HAS_PEER is true if there are
+   siblings of this node.  MAY_CONTAIN_THROW, CATCH and LAST_CATCH are
+   the fields of the eh_region.  */
+
+static void
+output_eh_try (void *obv,
+	       unsigned int region_number,
+	       bool has_inner, bool has_peer,
+	       bool may_contain_throw, unsigned int catch,
+	       unsigned int last_catch)
+{
+  struct output_block *ob = (struct output_block*)obv;
+  output_abbrev_ref (ob, get_eh_form (DW_TAG_gimple_eh_table_try,
+				  has_inner,
+				  may_contain_throw));
+  output_uleb128 (ob, region_number);
+  output_uleb128 (ob, catch);
+  output_uleb128 (ob, last_catch);
+  if (!has_peer)
+    output_zero (ob);
+}
+
+
+/* Output an eh_catch region with REGION_NUMBER.  HAS_INNER is true if
+   there are children of this node and HAS_PEER is true if there are
+   siblings of this node.  MAY_CONTAIN_THROW, NEXT_CATCH and
+   PREV_CATCH, and TYPE_LIST are the fields of the eh_region.  */
+
+static void
+output_eh_catch (void *obv,
+		 unsigned int region_number,
+		 bool has_inner, bool has_peer,
+		 bool may_contain_throw, unsigned int next_catch,
+		 unsigned int prev_catch, tree type_list)
+{
+  struct output_block *ob = (struct output_block*)obv;
+  output_abbrev_ref (ob, get_eh_form (DW_TAG_gimple_eh_table_catch,
+				      has_inner,
+				      may_contain_throw));
+  output_uleb128 (ob, region_number);
+  output_uleb128 (ob, next_catch);
+  output_uleb128 (ob, prev_catch);
+  output_type_list (ob, type_list);
+  if (!has_peer)
+    output_zero (ob);
+}
+
+/* Output an eh_allowed_exceptions region with REGION_NUMBER.
+   HAS_INNER is true if there are children of this node and HAS_PEER
+   is true if there are siblings of this node.  MAY_CONTAIN_THROW, and
+   TYPE_LIST are the fields of the eh_region.  */
+
+static void
+output_eh_allowed (void *obv,
+		   unsigned int region_number,
+		   bool has_inner, bool has_peer,
+		   bool may_contain_throw, tree type_list)
+{
+  struct output_block *ob = (struct output_block*)obv;
+  output_abbrev_ref (ob,
+		     get_eh_form (DW_TAG_gimple_eh_table_allowed,
+				  has_inner,
+				  may_contain_throw));
+  output_uleb128 (ob, region_number);
+  output_type_list (ob, type_list);
+  if (!has_peer)
+    output_zero (ob);
+}
+
+
+/* Output an eh_must_not_throw region with REGION_NUMBER.  HAS_INNER
+   is true if there are children of this node and HAS_PEER is true if
+   there are siblings of this node.  MAY_CONTAIN_THROW is the field of
+   the eh_region.  */
+
+static void
+output_eh_must_not_throw (void *obv,
+			  unsigned int region_number,
+			  bool has_inner, bool has_peer,
+			  bool may_contain_throw)
+{
+  struct output_block *ob = (struct output_block*)obv;
+  output_abbrev_ref (ob,
+		     get_eh_form (DW_TAG_gimple_eh_table_must_not_throw,
+				  has_inner,
+				  may_contain_throw));
+  output_uleb128 (ob, region_number);
+  if (!has_peer)
+    output_zero (ob);
+}
+
+
+/* Output the existing eh_table to OB.  */
+
+static void
+output_eh_regions (struct output_block *ob, struct function *cfun)
+{
+  if (cfun->eh)
+    {
+      output_abbrev_ref (ob, get_form_special (DW_TAG_gimple_eh_table, 0));
+      output_eh_records (ob, cfun,
+			 output_eh_cleanup,
+			 output_eh_try,
+			 output_eh_catch,
+			 output_eh_allowed,
+			 output_eh_must_not_throw);
+      output_zero (ob);
+    }
+}
+
+
+static void
+output_constructor (struct output_block *ob, tree ctor)
+{
+  tree value;
+  tree purpose;
+  unsigned HOST_WIDE_INT idx;
+
+  output_abbrev_ref (ob, get_expr_form (DW_TAG_gimple_constructor));
+
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
+    {
+      if (TREE_CODE (purpose) == RANGE_EXPR)
+	{
+	  output_abbrev_ref (ob, get_expr_form (DW_TAG_gimple_constructor_range));
+	  output_integer (ob, TREE_OPERAND (purpose, 0));
+	  output_integer (ob, TREE_OPERAND (purpose, 1));
+	}
+
+      switch (TREE_CODE (value))
+	{
+	case CONSTRUCTOR:
+	case INTEGER_CST:
+	case REAL_CST:
+	case STRING_CST:
+	case COMPLEX_CST:
+	case VECTOR_CST:
+	  output_expr_operand (ob, value);
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	  break;
+	}
+
+      /* Close the RANGE_EXPR wrapper.  */
+      if (TREE_CODE (purpose) == RANGE_EXPR)
+ 	output_zero (ob);
+    }
+  output_zero (ob);
+}
+
+/* Output EXPR to the main stream in OB.  */
+
+static void
+output_expr_operand (struct output_block *ob, tree expr)
+{
+  enum tree_code code;
+  enum tree_code_class class;
+  unsigned int tag;
+
+  if (expr == NULL)
+    return;
+
+  code = TREE_CODE (expr);
+  class = TREE_CODE_CLASS (code);
+
+  tag = expr_to_tag [code];
+  if (tag)
+    output_abbrev_ref (ob, get_expr_form (tag));
+
+  gcc_assert (class != tcc_type);
+
+  switch (code)
+    {
+    case COMPLEX_CST:
+      if (TREE_CODE (TREE_REALPART (expr)) == REAL_CST)
+	{
+	  output_abbrev_ref (ob,
+			     get_form_special (DW_TAG_gimple_complex_cst, 1));
+	  output_type_ref (ob, TREE_TYPE (TREE_REALPART (expr)));
+	  output_tree_flags (ob, expr);
+	  output_real (ob, TREE_REALPART (expr));
+	  output_real (ob, TREE_IMAGPART (expr));
+	}
+      else
+	{
+	  output_abbrev_ref (ob,
+			     get_form_special (DW_TAG_gimple_complex_cst, 0));
+	  output_type_ref (ob, TREE_TYPE (TREE_REALPART (expr)));
+	  output_tree_flags (ob, expr);
+	  output_integer (ob, TREE_REALPART (expr));
+	  output_integer (ob, TREE_IMAGPART (expr));
+	}
+      break;
+
+    case INTEGER_CST:
+      output_type_ref (ob, TREE_TYPE (expr));
+      output_tree_flags (ob, expr);
+      output_integer (ob, expr);
+      break;
+
+    case REAL_CST:
+      output_type_ref (ob, TREE_TYPE (expr));
+      output_tree_flags (ob, expr);
+      output_real (ob, expr);
+      break;
+
+    case STRING_CST:
+      {
+	unsigned int index
+	  = output_string (ob, TREE_STRING_POINTER (expr),
+			   TREE_STRING_LENGTH (expr));
+	output_type_ref (ob, TREE_TYPE (expr));
+	output_tree_flags (ob, expr);
+	output_uleb128 (ob, index);
+      }
+      break;
+
+    case VECTOR_CST:
+      {
+	tree t = TREE_VECTOR_CST_ELTS (expr);
+	int len = 1;
+	while ((t = TREE_CHAIN (t)) != NULL)
+	  len++;
+	t = TREE_VECTOR_CST_ELTS (expr);
+	if (TREE_CODE (TREE_VALUE(t)) == REAL_CST)
+	  {
+	    output_abbrev_ref (ob,
+			       get_form_special (DW_TAG_gimple_vector_cst, 1));
+	    output_type_ref (ob, TREE_TYPE (TREE_VALUE (t)));
+	    output_tree_flags (ob, expr);
+	    output_uleb128 (ob, len);
+	    output_real (ob, TREE_VALUE (t));
+	    while ((t = TREE_CHAIN (t)) != NULL)
+	      output_real (ob, TREE_VALUE (t));
+	  }
+	else
+	  {
+	    output_abbrev_ref (ob,
+			       get_form_special (DW_TAG_gimple_vector_cst, 0));
+	    output_type_ref (ob, TREE_TYPE (TREE_VALUE (t)));
+	    output_tree_flags (ob, expr);
+	    output_uleb128 (ob, len);
+	    output_integer (ob, TREE_VALUE (t));
+	    while ((t = TREE_CHAIN (t)) != NULL)
+	      output_integer (ob, TREE_VALUE (t));
+	  }
+      }
+      break;
+
+    case CASE_LABEL_EXPR:
+      {
+	int variant = 0;
+	if (CASE_LOW (expr) != NULL_TREE)
+	  variant |= 0x1;
+	if (CASE_HIGH (expr) != NULL_TREE)
+	  variant |= 0x2;
+	output_abbrev_ref (ob,
+			   get_form_special (DW_TAG_gimple_case_label_expr,
+					     variant));
+	output_tree_flags (ob, expr);
+
+	if (CASE_LOW (expr) != NULL_TREE)
+	  output_integer (ob, CASE_LOW (expr));
+	if (CASE_HIGH (expr) != NULL_TREE)
+	  output_integer (ob, CASE_HIGH (expr));
+	output_expr_operand (ob, CASE_LABEL (expr));
+	output_zero (ob);
+      }
+      break;
+
+    case CONSTRUCTOR:
+      output_constructor (ob, expr);
+      break;
+
+    case SSA_NAME:
+#if STUPID_TYPE_SYSTEM
+      output_type_ref (ob, TREE_TYPE (expr));
+#endif
+      output_tree_flags (ob, expr);
+      output_name_ref (ob, SSA_NAME_VAR (expr));
+      output_uleb128 (ob, SSA_NAME_VERSION (expr));
+      break;
+
+    case CONST_DECL:
+    case FIELD_DECL:
+    case FUNCTION_DECL:
+    case PARM_DECL:
+    case VAR_DECL:
+#if STUPID_TYPE_SYSTEM
+      output_type_ref (ob, TREE_TYPE (expr));
+#endif
+      output_tree_flags (ob, expr);
+      output_name_ref (ob, expr);
+      break;
+
+    case LABEL_DECL:
+      output_tree_flags (ob, expr);
+      output_label_ref (ob, expr);
+      break;
+
+    case LABEL_EXPR:
+      output_tree_flags (ob, expr);
+      output_label_ref (ob, TREE_OPERAND (expr, 0));
+      break;
+
+    case RESULT_DECL:
+      output_tree_flags (ob, expr);
+      break;
+
+    case COMPONENT_REF:
+#if STUPID_TYPE_SYSTEM
+      output_type_ref (ob, TREE_TYPE (expr));
+#endif
+      output_tree_flags (ob, expr);
+      output_expr_operand (ob, TREE_OPERAND (expr, 1));
+      output_expr_operand (ob, TREE_OPERAND (expr, 0));
+      /* Ignore 3 because it can be recomputed.  */
+      output_zero (ob);
+      break;
+
+    case CALL_EXPR:
+      {
+	unsigned int count = TREE_INT_CST_LOW (TREE_OPERAND (expr, 0));
+	unsigned int i;
+
+	if (TREE_OPERAND (expr, 2) == NULL)
+	  output_abbrev_ref (ob, get_form_special (DW_TAG_gimple_call_expr, 1));
+	else
+	  output_abbrev_ref (ob, get_form_special (DW_TAG_gimple_call_expr, 0));
+
+#if STUPID_TYPE_SYSTEM
+	output_type_ref (ob, TREE_TYPE (expr));
+#endif
+	output_tree_flags (ob, expr);
+	if (TREE_OPERAND (expr, 2) != NULL)
+	  output_name_ref (ob, TREE_OPERAND (expr, 2));
+
+	output_expr_operand (ob, TREE_OPERAND (expr, 1));
+	for (i = 3; i < count; i++)
+	  output_expr_operand (ob, TREE_OPERAND (expr, i));
+	output_zero (ob);
+
+      }
+      break;
+
+    case BIT_FIELD_REF:
+      {
+	tree op1 = TREE_OPERAND (expr, 1);
+	tree op2 = TREE_OPERAND (expr, 2);
+	if ((TREE_CODE (op1) == INTEGER_CST)
+	    && (TREE_CODE (op2) == INTEGER_CST))
+	  {
+	    output_abbrev_ref (ob,
+			       get_form_special (DW_TAG_gimple_bit_field_ref, 1));
+#if STUPID_TYPE_SYSTEM
+	    output_type_ref (ob, TREE_TYPE (expr));
+#endif
+	    output_tree_flags (ob, expr);
+	    output_uleb128 (ob, TREE_INT_CST_LOW (op1));
+	    output_uleb128 (ob, TREE_INT_CST_LOW (op2));
+	    output_expr_operand (ob, TREE_OPERAND (expr, 0));
+	    output_zero (ob);
+	  }
+	else
+	  {
+	    output_abbrev_ref (ob,
+			       get_form_special (DW_TAG_gimple_bit_field_ref, 0));
+#if STUPID_TYPE_SYSTEM
+	    output_type_ref (ob, TREE_TYPE (expr));
+#endif
+	    output_tree_flags (ob, expr);
+	    output_expr_operand (ob, TREE_OPERAND (expr, 0));
+	    output_expr_operand (ob, op1);
+	    output_expr_operand (ob, op2);
+	    output_zero (ob);
+	  }
+      }
+      break;
+
+    case CONVERT_EXPR:
+    case NOP_EXPR:
+      output_type_ref (ob, TREE_TYPE (expr));
+      output_tree_flags (ob, expr);
+      output_expr_operand (ob, TREE_OPERAND (expr, 0));
+      output_zero (ob);
+      break;
+
+    case ABS_EXPR:
+    case ADDR_EXPR:
+    case ALIGN_INDIRECT_REF:
+    case BIT_NOT_EXPR:
+    case CONJ_EXPR:
+    case FIX_CEIL_EXPR:
+    case FIX_FLOOR_EXPR:
+    case FIX_ROUND_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    case GOTO_EXPR:
+    case IMAGPART_EXPR:
+    case INDIRECT_REF:
+    case MISALIGNED_INDIRECT_REF:
+    case NEGATE_EXPR:
+    case NON_LVALUE_EXPR:
+    case REALPART_EXPR:
+    case REDUC_MAX_EXPR:
+    case REDUC_MIN_EXPR:
+    case REDUC_PLUS_EXPR:
+    case TRUTH_NOT_EXPR:
+    case VIEW_CONVERT_EXPR:
+#if STUPID_TYPE_SYSTEM
+      output_type_ref (ob, TREE_TYPE (expr));
+#endif
+      output_tree_flags (ob, expr);
+      output_expr_operand (ob, TREE_OPERAND (expr, 0));
+      output_zero (ob);
+      break;
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+      /* Ignore operands 3 and 4 for ARRAY_REF and ARRAY_RANGE REF
+	 because they can be recomputed.  */
+
+    case WITH_SIZE_EXPR:
+      /* WITH_SIZE_EXPR is a pass-through reference to its first
+	 argument, and an rvalue reference to its second argument.  */
+
+      /* All of the binary expressions and their friends.  */
+    case ASSERT_EXPR:
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case CEIL_DIV_EXPR:
+    case CEIL_MOD_EXPR:
+    case COMPLEX_EXPR:
+    case COMPOUND_EXPR:
+    case EQ_EXPR:
+    case EXACT_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case FLOOR_MOD_EXPR:
+    case GE_EXPR:
+    case GT_EXPR:
+    case LE_EXPR:
+    case LROTATE_EXPR:
+    case LSHIFT_EXPR:
+    case LT_EXPR:
+    case LTGT_EXPR:
+    case MAX_EXPR:
+    case MIN_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case NE_EXPR:
+    case OBJ_TYPE_REF:
+    case ORDERED_EXPR:
+    case PLUS_EXPR:
+    case RANGE_EXPR:
+    case RDIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case ROUND_MOD_EXPR:
+    case RROTATE_EXPR:
+    case RSHIFT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case UNEQ_EXPR:
+    case UNGE_EXPR:
+    case UNGT_EXPR:
+    case UNLE_EXPR:
+    case UNLT_EXPR:
+    case UNORDERED_EXPR:
+    case VEC_LSHIFT_EXPR:
+    case VEC_RSHIFT_EXPR:
+    case WIDEN_MULT_EXPR:
+    case WIDEN_SUM_EXPR:
+#if STUPID_TYPE_SYSTEM
+      output_type_ref (ob, TREE_TYPE (expr));
+#endif
+      output_tree_flags (ob, expr);
+      output_expr_operand (ob, TREE_OPERAND (expr, 0));
+      output_expr_operand (ob, TREE_OPERAND (expr, 1));
+      output_zero (ob);
+      break;
+
+    case COND_EXPR:
+    case DOT_PROD_EXPR:
+    case REALIGN_LOAD_EXPR:
+    case VEC_COND_EXPR:
+#if STUPID_TYPE_SYSTEM
+      output_type_ref (ob, TREE_TYPE (expr));
+#endif
+      output_tree_flags (ob, expr);
+      output_expr_operand (ob, TREE_OPERAND (expr, 0));
+      output_expr_operand (ob, TREE_OPERAND (expr, 1));
+      output_expr_operand (ob, TREE_OPERAND (expr, 2));
+      output_zero (ob);
+      break;
+
+    case EXC_PTR_EXPR:
+    case FILTER_EXPR:
+      /* There is absolutely no documentation as to what this is.
+	 Someone else can fix it.  */
+#if STUPID_TYPE_SYSTEM
+      output_type_ref (ob, TREE_TYPE (expr));
+#endif
+      output_tree_flags (ob, expr);
+      break;
+
+    case NAME_MEMORY_TAG:
+    case STRUCT_FIELD_TAG:
+    case SYMBOL_MEMORY_TAG:
+    case TARGET_MEM_REF:
+    case BLOCK:
+    default:
+      /* We cannot have forms that are not explicity handled.  So when
+	 this is triggered, there is some form that is not being
+	 output.  */
+      gcc_unreachable ();
+    }
+}
+
+
+/* Output a gimple STMT.  */
+
+static void
+output_stmt (struct output_block *ob, tree stmt)
+{
+  enum tree_code code = TREE_CODE (stmt);
+  unsigned int tag = stmt_to_tag [code];
+
+  if (tag)
+    output_abbrev_ref (ob, get_stmt_form (tag));
+
+  code = TREE_CODE (stmt);
+  switch (code)
+    {
+    case ASM_EXPR:
+      {
+	tree string_cst = ASM_STRING (stmt);
+	int index
+	  = output_string (ob, TREE_STRING_POINTER (string_cst),
+			   TREE_STRING_LENGTH (string_cst));
+	output_uleb128 (ob, index);
+	output_tree_flags (ob, stmt);
+
+	if (ASM_INPUTS (stmt) != NULL_TREE)
+	  {
+	    tree tl;
+	    output_abbrev_ref (ob, DW_TAG_gimple_asm_inputs);
+	    for (tl = ASM_INPUTS (stmt); tl; tl = TREE_CHAIN (tl))
+	      output_expr_operand (ob, TREE_VALUE (tl));
+	    output_zero (ob);
+	  }
+	if (ASM_OUTPUTS (stmt) != NULL_TREE)
+	  {
+	    tree tl;
+	    output_abbrev_ref (ob, DW_TAG_gimple_asm_outputs);
+	    for (tl = ASM_OUTPUTS (stmt); tl; tl = TREE_CHAIN (tl))
+	      output_expr_operand (ob, TREE_VALUE (tl));
+	    output_zero (ob);
+	  }
+	if (ASM_CLOBBERS (stmt) != NULL_TREE)
+	  {
+	    tree tl;
+	    output_abbrev_ref (ob, DW_TAG_gimple_asm_clobbers);
+	    for (tl = ASM_CLOBBERS (stmt); tl; tl = TREE_CHAIN (tl))
+	      output_expr_operand (ob, TREE_VALUE (tl));
+	    output_zero (ob);
+	  }
+      }
+      break;
+
+    case CALL_EXPR:
+    case COND_EXPR:
+    case GOTO_EXPR:
+    case LABEL_EXPR:
+      /* Just let the code in output_expr_operand handle this.  */
+      output_expr_operand (ob, stmt);
+      break;
+
+    case MODIFY_EXPR:
+      output_tree_flags (ob, stmt);
+      output_expr_operand (ob, TREE_OPERAND (stmt, 0));
+      output_expr_operand (ob, TREE_OPERAND (stmt, 1));
+      output_zero (ob);
+      break;
+
+    case RESX_EXPR:
+      output_tree_flags (ob, stmt);
+      output_uleb128 (ob, TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)));
+      break;
+
+    case RETURN_EXPR:
+      {
+	tree t = TREE_OPERAND (stmt, 0);
+	if (t == NULL)
+	  {
+	    /* Form return.  */
+	    output_abbrev_ref (ob,
+			       get_form_special (DW_TAG_gimple_return_expr, 0));
+	    output_tree_flags (ob, stmt);
+	  }
+	else if (TREE_CODE (t) == MODIFY_EXPR)
+	  {
+	    /* Form return a = b;  */
+	    output_abbrev_ref (ob,
+			       get_form_special (DW_TAG_gimple_return_expr,
+						      2));
+	    output_tree_flags (ob, stmt);
+	    output_expr_operand (ob, TREE_OPERAND (t, 0));
+	    output_expr_operand (ob, TREE_OPERAND (t, 1));
+	    output_zero (ob);
+	  }
+	else
+	  {
+	    /* Form return a; */
+	    output_abbrev_ref (ob,
+			       get_form_special (DW_TAG_gimple_return_expr, 1));
+	    output_tree_flags (ob, stmt);
+	    output_expr_operand (ob, t);
+	    output_zero (ob);
+	  }
+      }
+      break;
+
+    case SWITCH_EXPR:
+      {
+	tree label_vec = TREE_OPERAND (stmt, 2);
+	size_t len = TREE_VEC_LENGTH (label_vec);
+	size_t i;
+	output_tree_flags (ob, stmt);
+	output_expr_operand (ob, TREE_OPERAND (stmt, 0));
+	gcc_assert (TREE_OPERAND (stmt, 1) == NULL);
+
+	for (i = 0; i < len; ++i)
+	  output_expr_operand (ob, TREE_VEC_ELT (label_vec, i));
+	output_zero (ob);
+      }
+      break;
+
+    case BIND_EXPR:
+    case TRY_CATCH_EXPR:
+    case TRY_FINALLY_EXPR:
+    case EH_FILTER_EXPR:
+    case CATCH_EXPR:
+    case OMP_PARALLEL:
+    case OMP_SECTIONS:
+    case OMP_FOR:
+    case OMP_SINGLE:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+    case OMP_CRITICAL:
+    case OMP_RETURN:
+    case OMP_CONTINUE:
+      /* I will let diego do this.  */
+    default:
+      /* We cannot have forms that are not explicity handled.  So when
+	 this is triggered, there is some form that is not being
+	 output.  */
+      gcc_unreachable ();
+    }
+}
+
+
+/* Output a basic block BB to the main stream in OB for this CFUN.  */
+
+static void
+output_bb (struct output_block *ob, basic_block bb, struct function *cfun)
+{
+  edge e;
+  edge_iterator ei;
+  block_stmt_iterator bsi = bsi_start (bb);
+
+  output_abbrev_ref (ob, get_form_special (DW_TAG_gimple_bb,
+					   bsi_end_p (bsi)? 0 : 1));
+
+  /* Output the successors of bb.  */
+  output_uleb128 (ob, EDGE_COUNT (bb->succs));
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    output_uleb128 (ob, e->dest->index);
+
+  /* Output the flags for the successors of bb.  */
+  output_uleb128 (ob, EDGE_COUNT (bb->succs));
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    output_uleb128 (ob, e->flags);
+
+  /* Output the statements.  */
+  for (bsi = bsi_start (bb);
+       !bsi_end_p (bsi); bsi_next (&bsi))
+    {
+      tree stmt = bsi_stmt (bsi);
+      tree orig_stmt = stmt;
+
+      output_stmt (ob, stmt);
+
+      /* We only need to set the region number of the tree that could
+	 throw if the region number is different from the last region
+	 number we set.  */
+      if (tree_could_throw_p (stmt))
+	{
+	  int region = lookup_stmt_eh_region_fn (cfun, orig_stmt);
+	  if (region != last_eh_region_seen)
+	    {
+	      output_abbrev_ref (ob, get_set_eh_form (region));
+	      if (region)
+		output_uleb128 (ob, region);
+
+	      output_zero (ob);
+	      last_eh_region_seen = region;
+	    }
+	}
+    }
+
+  output_zero (ob);
+}
+
+
+/* Create the header in the file.  */
+
+static void
+create_header (struct output_block *ob)
+{
+  /* The entire header is stream computed here.  */
+  unsigned int header_size = 4 + 2 + 4 + 1 + 1 + (8 * 4);
+  unsigned int running_size;
+
+  output_4_stream (&ob->header_stream, 0xffffffffff);
+  /* Dwarf version.  */
+  output_2_stream (&ob->header_stream, 3);
+  /* Abbrev offset.  */
+  output_4_stream (&ob->header_stream, 0xffffffffff);
+  /* Address size.  */
+  output_1_stream (&ob->header_stream, HOST_BITS_PER_INT / 8);
+
+  /* Cannot call output_abbrev_ref here because it will put it in the
+     wrong section.  */
+  output_uleb128_stream (&ob->header_stream,
+			 get_form_special (DW_TAG_gimple_function_top, 0));
+
+  output_4_stream (&ob->header_stream, header_size);
+  output_4_stream (&ob->header_stream, ob->main_stream.total_size);
+
+  running_size = header_size + ob->main_stream.total_size;
+  output_4_stream (&ob->header_stream, header_size);
+  output_4_stream (&ob->header_stream, ob->string_stream.total_size);
+
+  running_size += ob->string_stream.total_size;
+  output_4_stream (&ob->header_stream, header_size);
+  output_4_stream (&ob->header_stream, ob->name_stream.total_size);
+
+  running_size += ob->name_stream.total_size;
+  output_4_stream (&ob->header_stream, header_size);
+  output_4_stream (&ob->header_stream, ob->type_stream.total_size);
+
+  running_size += ob->type_stream.total_size;
+
+  gcc_assert (header_size == ob->header_stream.total_size);
+}
+
+
+static void
+init_lto_out (void)
+{
+  /* Initialize the expression to tag mapping.  */
+
+  /* DW_TAG_gimple_bit_field_ref, DW_TAG_gimple_case_label_expr,
+     DW_TAG_gimple_call_expr, DW_TAG_gimple_complex_cst,
+     DW_TAG_gimple_vector_cst and are delibertly missing from the list
+     below.  This forces output_expr_operand to let the case write the
+     abbrev reference after it looks at the operands of the tree.
+     Asside from these special cases, this is every tree type
+     processed by output_expr_operand.  */
+
+  expr_to_tag [ADDR_EXPR] = DW_TAG_gimple_addr_expr;
+  expr_to_tag [ALIGN_INDIRECT_REF] = DW_TAG_gimple_align_indirect_ref;
+  expr_to_tag [ARRAY_RANGE_REF] = DW_TAG_gimple_array_range_ref;
+  expr_to_tag [ARRAY_REF] = DW_TAG_gimple_array_ref;
+  expr_to_tag [ASSERT_EXPR] = DW_TAG_gimple_assert_expr;
+  expr_to_tag [BIT_AND_EXPR] = DW_TAG_gimple_bit_and_expr;
+  expr_to_tag [BIT_IOR_EXPR] = DW_TAG_gimple_bit_ior_expr;
+  expr_to_tag [BIT_NOT_EXPR] = DW_TAG_gimple_bit_not_expr;
+  expr_to_tag [BIT_XOR_EXPR] = DW_TAG_gimple_bit_xor_expr;
+  expr_to_tag [CEIL_DIV_EXPR] = DW_TAG_gimple_ceil_div_expr;
+  expr_to_tag [CEIL_MOD_EXPR] = DW_TAG_gimple_ceil_mod_expr;
+  expr_to_tag [COMPLEX_EXPR] = DW_TAG_gimple_complex_expr;
+  expr_to_tag [COMPONENT_REF] = DW_TAG_gimple_component_ref;
+  expr_to_tag [COMPOUND_EXPR] = DW_TAG_gimple_compound_expr;
+  expr_to_tag [COND_EXPR] = DW_TAG_gimple_cond_expr;
+  expr_to_tag [CONJ_EXPR] = DW_TAG_gimple_conj_expr;
+  expr_to_tag [CONST_DECL] = DW_TAG_gimple_const_decl;
+  expr_to_tag [CONSTRUCTOR] = DW_TAG_gimple_constructor;
+  expr_to_tag [CONVERT_EXPR] = DW_TAG_gimple_convert_expr;
+  expr_to_tag [DOT_PROD_EXPR] = DW_TAG_gimple_dot_prod_expr;
+  expr_to_tag [EQ_EXPR] = DW_TAG_gimple_eq_expr;
+  expr_to_tag [EXACT_DIV_EXPR] = DW_TAG_gimple_exact_div_expr;
+  expr_to_tag [EXC_PTR_EXPR] = DW_TAG_gimple_exc_ptr_expr;
+  expr_to_tag [FIELD_DECL] = DW_TAG_gimple_field_decl;
+  expr_to_tag [FILTER_EXPR] = DW_TAG_gimple_filter_expr;
+  expr_to_tag [FIX_CEIL_EXPR] = DW_TAG_gimple_fix_ceil_expr;
+  expr_to_tag [FIX_FLOOR_EXPR] = DW_TAG_gimple_fix_floor_expr;
+  expr_to_tag [FIX_ROUND_EXPR] = DW_TAG_gimple_fix_round_expr;
+  expr_to_tag [FIX_TRUNC_EXPR] = DW_TAG_gimple_fix_trunc_expr;
+  expr_to_tag [FLOAT_EXPR] = DW_TAG_gimple_float_expr;
+  expr_to_tag [FLOOR_DIV_EXPR] = DW_TAG_gimple_floor_div_expr;
+  expr_to_tag [FLOOR_MOD_EXPR] = DW_TAG_gimple_floor_mod_expr;
+  expr_to_tag [FUNCTION_DECL] = DW_TAG_gimple_function_decl;
+  expr_to_tag [GE_EXPR] = DW_TAG_gimple_ge_expr;
+  expr_to_tag [GOTO_EXPR] = DW_TAG_gimple_goto_expr;
+  expr_to_tag [GT_EXPR] = DW_TAG_gimple_gt_expr;
+  expr_to_tag [IMAGPART_EXPR] = DW_TAG_gimple_imagpart_expr;
+  expr_to_tag [INDIRECT_REF] = DW_TAG_gimple_indirect_ref;
+  expr_to_tag [INTEGER_CST] = DW_TAG_gimple_integer_cst;
+  expr_to_tag [LABEL_DECL] = DW_TAG_gimple_label_decl;
+  expr_to_tag [LABEL_EXPR] = DW_TAG_gimple_label_expr;
+  expr_to_tag [LE_EXPR] = DW_TAG_gimple_le_expr;
+  expr_to_tag [LROTATE_EXPR] = DW_TAG_gimple_lrotate_expr;
+  expr_to_tag [LSHIFT_EXPR] = DW_TAG_gimple_lshift_expr;
+  expr_to_tag [LT_EXPR] = DW_TAG_gimple_lt_expr;
+  expr_to_tag [LTGT_EXPR] = DW_TAG_gimple_ltgt_expr;
+  expr_to_tag [MAX_EXPR] = DW_TAG_gimple_max_expr;
+  expr_to_tag [MIN_EXPR] = DW_TAG_gimple_min_expr;
+  expr_to_tag [MINUS_EXPR] = DW_TAG_gimple_minus_expr;
+  expr_to_tag [MISALIGNED_INDIRECT_REF] = DW_TAG_gimple_misaligned_indirect_ref;
+  expr_to_tag [MULT_EXPR] = DW_TAG_gimple_mult_expr;
+  expr_to_tag [NE_EXPR] = DW_TAG_gimple_ne_expr;
+  expr_to_tag [NEGATE_EXPR] = DW_TAG_gimple_negate_expr;
+  expr_to_tag [NON_LVALUE_EXPR] = DW_TAG_gimple_non_lvalue_expr;
+  expr_to_tag [NOP_EXPR] = DW_TAG_gimple_nop_expr;
+  expr_to_tag [OBJ_TYPE_REF] = DW_TAG_gimple_obj_type_ref;
+  expr_to_tag [ORDERED_EXPR] = DW_TAG_gimple_ordered_expr;
+  expr_to_tag [PARM_DECL] = DW_TAG_gimple_parm_decl;
+  expr_to_tag [PLUS_EXPR] = DW_TAG_gimple_plus_expr;
+  expr_to_tag [RANGE_EXPR] = DW_TAG_gimple_range_expr;
+  expr_to_tag [RDIV_EXPR] = DW_TAG_gimple_rdiv_expr;
+  expr_to_tag [REAL_CST] = DW_TAG_gimple_real_cst;
+  expr_to_tag [REALIGN_LOAD_EXPR] = DW_TAG_gimple_realign_load_expr;
+  expr_to_tag [REALPART_EXPR] = DW_TAG_gimple_realpart_expr;
+  expr_to_tag [REDUC_MAX_EXPR] = DW_TAG_gimple_reduc_max_expr;
+  expr_to_tag [REDUC_MIN_EXPR] = DW_TAG_gimple_reduc_min_expr;
+  expr_to_tag [REDUC_PLUS_EXPR] = DW_TAG_gimple_reduc_plus_expr;
+  expr_to_tag [RESULT_DECL] = DW_TAG_gimple_result_decl;
+  expr_to_tag [ROUND_DIV_EXPR] = DW_TAG_gimple_round_div_expr;
+  expr_to_tag [ROUND_MOD_EXPR] = DW_TAG_gimple_round_mod_expr;
+  expr_to_tag [RROTATE_EXPR] = DW_TAG_gimple_rrotate_expr;
+  expr_to_tag [RSHIFT_EXPR] = DW_TAG_gimple_rshift_expr;
+  expr_to_tag [SSA_NAME] = DW_TAG_gimple_ssa_name;
+  expr_to_tag [STRING_CST] = DW_TAG_gimple_string_cst;
+  expr_to_tag [TRUNC_DIV_EXPR] = DW_TAG_gimple_trunc_div_expr;
+  expr_to_tag [TRUNC_MOD_EXPR] = DW_TAG_gimple_trunc_mod_expr;
+  expr_to_tag [TRUTH_AND_EXPR] = DW_TAG_gimple_truth_and_expr;
+  expr_to_tag [TRUTH_NOT_EXPR] = DW_TAG_gimple_truth_not_expr;
+  expr_to_tag [TRUTH_OR_EXPR] = DW_TAG_gimple_truth_or_expr;
+  expr_to_tag [TRUTH_XOR_EXPR] = DW_TAG_gimple_truth_xor_expr;
+  expr_to_tag [UNEQ_EXPR] = DW_TAG_gimple_uneq_expr;
+  expr_to_tag [UNGE_EXPR] = DW_TAG_gimple_unge_expr;
+  expr_to_tag [UNGT_EXPR] = DW_TAG_gimple_ungt_expr;
+  expr_to_tag [UNLE_EXPR] = DW_TAG_gimple_unle_expr;
+  expr_to_tag [UNLT_EXPR] = DW_TAG_gimple_unlt_expr;
+  expr_to_tag [UNORDERED_EXPR] = DW_TAG_gimple_unordered_expr;
+  expr_to_tag [VAR_DECL] = DW_TAG_gimple_var_decl;
+  expr_to_tag [VEC_COND_EXPR] = DW_TAG_gimple_vec_cond_expr;
+  expr_to_tag [VEC_LSHIFT_EXPR] = DW_TAG_gimple_vec_lshift_expr;
+  expr_to_tag [VEC_RSHIFT_EXPR] = DW_TAG_gimple_vec_rshift_expr;
+  expr_to_tag [VIEW_CONVERT_EXPR] = DW_TAG_gimple_view_convert_expr;
+  expr_to_tag [WIDEN_MULT_EXPR] = DW_TAG_gimple_widen_mult_expr;
+  expr_to_tag [WIDEN_SUM_EXPR] = DW_TAG_gimple_widen_sum_expr;
+  expr_to_tag [WITH_SIZE_EXPR] = DW_TAG_gimple_with_size_expr;
+
+  /* Initialize the stmt to tag map.  */
+
+  /* DW_TAG_gimple_cond_expr, DW_TAG_gimple_return_expr and
+     DW_TAG_gimple_call_expr are delibertly missing from the list
+     below.  This forces output_expr_operand to let the case write the
+     abbrev reference after it looks at the operands of the tree.
+     Asside from these special cases, this is every tree type
+     processed by output_expr_operand.  */
+
+  stmt_to_tag [ASM_EXPR] = DW_TAG_gimple_asm_expr;
+  stmt_to_tag [MODIFY_EXPR] = DW_TAG_gimple_modify_expr;
+  stmt_to_tag [RESX_EXPR] = DW_TAG_gimple_resx_expr;
+  stmt_to_tag [SWITCH_EXPR] = DW_TAG_gimple_switch_expr;
+
+}
+
+#ifdef FILE_PER_FUNCTION
+/* The once per compilation unit initialization flag.  */
+static int function_num;
+#endif
+
+static bool initialized = false;
+
+
+/* Output CFUN.  */
+
+static void
+output_function (tree function)
+{
+  struct function *this_cfun = DECL_STRUCT_FUNCTION (function);
+  struct output_block *ob = xcalloc (1, sizeof (struct output_block));
+  FILE *f;
+  char * file_name = xmalloc (1000);
+  basic_block bb;
+  const char * mode; 
+
+  /* This file code is just a hack to get the stuff where it can be
+     measured.  The real lto will put the info into the assembly
+     stream.  */
+
+#ifdef FILE_PER_FUNCTION
+  mode = "w";
+  sprintf (file_name, "/tmp/ltotest/%s.%d.function", dump_base_name, function_num++);
+#else
+  mode = "a";
+  sprintf (file_name, "/tmp/ltotest/%s.function", dump_base_name);
+#endif
+  
+  f = fopen (file_name, mode);
+  if (f == NULL)
+    {
+      fprintf (stderr, "could not open file '%s'\n", file_name);
+      gcc_unreachable ();
+    }
+
+  free (file_name);
+
+  ob->type_hash_table = htab_create (37,
+				     hash_type_slot_node,
+				     eq_type_slot_node, free);
+  ob->name_hash_table = htab_create (37,
+				     hash_decl_slot_node,
+				     eq_decl_slot_node, free);
+  ob->label_hash_table = htab_create (37,
+				      hash_label_slot_node,
+				      eq_label_slot_node, free);
+
+  if (!initialized)
+    {
+      init_lto_out ();
+      initialized = true;
+    }
+
+  last_eh_region_seen = 0;
+
+  /* Duplicate any exception-handling regions.  */
+  output_eh_regions (ob, this_cfun);
+
+  /* Duplicate the code for the function.  */
+  FOR_ALL_BB_FN (bb, this_cfun)
+    output_bb (ob, bb, this_cfun);
+
+  /* The terminator for this function.  */
+  output_zero (ob);
+
+  /* Create a file to hold the pickled output of this function.  This
+     is a temp standin until we start writing sections.  */
+  create_header (ob);
+
+  write_stream (&ob->header_stream, f);
+  write_stream (&ob->main_stream, f);
+  write_stream (&ob->string_stream, f);
+  write_stream (&ob->name_stream, f);
+  write_stream (&ob->type_stream, f);
+  htab_delete (ob->type_hash_table);
+  htab_delete (ob->name_hash_table);
+  htab_delete (ob->label_hash_table);
+  free (ob);
+  fclose (f);
+}
+
+static unsigned int
+lto_output (void)
+{
+  struct cgraph_node *node;
+  char * file_name = xmalloc (1000);
+  FILE *fa;
+
+  mkdir ("/tmp/ltotest", 0777);
+
+  /* Process only the fuctions with bodies and only process the master
+     ones of them.  */
+#ifndef FILE_PER_FUNCTION
+  /* If we are not in file per function mode, we must truncate the file
+     to keep it's size from doubling on the second bootstrap.  */
+  sprintf (file_name, "/tmp/ltotest/%s.function", dump_base_name);
+  fa = fopen (file_name, "w");
+  fclose (fa);
+#endif
+
+  for (node = cgraph_nodes; node; node = node->next)
+    if (node->analyzed && cgraph_is_master_clone (node, true))
+      output_function (node->decl);
+
+  /* This code is just a hack to get the stuff where it can be
+     measured.  The real lto will put the info into the assembly
+     stream.  */
+
+  sprintf (file_name, "/tmp/ltotest/%s.abbrev", dump_base_name);
+  fa = fopen (file_name, "w");
+  free (file_name);
+
+  write_stream (&abbrev_stream, fa);
+  fclose (fa);
+
+  return 0;
+}
+
+static bool
+gate_lto_out (void)
+{
+  return (flag_unit_at_a_time != 0
+	  /* Don't bother doing anything if the program has errors.  */
+	  && !(errorcount || sorrycount));
+}
+
+struct tree_opt_pass pass_ipa_lto_out =
+{
+  "pure-const",		                /* name */
+  gate_lto_out,			        /* gate */
+  lto_output,		        	/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  TV_IPA_LTO_OUT,		        /* tv_id */
+  0,	                                /* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  0,                                    /* todo_flags_finish */
+  0					/* letter */
+};
+
+
Index: ipa-pure-const.c
===================================================================
--- ipa-pure-const.c	(revision 116385)
+++ ipa-pure-const.c	(working copy)
@@ -603,7 +603,7 @@ static_execute (void)
      for the one that overriders it.
   */
   for (node = cgraph_nodes; node; node = node->next)
-    if (node->analyzed && cgraph_is_master_clone (node))
+    if (node->analyzed && cgraph_is_master_clone (node, true))
       analyze_function (node);
 
   pointer_set_destroy (visited_nodes);
@@ -641,7 +641,7 @@ static_execute (void)
 		{
 		  struct cgraph_node *y = e->callee;
 		  /* Only look at the master nodes and skip external nodes.  */
-		  y = cgraph_master_clone (y);
+		  y = cgraph_master_clone (y, true);
 		  if (y)
 		    {
 		      funct_state y_l = get_function_state (y);
Index: ipa-utils.c
===================================================================
--- ipa-utils.c	(revision 116385)
+++ ipa-utils.c	(working copy)
@@ -104,7 +104,7 @@ searchc (struct searchc_env* env, struct
       struct cgraph_node *w = edge->callee;
       /* Bypass the clones and only look at the master node.  Skip
 	 external and other bogus nodes.  */
-      w = cgraph_master_clone (w);
+      w = cgraph_master_clone (w, true);
       if (w && w->aux) 
 	{
 	  w_info = w->aux;
@@ -171,7 +171,7 @@ ipa_utils_reduced_inorder (struct cgraph
   
   for (node = cgraph_nodes; node; node = node->next) 
     if ((node->analyzed)
-	&& (cgraph_is_master_clone (node) 
+	&& (cgraph_is_master_clone (node, true) 
 	 || (allow_overwritable 
 	     && (cgraph_function_body_availability (node) == 
 		 AVAIL_OVERWRITABLE))))
Index: timevar.def
===================================================================
--- timevar.def	(revision 116385)
+++ timevar.def	(working copy)
@@ -43,6 +43,7 @@ DEFTIMEVAR (TV_DUMP                  , "
 DEFTIMEVAR (TV_CGRAPH                , "callgraph construction")
 DEFTIMEVAR (TV_CGRAPHOPT             , "callgraph optimization")
 DEFTIMEVAR (TV_IPA_CONSTANT_PROP     , "ipa cp")
+DEFTIMEVAR (TV_IPA_LTO_OUT           , "ipa lto out")
 DEFTIMEVAR (TV_IPA_REFERENCE         , "ipa reference")
 DEFTIMEVAR (TV_IPA_PURE_CONST        , "ipa pure const")
 DEFTIMEVAR (TV_IPA_TYPE_ESCAPE       , "ipa type escape")
Index: ipa-type-escape.c
===================================================================
--- ipa-type-escape.c	(revision 116385)
+++ ipa-type-escape.c	(working copy)
@@ -1700,7 +1700,7 @@ type_escape_execute (void)
   */
   for (node = cgraph_nodes; node; node = node->next)
     if (node->analyzed 
-	&& (cgraph_is_master_clone (node)
+	&& (cgraph_is_master_clone (node, true)
 	    || (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE)))
       analyze_function (node);
 
Index: except.c
===================================================================
--- except.c	(revision 116385)
+++ except.c	(working copy)
@@ -136,12 +136,11 @@ struct eh_region GTY(())
   enum eh_region_type
   {
     ERT_UNKNOWN = 0,
-    ERT_CLEANUP,
-    ERT_TRY,
-    ERT_CATCH,
-    ERT_ALLOWED_EXCEPTIONS,
-    ERT_MUST_NOT_THROW,
-    ERT_THROW
+    ERT_CLEANUP,             /* eh_region_u_cleanup.  */
+    ERT_TRY,                 /* eh_region_u_try.  */
+    ERT_CATCH,               /* eh_region_u_catch.  */
+    ERT_ALLOWED_EXCEPTIONS,  /* eh_region_u_allowed.  */
+    ERT_MUST_NOT_THROW       /* None.  */
   } type;
 
   /* Holds the action to perform based on the preceding type.  */
@@ -168,12 +167,6 @@ struct eh_region GTY(())
       int filter;
     } GTY ((tag ("ERT_ALLOWED_EXCEPTIONS"))) allowed;
 
-    /* The type given by a call to "throw foo();", or discovered
-       for a throw.  */
-    struct eh_region_u_throw {
-      tree type;
-    } GTY ((tag ("ERT_THROW"))) throw;
-
     /* Retain the cleanup expression even after expansion so that
        we can match up fixup regions.  */
     struct eh_region_u_cleanup {
@@ -706,13 +699,6 @@ remove_unreachable_regions (rtx insns)
 	  bool kill_it = true;
 	  switch (r->type)
 	    {
-	    case ERT_THROW:
-	      /* Don't remove ERT_THROW regions if their outer region
-		 is reachable.  */
-	      if (r->outer && reachable[r->outer->region_number])
-		kill_it = false;
-	      break;
-
 	    case ERT_MUST_NOT_THROW:
 	      /* MUST_NOT_THROW regions are implementable solely in the
 		 runtime, but their existence continues to affect calls
@@ -849,8 +835,7 @@ current_function_has_exception_handlers 
 
       region = VEC_index (eh_region, cfun->eh->region_array, i);
       if (region
-	  && region->region_number == i
-	  && region->type != ERT_THROW)
+	  && region->region_number == i)
 	return true;
     }
 
@@ -1506,7 +1491,6 @@ build_post_landing_pads (void)
 	  break;
 
 	case ERT_CATCH:
-	case ERT_THROW:
 	  /* Nothing to do.  */
 	  break;
 
@@ -1709,12 +1693,6 @@ sjlj_find_directly_reachable_regions (st
       region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
 
       type_thrown = NULL_TREE;
-      if (region->type == ERT_THROW)
-	{
-	  type_thrown = region->u.throw.type;
-	  region = region->outer;
-	}
-
       /* Find the first containing region that might handle the exception.
 	 That's the landing pad to which we will transfer control.  */
       rc = RNL_NOT_CAUGHT;
@@ -2103,7 +2081,7 @@ finish_eh_generation (void)
   /* The object here is to provide find_basic_blocks with detailed
      information (via reachable_handlers) on how exception control
      flows within the function.  In this first pass, we can include
-     type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS
+     type information garnered from ERT_ALLOWED_EXCEPTIONS
      regions, and hope that it will be useful in deleting unreachable
      handlers.  Subsequently, we will generate landing pads which will
      connect many of the handlers, and then type information will not
@@ -2576,7 +2554,6 @@ reachable_next_level (struct eh_region *
       else
 	return RNL_BLOCKED;
 
-    case ERT_THROW:
     case ERT_UNKNOWN:
       /* Shouldn't see these here.  */
       gcc_unreachable ();
@@ -2612,11 +2589,6 @@ foreach_reachable_handler (int region_nu
 	return;
       region = region->outer;
     }
-  else if (region->type == ERT_THROW)
-    {
-      type_thrown = region->u.throw.type;
-      region = region->outer;
-    }
 
   while (region)
     {
@@ -2695,11 +2667,6 @@ can_throw_internal_1 (int region_number,
   type_thrown = NULL_TREE;
   if (is_resx)
     region = region->outer;
-  else if (region->type == ERT_THROW)
-    {
-      type_thrown = region->u.throw.type;
-      region = region->outer;
-    }
 
   /* If this exception is ignored by each and every containing region,
      then control passes straight out.  The runtime may handle some
@@ -2755,11 +2722,6 @@ can_throw_external_1 (int region_number,
   type_thrown = NULL_TREE;
   if (is_resx)
     region = region->outer;
-  else if (region->type == ERT_THROW)
-    {
-      type_thrown = region->u.throw.type;
-      region = region->outer;
-    }
 
   /* If the exception is caught or blocked by any containing region,
      then it is not seen by any calling function.  */
@@ -3218,9 +3180,7 @@ collect_one_action_chain (htab_t ar_hash
       return -2;
 
     case ERT_CATCH:
-    case ERT_THROW:
-      /* CATCH regions are handled in TRY above.  THROW regions are
-	 for optimization information only and produce no output.  */
+      /* CATCH regions are handled in TRY above.  */
       return collect_one_action_chain (ar_hash, region->outer);
 
     default:
@@ -3620,6 +3580,85 @@ output_ttype (tree type, int tt_format, 
     dw2_asm_output_encoded_addr_rtx (tt_format, value, public, NULL);
 }
 
+
+/* This call is for the generation of lto function information.  The
+   five output functions are used as callbacks to output each of the
+   five flavors of eh_region.  */
+
+void 
+output_eh_records (void *ob, struct function * cfun,
+		   output_eh_cleanup_t cleanup, 
+		   output_eh_try_t try,
+		   output_eh_catch_t catch,
+		   output_eh_allowed_t allowed,
+		   output_eh_must_not_throw_t must_not_throw)
+{
+  struct eh_region *i = cfun->eh->region_tree;
+  if (! i)
+    return;
+
+  while (1)
+    {
+      switch (i->type)
+	{
+	case ERT_CLEANUP:
+	  cleanup (ob, i->region_number, 
+		   i->inner != NULL, i->next_peer != NULL, 
+		   i->may_contain_throw, 
+		   i->u.cleanup.prev_try 
+		   ? i->u.cleanup.prev_try->region_number : 0);
+	  break;
+	case ERT_TRY:
+	  try (ob, i->region_number, 
+	       i->inner != NULL, i->next_peer != NULL, 
+	       i->may_contain_throw, i->u.try.catch->region_number, 
+	       i->u.try.last_catch ? 
+	       i->u.try.last_catch->region_number : 0);
+	  break;
+	case ERT_CATCH:
+	  catch (ob, i->region_number, 
+		 i->inner != NULL, i->next_peer != NULL, 
+		 i->may_contain_throw, 
+		 i->u.catch.next_catch 
+		 ? i->u.catch.next_catch->region_number : 0, 
+		 i->u.catch.prev_catch 
+		 ? i->u.catch.prev_catch->region_number : 0,
+		 i->u.catch.type_list);
+	  break;
+	case ERT_ALLOWED_EXCEPTIONS:
+	  allowed (ob, i->region_number, 
+		   i->inner != NULL, i->next_peer != NULL, 
+		   i->may_contain_throw, i->u.allowed.type_list);
+	  break;
+	case ERT_MUST_NOT_THROW:
+	  must_not_throw (ob, i->region_number, 
+			  i->inner != NULL, i->next_peer != NULL, 
+			  i->may_contain_throw);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+
+      /* If there are sub-regions, process them.  */
+      if (i->inner)
+	i = i->inner;
+      /* If there are peers, process them.  */
+      else if (i->next_peer)
+	i = i->next_peer;
+      /* Otherwise, step back up the tree to the next peer.  */
+      else
+	{
+	  do {
+	    i = i->outer;
+	    if (i == NULL)
+	      return;
+	  } while (i->next_peer == NULL);
+	  i = i->next_peer;
+	}
+    }
+}
+
+
 void
 output_function_exception_table (void)
 {
Index: except.h
===================================================================
--- except.h	(revision 116385)
+++ except.h	(working copy)
@@ -174,6 +174,21 @@ struct throw_stmt_node GTY(())
   int region_nr;
 };
 
+typedef void (*output_eh_cleanup_t) (void *, unsigned int, bool, bool, 
+				     bool, unsigned int);
+typedef void (*output_eh_try_t) (void *, unsigned int, bool, bool, 
+				 bool, unsigned int, unsigned int);
+typedef void (*output_eh_catch_t) (void *, unsigned int, bool, bool, 
+				   bool, unsigned int, unsigned int, tree);
+typedef void (*output_eh_allowed_t) (void *, unsigned int, bool, bool, 
+				     bool, tree);
+typedef void (*output_eh_must_not_throw_t) (void *, unsigned int, bool, bool, bool);
+
+extern void output_eh_records (void *, struct function *, 
+			       output_eh_cleanup_t, output_eh_try_t, 
+			       output_eh_catch_t, output_eh_allowed_t, 
+			       output_eh_must_not_throw_t);
+
 extern struct htab *get_eh_throw_stmt_table (struct function *);
 extern void set_eh_throw_stmt_table (struct function *, struct htab *);
 
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 116385)
+++ Makefile.in	(working copy)
@@ -965,6 +965,7 @@ C_OBJS = c-lang.o stub-objc.o $(C_AND_OB
 
 # Language-independent object files.
 OBJS-common = \
+ lto-out-dwarf.o                                                           \
  double-int.o tree-chrec.o tree-scalar-evolution.o tree-data-ref.o	   \
  tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-gimple.o  \
  gimplify.o tree-pretty-print.o tree-into-ssa.o				   \
@@ -1801,6 +1802,11 @@ convert.o: convert.c $(CONFIG_H) $(SYSTE
 
 double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
+lto-out-dwarf.o : lto-out-dwarf.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   toplev.h $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h $(VARRAY_H) \
+   $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) tree-iterator.h tree-pass.h \
+   tree-flow.h $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) except.h \
+   debug.h $(TIMEVAR_H) lto-dwarf.h lto-tree-flags.def
 langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) toplev.h $(TREE_INLINE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \
    langhooks.h $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) $(DIAGNOSTIC_H) intl.h \
Index: tree-ssa-structalias.c
===================================================================
--- tree-ssa-structalias.c	(revision 116385)
+++ tree-ssa-structalias.c	(working copy)
@@ -4566,7 +4566,7 @@ ipa_pta_execute (void)
    
   for (node = cgraph_nodes; node; node = node->next)
     {
-      if (!node->analyzed || cgraph_is_master_clone (node))
+      if (!node->analyzed || cgraph_is_master_clone (node, true))
 	{
 	  unsigned int varid;
 	  
@@ -4582,7 +4582,7 @@ ipa_pta_execute (void)
     }
   for (node = cgraph_nodes; node; node = node->next)
     {
-      if (node->analyzed && cgraph_is_master_clone (node))
+      if (node->analyzed && cgraph_is_master_clone (node, true))
 	{
 	  struct function *cfun = DECL_STRUCT_FUNCTION (node->decl);
 	  basic_block bb;
Index: passes.c
===================================================================
--- passes.c	(revision 116385)
+++ passes.c	(working copy)
@@ -443,6 +443,7 @@ init_optimization_passes (void)
   NEXT_PASS (pass_early_ipa_inline);
   NEXT_PASS (pass_early_local_passes);
   NEXT_PASS (pass_ipa_cp);
+  NEXT_PASS (pass_ipa_lto_out);
   NEXT_PASS (pass_ipa_inline);
   NEXT_PASS (pass_ipa_reference);
   NEXT_PASS (pass_ipa_pure_const); 
Index: lto-dwarf.h
===================================================================
--- lto-dwarf.h	(revision 0)
+++ lto-dwarf.h	(revision 0)
@@ -0,0 +1,231 @@
+/* Declarations and definitions of codes relating to the DWARF3
+   encoding of gimple.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#ifndef GCC_LTO_DWARF2_H
+#define GCC_LTO_DWARF2_H
+
+/* When we get a strongly typed gimple, which may not be for another
+   15 years, this flag should be set to 0 so we do not waste so much
+   space printing out largely redundant type codes.  */
+#define STUPID_TYPE_SYSTEM 1
+
+/* I am sorry, the devil made me do it.  This is an unauthorized
+   extension to dwarf.  For all of the other tag types there is a
+   specific mechanism for adding user defined extension.  However, for
+   some reason only known to computer literate, short, stocky, people
+   with long beards, you are not supposed to be able to add to the
+   forms.  This is a serious problem for writing out GIMPLE
+   intermediate code.  In particular, lists of things like types or
+   cfg edges are a real problem.  The encoding for these would be
+   really bulky.  */
+#define DW_FORM_udata_list                        0x3080
+#define DW_FORM_sdata_list                        0x3081
+#define DW_FORM_const_false                       0x3082
+#define DW_FORM_const_true                        0x3083
+
+
+#define DW_TAG_gimple_function_top                0x4080
+#define DW_TAG_gimple_eh_table                    0x4081
+#define DW_TAG_gimple_eh_table_cleanup            0x4082
+#define DW_TAG_gimple_eh_table_try                0x4083
+#define DW_TAG_gimple_eh_table_catch              0x4084
+#define DW_TAG_gimple_eh_table_allowed            0x4085
+#define DW_TAG_gimple_eh_table_must_not_throw     0x4086
+
+#define DW_TAG_gimple_eh_table_first  DW_TAG_gimple_eh_table_cleanup
+#define DW_TAG_gimple_eh_table_count \
+  (1 + DW_TAG_gimple_eh_table_must_not_throw - DW_TAG_gimple_eh_table_cleanup)
+
+#define DW_TAG_gimple_bb                          0x4090
+#define DW_TAG_gimple_set_eh                      0x4091
+
+/* All of the expression types that we can see.  */
+#define DW_TAG_gimple_abs_expr                    0x4100
+#define DW_TAG_gimple_addr_expr                   0x4101
+#define DW_TAG_gimple_align_indirect_ref          0x4102
+#define DW_TAG_gimple_array_range_ref             0x4103
+#define DW_TAG_gimple_array_ref                   0x4104
+#define DW_TAG_gimple_assert_expr                 0x4105
+#define DW_TAG_gimple_bit_and_expr                0x4106
+#define DW_TAG_gimple_bit_ior_expr                0x4107
+#define DW_TAG_gimple_bit_field_ref               0x4108
+#define DW_TAG_gimple_bit_not_expr                0x4109
+#define DW_TAG_gimple_bit_xor_expr                0x410A
+#define DW_TAG_gimple_call_expr                   0x410C
+#define DW_TAG_gimple_case_label_expr             0x410D
+#define DW_TAG_gimple_ceil_div_expr               0x410E
+#define DW_TAG_gimple_ceil_mod_expr               0x410F
+#define DW_TAG_gimple_complex_cst                 0x4110
+#define DW_TAG_gimple_complex_expr                0x4111
+#define DW_TAG_gimple_component_ref               0x4112
+#define DW_TAG_gimple_compound_expr               0x4113
+#define DW_TAG_gimple_cond_expr                   0x4114
+#define DW_TAG_gimple_conj_expr                   0x4115
+#define DW_TAG_gimple_const_decl                  0x4116
+#define DW_TAG_gimple_constructor                 0x4117
+#define DW_TAG_gimple_constructor_range           0x4118
+#define DW_TAG_gimple_convert_expr                0x4119
+#define DW_TAG_gimple_dot_prod_expr               0x411A
+#define DW_TAG_gimple_eq_expr                     0x411B
+#define DW_TAG_gimple_exact_div_expr              0x411C
+#define DW_TAG_gimple_exc_ptr_expr                0x411D
+#define DW_TAG_gimple_field_decl                  0x411E
+#define DW_TAG_gimple_filter_expr                 0x411F
+#define DW_TAG_gimple_fix_ceil_expr               0x4120
+#define DW_TAG_gimple_fix_floor_expr              0x4121
+#define DW_TAG_gimple_fix_round_expr              0x4122
+#define DW_TAG_gimple_fix_trunc_expr              0x4123
+#define DW_TAG_gimple_float_expr                  0x4124
+#define DW_TAG_gimple_floor_div_expr              0x4125
+#define DW_TAG_gimple_floor_mod_expr              0x4126
+#define DW_TAG_gimple_function_decl               0x4127
+#define DW_TAG_gimple_ge_expr                     0x4128
+#define DW_TAG_gimple_goto_expr                   0x4129
+#define DW_TAG_gimple_gt_expr                     0x412A
+#define DW_TAG_gimple_imagpart_expr               0x412B
+#define DW_TAG_gimple_indirect_ref                0x412C
+#define DW_TAG_gimple_integer_cst                 0x412D
+#define DW_TAG_gimple_label_decl                  0x412E
+#define DW_TAG_gimple_label_expr                  0x412F
+#define DW_TAG_gimple_le_expr                     0x4130
+#define DW_TAG_gimple_lrotate_expr                0x4131
+#define DW_TAG_gimple_lshift_expr                 0x4132
+#define DW_TAG_gimple_lt_expr                     0x4133
+#define DW_TAG_gimple_ltgt_expr                   0x4134
+#define DW_TAG_gimple_max_expr                    0x4135
+#define DW_TAG_gimple_min_expr                    0x4136
+#define DW_TAG_gimple_minus_expr                  0x4137
+#define DW_TAG_gimple_misaligned_indirect_ref     0x4138
+#define DW_TAG_gimple_mult_expr                   0x4139
+#define DW_TAG_gimple_ne_expr                     0x413A
+#define DW_TAG_gimple_negate_expr                 0x413B
+#define DW_TAG_gimple_non_lvalue_expr             0x413C
+#define DW_TAG_gimple_nop_expr                    0x413D
+#define DW_TAG_gimple_obj_type_ref                0x413E
+#define DW_TAG_gimple_ordered_expr                0x413F
+#define DW_TAG_gimple_parm_decl                   0x4140
+#define DW_TAG_gimple_plus_expr                   0x4141
+#define DW_TAG_gimple_range_expr                  0x4142
+#define DW_TAG_gimple_rdiv_expr                   0x4143
+#define DW_TAG_gimple_real_cst                    0x4144
+#define DW_TAG_gimple_realign_load_expr           0x4145
+#define DW_TAG_gimple_realpart_expr               0x4146
+#define DW_TAG_gimple_reduc_max_expr              0x4147
+#define DW_TAG_gimple_reduc_min_expr              0x4148
+#define DW_TAG_gimple_reduc_plus_expr             0x4149
+#define DW_TAG_gimple_result_decl                 0x414A
+#define DW_TAG_gimple_round_div_expr              0x414B
+#define DW_TAG_gimple_round_mod_expr              0x414C
+#define DW_TAG_gimple_rrotate_expr                0x414D
+#define DW_TAG_gimple_rshift_expr                 0x414E
+#define DW_TAG_gimple_ssa_name                    0x414F
+#define DW_TAG_gimple_string_cst                  0x4150
+#define DW_TAG_gimple_trunc_div_expr              0x4151
+#define DW_TAG_gimple_trunc_mod_expr              0x4152
+#define DW_TAG_gimple_truth_and_expr              0x4153
+#define DW_TAG_gimple_truth_not_expr              0x4154
+#define DW_TAG_gimple_truth_or_expr               0x4155
+#define DW_TAG_gimple_truth_xor_expr              0x4156
+#define DW_TAG_gimple_uneq_expr                   0x4157
+#define DW_TAG_gimple_unge_expr                   0x4158
+#define DW_TAG_gimple_ungt_expr                   0x4159
+#define DW_TAG_gimple_unle_expr                   0x415A
+#define DW_TAG_gimple_unlt_expr                   0x415B
+#define DW_TAG_gimple_unordered_expr              0x415C
+#define DW_TAG_gimple_var_decl                    0x415D
+#define DW_TAG_gimple_vec_cond_expr               0x415E
+#define DW_TAG_gimple_vec_lshift_expr             0x415F
+#define DW_TAG_gimple_vec_rshift_expr             0x4160
+#define DW_TAG_gimple_vector_cst                  0x4161
+#define DW_TAG_gimple_view_convert_expr           0x4162
+#define DW_TAG_gimple_widen_mult_expr             0x4163
+#define DW_TAG_gimple_widen_sum_expr              0x4164
+#define DW_TAG_gimple_with_size_expr              0x4165
+
+#define DW_TAG_gimple_expr_table_first DW_TAG_gimple_abs_expr
+#define DW_TAG_gimple_expr_table_count \
+  (1 + DW_TAG_gimple_with_size_expr - DW_TAG_gimple_abs_expr)
+
+/* All of the statement types that do not also appear as
+   expressions.  */
+#define DW_TAG_gimple_asm_expr                    0x4200
+#define DW_TAG_gimple_asm_inputs                  0x4201
+#define DW_TAG_gimple_asm_outputs                 0x4202
+#define DW_TAG_gimple_asm_clobbers                0x4203
+#define DW_TAG_gimple_modify_expr                 0x4204
+#define DW_TAG_gimple_resx_expr                   0x4205
+#define DW_TAG_gimple_return_expr                 0x4206
+#define DW_TAG_gimple_switch_expr                 0x4207
+
+#define DW_TAG_gimple_stmt_table_first DW_TAG_gimple_asm_expr
+#define DW_TAG_gimple_stmt_table_count \
+  (1 + DW_TAG_gimple_switch_expr - DW_TAG_gimple_asm_expr)
+
+
+/* True if the return is of the form return a=b;  */
+#define DF_AT_gimple_return_assign                0x2000
+
+#define DW_AT_gimple_ssa_name                     0x2010
+#define DW_AT_gimple_ssa_name_version             0x2011
+#define DW_AT_gimple_decl                         0x2012
+#define DW_AT_gimple_decl_list                    0x2013
+#define DW_AT_gimple_type                         0x2014
+#define DW_AT_gimple_type_list                    0x2015
+#define DW_AT_gimple_tree_flags                   0x2016
+#define DW_AT_gimple_label                        0x2017
+
+#define DW_AT_gimple_bit_num                      0x2020
+#define DW_AT_gimple_bit_start                    0x2021
+
+#define DW_AT_gimple_cst_int                      0x2030
+#define DW_AT_gimple_cst_imag                     0x2031
+#define DW_AT_gimple_cst_real                     0x2032
+#define DW_AT_gimple_cst_string                   0x2033
+#define DW_AT_gimple_cst_generic                  0x2034
+#define DW_AT_gimple_is_real                      0x2035
+#define DW_AT_gimple_range_low                    0x2036
+#define DW_AT_gimple_range_high                   0x2037
+#define DW_AT_gimple_case_low                     0x2038
+#define DW_AT_gimple_case_high                    0x2039
+
+#define DF_AT_gimple_eh_may_contain_throw         0x2040
+#define DF_AT_gimple_eh_prev_try                  0x2041
+#define DF_AT_gimple_eh_catch                     0x2042
+#define DF_AT_gimple_eh_last_catch                0x2043
+#define DF_AT_gimple_eh_next_catch                0x2044
+#define DF_AT_gimple_eh_prev_catch                0x2045
+#define DF_AT_gimple_eh_allowed_exceptions        0x2046
+#define DF_AT_gimple_eh_region_number             0x2047
+
+#define DF_AT_gimple_bb_succs                     0x2050
+#define DF_AT_gimple_bb_edge_flags                0x2051
+
+#define DW_AT_main_offset                         0x2060
+#define DW_AT_main_size                           0x2061
+#define DW_AT_string_offset                       0x2062
+#define DW_AT_string_size                         0x2063
+#define DW_AT_name_offset                         0x2064
+#define DW_AT_name_size                           0x2065
+#define DW_AT_type_offset                         0x2066
+#define DW_AT_type_size                           0x2067
+
+#endif /* lto-dwarf2.h */

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