What change caused the largest reduction in code size? #264
-
Hello, After discovering this repository, I was inspired to spin my own version of printf functions with similar (but not identical) goals:
I feel like I've accomplished goals 1-3, but I am struggling a bit with goal 4. I've tried both plugging my code into godbolt compiler explorer and iterating through making some changes, recompiling, and looking at the size/generated code. In both situations I'm not seeing any optimizations I can make that affect the code size by more than like 10 bytes. When nanoprintf was being developed, were there any minor changes made that had an outsized affect on the compiled code size? Any low-hanging fruit I might have overlooked? Otherwise, were there any specialized programs or compiler options that helped you reduce the size? Obviously, I could make drastic changes to my code or rewrite it in assembly to reduce the size, but that would go against goal 1. (also, in that situation I would just use nanoprintf!) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
Yup, it gets really hard to keep things really tiny in C, and as soon as you drop into ASM you hit portability issues. Off the top of my head, there wasn't a single silver bullet, it was as you say: just constantly pasting the code into godbolt and studying the asm. Big wins:
There are also a bunch of micro-optimization wins: lines 402-413 look like buggy nonsense, but they're a way to express logic that can't otherwise be done in C, in a way that let me add the feature without increasing a single byte of object code because the compiler "understood" it. (https://github.com/charlesnicholson/nanoprintf/pull/245/files). I also got back a bunch of bytes by using array indices instead of pointers, and also by expanding out the various fields of Ultimately though, it's the result of a few years of staring at the assembly, coming up with ideas, trying them, and seeing what happens. I don't believe it's possible to make code like this "pretty" or "simple" while maintaining the tiny size and the feature/flag matrix intact. The code started off closer to your first goal, but then I just kept trading simplicity away for big size reductions, and ended up here. I don't have the hubris to claim that nanoprintf is optimal at all; I'd love to see a smaller version that's just as full-featured! But, it's definitely not simple to get there, no matter what your approach :) I do agree that nanoprintf is ugly and near-unreadable, and this project is the only time I've made these kinds of tradeoffs (intentionally, anyway...) |
Beta Was this translation helpful? Give feedback.
Yup, it gets really hard to keep things really tiny in C, and as soon as you drop into ASM you hit portability issues. Off the top of my head, there wasn't a single silver bullet, it was as you say: just constantly pasting the code into godbolt and studying the asm.
Big wins:
npf_putc_cnt
to increment the output buffer cursor for free, instead of having to increment the output buffer cursor at every point innpf_vpprintf
where …