Close

Internals: the asset of GOTO

A project log for reprint: modern printf

reprint is printf redone with decades of hindsight, revamping the semantics and syntax to make a function worthy of Hello World.

analog-twoAnalog Two 04/08/2016 at 12:063 Comments

TRIGGER WARNING: The following content may harm the sensibilities of those who hate GOTO.

The reprint_cb() is a state machine that interprets a format string and outputs characters based on its current state. It is natural in its control flow that from a single dispatch point, the correct code segment is executed to say, output a numeric digit or bitfield. Typically, state machines are implemented with an integer representing the state and a corresponding switch statement that peforms the dispatch.

On embedded systems this wastes space and time. switch() statements entail a lookup table at best, and a sequence of if statements at worst. Stepping through the generated code instruction by instruction makes one very aware of this waste. Consequently, I wanted to do what our forefather assembler programmers could do: JMP or BR to an arbitrary address. Unfortunately, these capabilities were banned from Standard C to protect the masses.

However, gcc supports labels as values. Thus, instead of maintaining an integer state, I can store a starting address to the segment I want to execute next (hint this is reprint's program counter). Instead of wading through if statements and jump table lookups, this is just a single instruction branch. The code size and execution time savings easily become apparent on an MSP430, which is the first embedded processor to run reprint.

References:

https://github.com/codehero/reprint/blob/b683bbac82bf796f5aa68ad6c2b894d698c5b4e7/src/reprint.c#L283-L299

https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html

Great write up by Eli Bendersky

http://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables

Discussions

K.C. Lee wrote 04/09/2016 at 03:28 point

If you want to save code space in an embedded, you wouldn't use a huge monolith print function in the first place.  Not every piece of  software would require the entire collection of formats and parsing is kind of a luxury if you worry about the code space for switch statements.  All  those fancy new features isn't helping with bloat.

I code a minimal set of simple individual libraries functions for formatting my data and my I/O drivers, so no switch statements needed and the complier linker would keep track of what's needed in my bare metal embedded code.

  Are you sure? yes | no

Analog Two wrote 04/09/2016 at 14:25 point

I agree with you 100%, but if you have the code space (and a little extra cycles) to spare then it's not an issue. For example, MSP430G2553 has 16KB of code space; reprint occupies a little under 3K; printf takes way more.

When you are writing an embedded web server with lots of different outputs, you sometimes save code space if all you need is a format string vs a series of function calls.

  Are you sure? yes | no

Eric Hertz wrote 04/09/2016 at 02:44 point

Ah hah! Always wondered how efficient switch() statements were... Been using them quite a bit lately. Gonna throw this in the ol' bag of tricks!

  Are you sure? yes | no