GENERIC
*******

The purpose of GENERIC is simply to provide a language-independent way of representing an entire function in trees.  To this end, it was necessary to add a few new tree codes to the back end, but most everything was already there.  If you can express it with the codes in gcc/tree.def, it's GENERIC.

Early on, there was a great deal of debate about how to think about statements in a tree IL.  In GENERIC, a statement is defined as any expression whose value, if any, is ignored.  A statement will always have TREE_SIDE_EFFECTS set (or it will be discarded), but a non-statement expression may also have side effects.  A CALL_EXPR, for instance.

It would be possible for some local optimizations to work on the GENERIC form of a function; indeed, the adapted tree inliner works fine on GENERIC, but the current compiler performs inlining after lowering to GIMPLE (a restricted form described in the next section). Indeed, currently the frontends perform this lowering before handing off to tree_rest_of_compilation, but this seems inelegant.

If necessary, a front end can use some language-dependent tree codes in its GENERIC representation, so long as it provides a hook for converting them to GIMPLE and doesn't expect them to work with any (hypothetical) optimizers that run before the conversion to GIMPLE. The intermediate representation used while parsing C and C++ looks very little like GENERIC, but the C and C++ gimplifier hooks are perfectly happy to take it as input and spit out GIMPLE.

Statements
==========

Most statements in GIMPLE are assignment statements, represented by GIMPLE_ASSIGN.  No other C expressions can appear at statement level; a reference to a volatile object is converted into a GIMPLE_ASSIGN.

There are also several varieties of complex statements.

Blocks
------

Block scopes and the variables they declare in GENERIC are expressed using the BIND_EXPR code, which in previous versions of GCC was primarily used for the C statement-expression extension.

Variables in a block are collected into BIND_EXPR_VARS in declaration order.  Any runtime initialization is moved out of DECL_INITIAL and into a statement in the controlled block. When gimplifying from C or C++, this initialization replaces the DECL_STMT.

Variable-length arrays (VLAs) complicate this process, as their size often refers to variables initialized earlier in the block. To handle this, we currently split the block at that point, and move the VLA into a new, inner BIND_EXPR.  This strategy may change in the future.

A C++ program will usually contain more BIND_EXPRs than there are syntactic blocks in the source code, since several C++ constructs have implicit scopes associated with them.  On the other hand, although the C++ front end uses pseudo-scopes to handle cleanups for objects with destructors, these don't translate into the GIMPLE form; multiple declarations at the same level use the same BIND_EXPR.

Statement Sequences
-------------------

Multiple statements at the same nesting level are collected into a STATEMENT_LIST.  Statement lists are modified and traversed using the interface in tree-iterator.h.

Empty Statements
----------------

Whenever possible, statements with no effect are discarded.  But if they are nested within another construct which cannot be discarded for some reason, they are instead replaced with an empty statement, generated by build_empty_stmt. Initially, all empty statements were shared, after the pattern of the Java front end, but this caused a lot of trouble in practice.

An empty statement is represented as (void)0.

Jumps
-----

Other jumps are expressed by either GOTO_EXPR or RETURN_EXPR.

The operand of a GOTO_EXPR must be either a label or a variable containing the address to jump to.

The operand of a RETURN_EXPR is either NULL_TREE, RESULT_DECL, or a MODIFY_EXPR which sets the return value.  It would be nice to move the MODIFY_EXPR into a separate statement, but the special return semantics in expand_return make that difficult.  It may still happen in the future, perhaps by moving most of that logic into expand_assignment.

Cleanups
--------

Destructors for local C++ objects and similar dynamic cleanups are represented in GIMPLE by a TRY_FINALLY_EXPR. TRY_FINALLY_EXPR has two operands, both of which are a sequence of statements to execute.  The first sequence is executed.  When it completes the second sequence is executed.

The first sequence may complete in the following ways:

 1. Execute the last statement in the sequence and fall off the end.

 2. Execute a goto statement (GOTO_EXPR) to an ordinary label outside the sequence.

 3. Execute a return statement (RETURN_EXPR).

 4. Throw an exception.  This is currently not explicitly represented in GIMPLE.

The second sequence is not executed if the first sequence completes by calling setjmp or exit or any other function that does not return.  The second sequence is also not executed if the first sequence completes via a non-local goto or a computed goto (in general the compiler does not know whether such a goto statement exits the first sequence or not, so we assume that it doesn't).

After the second sequence is executed, if it completes normally by falling off the end, execution continues wherever the first sequence would have continued, by falling off the end, or doing a goto, etc.

TRY_FINALLY_EXPR complicates the flow graph, since the cleanup needs to appear on every edge out of the controlled block; this reduces the freedom to move code across these edges.  Therefore, the EH lowering pass which runs before most of the optimization passes eliminates these expressions by explicitly adding the cleanup to each edge.  Rethrowing the exception is represented using RESX_EXPR.