Stripping dead code at Linking (dsPIC)

For Flowcode users to discuss projects, flowcharts, and any other issues related to Flowcode 5.
To post in this forum you must have a registered copy of Flowcode 5 or higher.

Moderator: Benj

Posts: 7
Joined: Sat Oct 27, 2018 5:04 am
Has thanked: 1 time
Been thanked: 8 times

Stripping dead code at Linking (dsPIC)

Postby kejam » Wed Feb 12, 2020 10:57 pm

I don’t know if this has been covered before, but a search didn’t reveal much.
I really like Flowcode for rapid application development, but one of the things that’s bugged me for a number of years, is the dead code, uncalled functions etc. that it compiles into the executable.
I have at times had to purchase a higher capacity chip, or delete the Flowcode components and write my own to get a project to work, which defeats the purpose of having a RAD system, and I find myself getting so anxious having to scan datasheets and pore over register settings, and time can stream by in a flash while searching for the missed bit that needs attention to make the peripheral work as required.

Over the last few days I’ve been working on a temperature monitor for environmental chambers and decided to use a small 8KB device I have lots of. So I lazily added the LED and ADC components and a bit of processing code and I was blown away to find that 50% of the chip was used up with optimization set for minimum size (-Os) I usually compile first with optimization at level 2 (-O2) as I have encountered weird stuff happening at times with increasing levels of compression. (89% usage at zero optimization)

In this program I use the ADC function FCD_ADC0_ReadAsInt, but included along with this in the compiled hex file are;

Along with these are a string of associated math functions that I never use in the course of the program.
So rather than starting from scratch and writing my own ADC macro I decided to try and find a solution to the bloating.

The compiler does support dead code removal at linking by using the garbage collection switch (--gc-sections). It also requires that there is no debug (-g) output and the file type must be .elf and not .cof.
It requires that the functions be compartmentalized for ease of stripping (-ffunction-sections) and there is also an option of doing the same with the data (-fdata-sections) but I seem to recall somewhere that this can cause strange things to happen, so I ignored this one.

With Flowcode calling two batch files to compile and link the code presented a bit of a problem. I found I needed to move the compilation and assembly into the linking script to get it to work.

With garbage collection enabled the program memory usage went from 50% down to 9% at optimization for size (-Os) and 12% at zero optimization (-O0)

I must add that I am using Flowcode V5 for dsPIC on an old Windows 7 box, and the compiler is C30 version 3.31, so I cannot guarantee that this will work for everyone the way it has for me.

There are two files you need to place in your Flowcode MX_Bats directory, for me it is situated here
C:\Program Files (x86)\Flowcode(dsPIC)\v5\Tools\MX_bats

You need to point to these in Flowcode (Sorry if this is egg suckingly boring, but others maybe old farts like me and appreciate the obvious being stated)
On Flowcode top menu, click on Build, and select Compiler Options.
On the Compiler Tab click Browse.
Now select your way to the MX_Bats directory where you copied the two files to.
At the bottom right of the page you will see a pulldown entitled Executable Files (*.exe)
Click on this and select All Files (*.*)
You should now see the files you copied over.
Select “Debloating-pic16_C30_COMPILER.bat”
You should now be back at the Compiler Options panel.
Select the Tab named Linker/Assembler
Click on Browse again
Once again select show All Files (*.*) on the bottom right of the page
You should now be able to see “Debloating-pic16_C30_LINKER_Level_2_Optimization.bat”
Select this and click OK on the Compiler Options panel.

Your project should now be optimized to level 2 and the program space should be free of dead code.

I have a number of different Linker batch files with different levels of optimization. I prefer Level 2 as I always get reliable code that doesn’t surprise me with weird stuff. I have one with no optimization as well and this sometimes helps debug a project if I suspect the compiler is at fault.
Open the Linker file in Notepad and you will see the optimization switch on the tenth line from the top and fifth term along i.e. -O2

Here are some notes from a compiler manual regarding this switch, although not PIC specific.

These options control various sorts of optimizations: -O

Without -O, the compiler's goal is to reduce the cost of compilation and to make debugging produce the expected results. Statements are independent: if you stop the program with a breakpoint between statements, you can then assign a new value to any variable or change the program counter to any other statement in the function and get exactly the results you would expect from the source code.
With -O, the compiler tries to reduce code size and execution time, without performing any optimizations that take a great deal of compilation time.
-O1 Optimize. Optimizing compilation takes somewhat more time, and a lot more memory for a large function.
-O2 Optimize even more. GCC performs nearly all supported optimizations that do not involve a space-speed tradeoff. The compiler does not perform loop unrolling or function inlining when you specify -O2. As compared to -O, this option increases both compilation time and the performance of the generated code. -O2 turns on all optional optimizations except for loop unrolling, function inlining, and register renaming. It also turns on the-fforce-mem option on all machines and frame pointer elimination on machines where doing so does not interfere with debugging. Please note the warning under -fgcse about invoking -O2 on programs that use computed gotos.
-O3 Optimize yet more. -O3 turns on all optimizations specified by -O2 and also turns on the -finline-functions and -frename-registers options.
-O0 Do not optimize.
-Os Optimize for size. -Os enables all -O2 optimizations that do not typically increase code size. It also performs further optimizations designed to reduce code size.
If you use multiple -O options, with or without level numbers, the last such option is the one that is effective.

If you are getting very low on RAM you could try reducing the heap allocation, the direction is also contained in this batch file i.e. (--heap=256)

This feature will allow me to quickly develop applications without fear of bloating out of room.
I hope it works for you too.

(1.15 KiB) Downloaded 14 times
(155 Bytes) Downloaded 18 times
These users thanked the author kejam for the post:
Benj (Thu Feb 13, 2020 11:26 am)
Rating: 5%

Posts: 7
Joined: Sat Oct 27, 2018 5:04 am
Has thanked: 1 time
Been thanked: 8 times

Re: Stripping dead code at Linking (dsPIC)

Postby kejam » Thu May 14, 2020 5:57 am

I've been using the above process for a while now, but thought I should pop back and report a problem I've encountered with it.

The configuration parameters are not saved inline so each time I compile the code and reflash a chip during development I have to reenter the config settings into the IPE. Once the development process is completed I read back from a chip and export the hex file from IPE, this file has the config setting embedded so in future whenever a chip needs programming there's no need to try and remember the settings again.

It is a bit of a hassle but the extra capacity it allows gives a lot of headroom if your program is inflating towards a bigger device.

These users thanked the author kejam for the post:
Benj (Fri May 15, 2020 11:45 am)
Rating: 5%