Pre-Processers for Inlined C Code?
Scott Snell asks: "I have inherited the C code for an embedded system project that has run out of code space. The source code is highly fragmented and the compiler doesnt generate efficient code for stack handling. Ideally I would direct the compiler to 'inline' a lot of the functions but unfortunately it doesnt support the inline keyword. Using macros is dangerous and manually inlining is driving me crazy! What I need is a tool that will take the source files, look for the 'inline' keyword and generate new source files that are inlined. Any ideas?"
Porting it to a compiler that supports inline functions might be easier than manually inlining the functions, depending on how non-standard the C in your program is.
Regards, Guspaz.
Perl.
Unless I'm on crack, inlining all calls to a function is pretty much the same as replacing the function with a macro. The main difference between inlining and macros would be that the compiler can decide not to inline a function if it doesn't make sense (e.g., if the function is recursive and the compiler isn't up to iterative-izing it), whereas with macros you just can't do recursion safely.
Is using GCC not an option?
Does this compiler not use standard preprocessor directives like #include. All that is is an insert text file b into text file a. So instead of including headers you just include code files.
What compiler is being used? The inline keyword is not supported by ANSI C - it is a C++ feature. However many C compilers support a proprietary inline declaration. Examples:
Green Hills: __inline
Diab: __inline__
Others use: #pragma inline
So, RTFM. Also, check the docs for inlining optimizations.
Jeff
You're right: inline functions will generate larger compiled code sizes if the function is called often enough. However, it is not impossible that the overhead of calling the function generates more machine code than inlining the code. This would depend on the system he is targetting and the size/purpose of the function that is to be inlined.
On the other hand, I reread the post several times, and I'm probably wrong, but it almost sounds like he is running into a problem with "source code" space. Could it be that he is compiling the code on the embedded system?
At any rate, this post should be modded as Offtopic because it doesn't really attempt to answer the problem. I'm guess I'm just trying to figure out if there isn't maybe another solution.
Green Hills has proposed an Embedded C++ standard which is essentially ANSI C++ without exception handling, mutiple inheritance, namespaces, run time type identification, templates, or virtual base classes. It does support the C++ inline keyword. So the compiler will, when possible, expand functions as macros. This results in faster performance at the expense of larger code space, but smaller stack space.
There are few problems porting code from C to C++. It's actually more difficult to port from pre- to post-ANSI C++, e.g. because of changes to the definition of the for statement. A C++ compiler is more type strict then a C compiler, meaning that more operations between different fundamental data types will be flagged as errors.
EC++ won't result in tremendous code bloat, either. About the same order of ANSI C. Plus if this system continues to evolve, one can take advantage of easier memory allocation with new and delete as opposed to malloc and free.
Granted the original post asked about inlining C functions. But moving to C++ gives one portability, since the inline keyword is part of the ANSI C++ standard.
as using some strange non-standard tool or hack to get around this, or letting your code get really big and ugly from "manually inlining" everything.
Macros have their dangers, but at least their dangers are well understood, and should be familiar to anyone who is writing embedded C. It is the commonly used solution to your problem, which makes it nice for keeping your code maintainable.
If you use a trick to get around the problem, it will just be another thing to confuse the next person who has to maintain the code.
...the poster is already talking about ways to transform the text of the code, which almost certainly won't pay attention to type checking anyway. I'd rather have a macro that gets transformed when the code is compiled than run a Perl script to mangle the code once and have to maintain it thereafter. (Yes, I forgot about type checking when I wrote my reply.)
As our Asker noted, macros are dangerous. For example, let a macro processor replace
foo = bar(i++);
and you'd better hope that the parameter isn't used more than once in the function's code - otherwise i will get incremented too often - hello bugs!
Flip side, you can eyeball the most commonly used functions for safe-to-macro-inline candidates and save space just on them.
An el-crapo compiler could easily burn more bytes with call & return code than a small function would need inline.
Are there any dusty & old or not-so-essential hunks of this code that could be ditched? A badly-written section that could be rewritten much smaller? Wordy user interface stuff to edit down?
It's easy to make up & spread cool- and credible-sounding stuff. Finding & checking hard facts is hard work.
Their preprocessor happens also to be a complete C++ compiler. You don't have to use the rest of the C++ features. (You might, for example, want to turn off exception handling.)
Any half-assed preprocessor that just folds function bodies into line is likely to be much worse than using macros. The worst possible outcome is code that's in some weird private language that only your weird private tools understand. (Cf. Qt/KDE)
#include "function.i"
-I like my women like I like my tea: green-
Using M4 or some other preprocessor should alleviate a lot of the problems. You can use it to preprocess the code, before it gets to the C preprocessor. Possibly use a version of C-front, which outputs C code from C++, then just compile the C it outputs. Some of the C-front compilers support inlining no problem. Otherwise, it's relatively simple to follow the rules to make using straight C macros not be dangerous. Everything you pass to a macro is a locally declared variable, with no expressions, and it'll act just the way you want. It's a pain in the ass to remember, but then again, you are writting an embedded system.
Unless the functions to inline are *real* small. Think about it- if the function is f bytes in size inlined, and f+a bytes in size as a standalone, and it takes c bytes to call the standalone function, and the function is called in n places, then inlining the function everywhere takes f*n bytes, while calling it takes c*n + f + a bytes. If c f - ((f+a)/n), then it'll be cheaper (require fewer code bytes) to not inline f than to inline f. As n gets large, all you need is c f for it to be a win. How many bytes does it take to call a function? That's your target- if your function is more than a few lines of code (at best) you're probably better off not inlining the function.
I'd actually be inclined to go the other direction- is it possible to uninline things? If the code is doing similiar things in different places, is it possible to write a single function which is instead called in both places?
Barring that, other options include using a different complier- does gcc support your processor? I know gcc doesn't support everything under the sun- many 8- and 16-bit micros and DSPs aren't supported, for example. But if gcc is supported, it does pretty good on the stack space management and automatically inlining. Or you just might have to bite the bullet and spring for a larger rom/flash or larger cpu.
Brian
A tad heavy handed, but if everything else fails, you can always write your dream inliner yourself with Cil :
http://manju.cs.berkeley.edu/cil/cil001.html
This post was compiled with `% gec -O`. email me if you need the sources
I need to squeeze down some C code to fit into an embedded system. I can't tell you much about it, for example the processor type, what compiler I'm using, how much of the code is libraries and how much is our own code, or how far over the limit we are.
I think the problem can be solved by inlining functions. Yes, inlining. Even though this generally increases code size, I think it's the solution in this case. You don't have enough information to argue about this, so trust me. Just give me a solution. Can you write me a Perl program, for example? I told you that the word you are looking for is "inline". Is there anything else you need to know?
Using macros is dangerous and manually inlining is driving me crazy! What I need is a tool that will take the source files, look for the 'inline' keyword and generate new source files that are inlined.
Umm, isn't looking for the inline keyword and generating new source files dangerous as well?
Use awk.
Why? So you can con management into buying you that nifty O-reilly CD-ROM series for UNIX!
Worked for me...
In the future, I would want to not be isolated from my friends in the Space Station.
are you really saying that you've run out of space in the code segment? or that the call depth is exceeding the size of the stack?
That said, you are looking to refactor your software anyway, you might as well do it right, possibly starting with picking a newer more modern toolset, architecting the code differently to allow you to optimize for stack/code/data space, and many other factors. Will this take time, of course, but it might not take as long as a simple little hack, plus give you better results, and the ability to improve in the future. Will management buy it ??? Probably not, so just tell them you are inlining everything, and give them so much more out the back end.
I have mod points and I am not afraid to use them
Stack space? Inlining is not neccessarily going to solve this problem. Recursion is probably your problem. Also, make the stack larger if possible.
Instruction space? Inlining will most likely make this worse, except in extremely abstracted code where the overhead to make the function call is more than the inline expense.
The solution is to fix the compiler's stack handling. When the compiler is the problem, fix the compiler. I've never heard of an embedded systems project that didn't include someone hacking with the compiler.
Ideally I would direct the compiler to 'inline' a lot of the functions but unfortunately it doesnt support the inline keyword.
Changing the compiler to support the keyword is probably a pain in the butt. However, there are very few C compilers which don't support some form of the inline keyword. Double check your docs.
Using macros is dangerous...
Macros Dangerous? That's rediculous. I suppose creating some wierd perl script to munch through your source code ripping up inline functions and auto-generating C files that will never have the propper dependecies is safe?
This is crazy! Autogenerating code is a great way to totally fuck up your build system. You'll never get your dependencies right and you'll end up building your entire project every time. Writing a tool that will parse your source code and identify the inline keyword is *exactly* as complicated as making the compiler understand the inline keyword. Don't do some bizzare on-off wierd hack. Instead, if you really want to use inline, bust out your compiler source and get cranking. If you don't have the compiler source, bust out gcc source and get cranking porting gcc to your hardware.
Someone you trust is one of us.
On another note, I'm a compiler writer who's having problems writing my compiler. Does anyone who frequents Slashdot know of a tool that will take a language standard as its input, and generate a working, bug-free, efficient compiler? Barring that, is anyone proficient enough in Perl? That's the language I've been using to implement my compiler, and I find that it's great for parsing. And while you're at it, maybe you could...
To me a fix for fragmented code is not a new compiler or some inline magic.
FIX THE CODE! You will not regret a "re-mastering" of the problem.
Wouldn't inlining make things worse?
I don't think inline isn't part of the (old) C standard. It is part of the C++ standard and I believe it may have been when cfront was around. The original C++ compiler, cfront, worked by preprocessing C++ and spitting out C to a C compiler. If what I say is correct above it must have done what you ask. Therefore port the code to C++ (if you're using ANSI C this is most likely trivial) and cfront it. I believe a version of cfront may still be available.
Doesn't it make you feel good to know that our freedoms are protected by politicans, lawyers and journalists.
crucial.com
No data, no cry
I see this problem from another direction. ... but dont forget every language make possible to write almost everything. So what you realy need to think about is not the inline problem, but your code itself. I saw many programmers who try to fix their problem with some hacking, insted of trying to find and fix the real problem.
You are talking about inline, stack, hacking,
I think you have to think about your code functionality, and than you will be able to see how you can fix this problem witout any hacking. There is always a way to fix the real problem!
What you are trying to make is cover a bug with another bigger one! Dont be crazy!!
What you should do is planning and not hacking!
There is only one good solution: The simpliest!