arduino / arduino/ArduinoCore-avr

Inline library functions based on constant-ness of arguments

Open
#352 8 comments 1 reaction 0 assignees View on GitHub
Dominant language
C
Stars
1.5k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

Many fundamental functions could be effectively inlined without causing significant binary size increase if they could be inlined only if certain arguments were constants, as in such a case significant parts of the function body would turn into dead code, and could be therefore eliminated.

Samples of this kind of functions include: `digitalWrite`, `digitalRead`, `analogWrite`, `analogRead`, `pinMode`, `turnOffPWM` and so on.

GCC apparently does not do this automatically, but it can be done. One way is as follows (let's take [`analogWrite`](https://github.com/arduino/ArduinoCore-avr/blob/3055c1efa3c6980c864f661e6c8cc5d5ac773af4/cores/arduino/wiring_analog.c#L104-L293) as an example):

```c
void analogWrite(uint8_t pin, int val)
{
// body...
}
```

If we accept to turn analogWrite into a macro, we can rewrite it as follows:

```c
#define analogWrite(pin, val) \
( __builtin_constant_p(pin) ? _analogWrite_inline((pin), (val)) : _analogWrite((pin), (val)) )

void _analogWrite(uint8_t pin, int val) {
_analogWrite_inline(pin, val);
}

inline __attribute__((__always_inline__)) _analogWrite_inline(uint8_t pin, int val) {
// body...
}
```

In this way, callsites that have a non-constant `pin` argument will get the regular `_analogWrite` function as they do today without causing any increase in binary size, whereas callsites that have a constant `pin` argument will get an inlined version, and constant propagation will take care of eliminating dead code. If done consistently, this would allow GCC to turn a call to e.g. `analogWrite(PIN, HIGH)` into the following:

```c
uint8_t oldSREG = SREG;
cli();
*reg |= regbit; // reg, regbit are constant
SREG = oldSREG;
uint8_t oldSREG = SREG;
cli();
*out |= outbit; // out, outbit are constant
SREG = oldSREG;
```

(that does not take much more space than the original call and that, potentially, opens up the potential, if all callsites use constant args, for `_analogWrite` and related functions to be completely omitted from the final binary)

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with cores/arduino/wiring_analog.c and the analogWrite implementation linked in the issue, then compare it with the related digitalWrite, digitalRead, analogRead, pinMode, and turnOffPWM functions. Investigate how constant and non-constant arguments are handled, and verify that constant call sites can eliminate dead code without increasing binary size for regular calls.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
embedded-iot
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.