[< back to index](../doc_index.md)

# Macros and inlining

## Macros

Functions defined with the `macro` keyword are not actual functions, but they are used as syntax replacements.

It implies the following:

* macros must return `void`

* cannot be `inline`, `noinline` or `extern`

* can be `asm` - in this case, they should **not** end with a return instruction

* do not have an address

* their invocations cannot be used as expressions

* in case of `asm` macros, the parameters:

    * must be defined as either `const` (compile-time constants), `ref` (variables) or `register(XX)` (registers, where XX is the register you want to use)
    
    * at most one parameter can be defined as a register

* in case of non-`asm` macros, the parameters

    * must be defined as either `ref` (variables; default, may be omitted) `const` (compile-time constants), or `call` (expressions, which are evaluated every time they are used)
    
    * `ref` parameters exceptionally can have their type declared as `void`; such parameters accept variables of any type
    
    * `call` parameters exceptionally can have their type declared as `void`;
    such parameters accept expressions of any type, including `void`, however, you cannot assign from those expressions

* macros do not have their own scope (they reuse the scope from their invocations) – exceptions: the parameters and the local labels defined in assembly

* control-flow statements (`break`, `continue`, `return`, `goto`, `label`) are run as if places in the caller function

When invoking a macro, you need to pass variables as arguments to parameters annotated with `ref` and constants as arguments annotated with `const`.

Invoking a non-`asm` macro requires the types of variables via `ref` parameters to match precisely.
No type conversions are performed.
Exception: parameters of type `void` can accept a variable of any type.

For parameters defined as `const`, `register(XX)` or `call`, the usual type conversions are performed.

You can invoke a macro from assembly, by preceding the invocation with `+`

Examples:

    macro void inc_x() {
        x += 1
    }
    byte add_two_1(byte x) {
        inc_x()
        inc_x()
        return x
    }
    
    macro void inc(byte b) {
        b += 1
    }
    byte add_two_2(byte x) {
        inc(x)
        inc(x)
        return x
    }
    macro void perform_twice(void call f) {
        f
        f
    }
    byte add_two_3(byte x) {
        perform_twice(inc(x))
        return x
    }
    
    macro void add(byte b, byte v) {
        b += v
    }
    macro void retu(byte result) {
        return result
    }
    byte add_two_4(byte x) {
        add(x, 2)
        retu(x)
    }
    
    macro asm byte add_asm(byte ref b, byte const v) {
        LDA b
        CLC
        ADC #v
        STA b
        // no RTS!
    }
    byte add_two_5(byte x) {
        add_asm(x, 2)
        return x
    }
    
    macro asm byte add_asm_2(byte ref b, byte register(x) v) {
        TXA
        CLC
        ADC b
        STA b
        // no RTS!
    }
    byte add_two_6(byte x) {
        add_asm_2(x, 2)
        return x
    }
    

## Automatic inlining

You can control inlining behavior in several ways:

* functions declared with the `const` keyword called with constant arguments will always be inlined,
with the whole invocation being converted into a single constant, regardless of `inline` and `noinline` keywords;
calls with non-constant arguments are subject to the regular rules.

* functions declared with the `inline` keyword will be inlined if possible

* functions declared with the `noinline` keyword will never be inlined

* the remaining functions may be inlined only if the `-finline` command-line option is enabled
and the compiler decides the function is worth doing

## Automatic subroutine extraction

Subroutine extraction is the opposite of inlining.

When given the `-fsubroutine-extraction`, the compiler will attempt to extract common code fragments to new subroutines.
The code will get smaller and slower.

Generally, when using `-fsubroutine-extraction`, it's recommended to also use `-finline`.
This allows the compiler to first inline and optimize code and then extract it back when appropriate.
