

*************
The optimizer
*************

The compiler applies various optimizations to reduce code size and
increase performance.
This chapter describes how to control optimizations and highlights useful
aspects, rather than detailing every optimization applied.

Overview
========

By default, the compiler performs basic rewrites, optimizes code selection
for efficient instruction set utilization, and makes good use of the CPU's
internal registers.

The resulting application is generally well-suited for debugging,
as many optimization passes are disabled by default.

General settings
----------------

Optimizations can be broadly enabled using the following
command-line options.

``-O1``
^^^^^^^

Enable some optimization passes.

``--O2``
^^^^^^^^

Enable all provided optimization passes.

``--speed``
^^^^^^^^^^^

Allow application size to grow in order to make the application run
faster.

``--space``
^^^^^^^^^^^

Tune optimizations more towards making the application small. This is
the default.

.. index:: inlining; optimization, optimization; inlining
.. _inline:

Function inlining
=================

Function inlining expands a function's body at its call site, typically
increasing performance but potentially increasing code size.

Function inlining may be beneficial on code size for small functions
as the inserted function body becomes tailored to the particular code
surrounding it. Normally when making a function call there is a
calling convention that has to be followed which puts restrictions on
how registers are used.

Inlining is enabled by specifying at least ``-O1``.

The inline keyword
------------------

The ``inline`` keyword in C is sometimes misunderstood. Its purpose is
to expose a function body to many compilation units and hint that the
function may be inline expanded instead of making an ordinary call to it.
There is no guarantee that a function marked as ``inline`` is actually
inlined, this decision is taken by the compiler.
Futhermore, the compiler may also choose to inline functions that are
not marked as ``inline``.

Using the inline keyword
------------------------

A function marked as ``inline`` is normally placed in a header file to
allow it to be used by multiple compilation units:

.. code-block:: C

   inline max (int a, int b) {
     if (a > b) {
       return a;
     } else {
       return b;
     }
   }

An inline function can also be marked as ``static inline`` in a
similar way:

.. code-block:: C

   static inline max (int a, int b) {
     if (a > b) {
       return a;
     } else {
       return b;
     }
   }

You can use functions marked as ``inline`` or ``static inline`` in the
same way as any other function. They can be called and in that case
they may be subject to inline expansion and you can store it as a function
pointer and make calls to it using that function pointer.

There are two cases when a function marked as ``inline`` or
``static inline`` requires a separate copy of the function. First, the
compiler may choose to make an ordinary function call to it.
Second, a function marked as ``inline`` may be stored in a function
pointer.

Variants of inline functions
----------------------------

As hinted in the previous section, there are two kinds of inline
functions, plain ``inline`` and ``static inline``. As long as the
compiler chose to do inline expansion these two variants work
identically.
They differ when the compiler choose to not inline expand it and make
an ordinary function call instead.

``inline``
^^^^^^^^^^

A function is marked as ``inline`` does not cause the compiler to
generate a separate definition of the function. If such separate
function is needed, it is assumed that one compilation unit provides
the definition using the ``extern`` keyword:

.. code-block:: C

   extern inline max (int a, int b);

This should be placed in an ordinary C source file, not a header file.

In most cases you will need to tell the compiler to actually generate
such separate function using an ``extern`` declaration somewhere. If
you do not do this and the function is required by the application, a
linker error will result that tells you that the function is not
defined.

The main benefit of using ``inline`` rather than ``static inline`` is
that you are ensured that there will be at most one separate
definition of the function.

.. note::

   One subtle benefit which ``inline`` has over ``static inline`` is that if
   you really must expand the function inline, then you can omit the
   ``extern`` declaration of the function. The linker will then
   let you know that the required inline expansion did not happen.
   In this case you most likely want to specify the command-line
   option  ``--always-inline`` to ensure that the inliner is always
   used.


``static inline``
^^^^^^^^^^^^^^^^^^

The compiler will generate a ``static`` standalone version of a
``static inline`` function whenever there is a need for it.
Being ``static`` it is local to the compilation unit with no
external linkage.

This means that if you make use of the same ``static inline`` function
in several compilation units, there may be multiple copies of the
same function.

.. note::

   If you take the address of the same ``static inline`` function in
   different translation units then the result will not compare equal.

.. note::

   While it is slightly easier to use a ``static inline`` function as
   you do not need to provide a single ``extern`` declaration, it
   comes with the cost of potentially having duplicate code in the final
   application.

.. _controlling-inline-expansion:

Controlling inline expansion
----------------------------

The compiler will apply it own decisions on what to inline and when to
use normal function calls. Small simple functions and static
functions with only a single use are prime candidates for inline
expansion.

There are a couple of command-line options that allow for tuning which
functions are considered for inlining:

``--always-inline``
^^^^^^^^^^^^^^^^^^^

Always enable the inliner, no matter which optimization level is
used.

This is useful if you have functions that you always want to be inlined.

``--no-inline``
^^^^^^^^^^^^^^^^

Do not perform any inlining at all.

``--only-marked-as-inline``
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Only consider functions that have the ``inline`` keyword. This
prevents functions not marked as ``inline`` from being considered
for inlining.

``--strong-inline``
^^^^^^^^^^^^^^^^^^^^

Try to obey the ``inline`` keyword. This relaxes some of the
requirements, such as that the function must be small enough.
This is a strong hint that we really want functions marked for
inlining to be inlined. The compiler may still refuse to inline a
function.

.. index:: inlining functions; not inlined

.. note::

   There are a number of reasons why the compiler may refuse to inline
   a function, e.g. used recursively, there is no prototype, it uses a
   variable argument list or it uses variable length arrays.

``--inline-on-matching-custom-text-section``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Functions being placed in a custom section (using ``#pragma clang section``)
are only allowed to be inlined into a function that belongs to the same
custom section.

This is useful in situations when the memory system is being manipulated
and functions are placed in a custom section to control placement
to obey the memory setup. Especially if you have several such configurations
you may want to prevent functions from being inlined cross custom sections
as they may make assumptions on which section (memory placement) they are
being executed from.

.. index:: cross call; optimization, optimization; cross call

Cross call
==========

This optimization pass can sometimes result in quite significant
savings on the application size. It examines the almost final program
looking for instruction sequences that are identical. Such sequences
are lifted out to separate subroutines which are called instead. This
takes in account the size of the code sequences as well as how many
times they appear.

Controlling cross call
----------------------

Cross call is enabled by specifying at least ``-O2``.
Even though cross call is focusing on the application size, it is
enabled also when the ``--speed`` command-line option is specified, as
the savings on code space can sometimes be quite significant.

``--no-cross-call``
^^^^^^^^^^^^^^^^^^^

This option disables the cross call optimization. This can be used
with ``-O2`` when you want to avoid the subroutine call overhead that
cross call will introduce.

``--no-interprocedural-cross-jump``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This option disables the cross jump between functions optimization.
This can be used if you are manually mapping in functions by some bank
mechanism in a way so that not all functions in the same compilation
are visible at the same time.
