1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-25 21:29:25 +00:00
millfork/docs/abi/inlining.md
Karol Stasiak 63ff28e94e Changes to macros and parameter list syntax:
* non-asm macros can now take `const` and `call` parameters
* register parameters to asm functions and macros can be given names if annotated explicitly
2020-03-30 19:23:48 +02:00

138 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[< 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.