Hello all. Sorry if this has already been answered, I couldn't find it anywhere on the forums or online.We're migrating a large amount of source code written in C from an older processor to an Altera FPGA. Does anyone know if there is a way to prompt Nios II to output the complete list of compiler optimization flags? The GCC compiler allows for a '-Q --help=optimizers' flag to list this sort of thing. I note that the first level of optimization (-O or -O1) is different between the GCC and the Nios II compilers. I'm not sure why some of the flags listed in the GCC literature aren't in the Nios II. For example, we're seeing the Nios II remove what it believes to be dead code, similar to what the GCC would do with a '-fdce' flag. However no such flag exists (as far as I can tell) for the Nios II. Simply disabling optimization altogether would be a solution to this issue, but I'd like to avoid doing that if possible. Any insight would be immensely appreciated!
The nios2 compiler is gcc, to get all the parameters use '--help -v'.I think that, with any level of optimisation, modern gcc will not generate code for C statements that cannot be executed. Why do you need instructions generated for code that can't be executed? If you are building a lot of code, you might find it worth while building gcc yourself from the archive on Altera's ftp site. Some of the gcc build options they've used (esp. for gcc4) are sub-optimal in many cases. There are also some patches that give better code for both gcc3 and gcc4.
dsl, thank you for the response!We design fault-tolerant vital systems, so we have code that really "should" never be reached, but in the event of a single-point hardware failure (e.g. a stuck bit) we need the system to take appropriate action. Hence the "dead code". I was hoping for an exhaustive list similar to this: http(slashslash)gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options (Sorry, can't post links on this forum, it says I'm too new). Nios II comes with similar documentation, however I'm pretty sure that there are a few optimization options happening that are not listed. I haven't ever worked on a compiler, so for all I know such a list may not be possible. However it looks like the GCC supports a "do not remove dead code" option, so I'm hoping that the Nios II might as well. Again, thanks!
Ah - I think -fdce got added for gcc 4.1, you are probably running gcc 3.4.5 for nios2.I found that the newer gcc generated worse code - but I didn't look where/why. My code was somewhat tweaked to avoid unwanted memory references and almost all cycle stalls. I'm not sure which 'stuck bits' (etc) you might have that leave the processor running well enough to test... You might find that defining some like:
#define XSTR(x)# x# define STR(x) XSTR(x)# define GCC_MEMBAR() asm volatile( "#gcc_membar, line " STR(__LINE__) "\n" : : : "memory" )(which tells gcc that any memory might be changed by the (non-existent) assembler). Then a GCC_MEMBAR() in the code will force gcc to write out values cached in registers, and re-read values from memory. This might let you do the checks you want. (I used it to control the number of live values and pressure on registers.)
That would essentially be telling the compiler that everything is volatile... interesting. We may have to go that route. I also was not aware that the NiosII is based on an earlier version of the GCC. Though I probably should have assumed so. Thank you for your help!
--- Quote Start --- We design fault-tolerant vital systems, so we have code that really "should" never be reached, but in the event of a single-point hardware failure (e.g. a stuck bit) we need the system to take appropriate action. Hence the "dead code". --- Quote End --- But compiler "dead code" - code which it removes is code it determined cannot and will not be executed. In a completely obvious example
if(1) do_something(); else do_something_else();The compiler will delete the else - it knows it can't get there no matter what you do or fault you have in your program. Maybe if you cite an example it will help us to understand what you mean by "dead code". I would think if the compiler removes dead code that really isn't dead, then the compiler is faulty and I'd be worried about using that in a fault-tolerant system, wouldn't you? Bill
Bill,Really good point, thanks for your reply! Truth be told, I should admit that I'm just the intern on this project trying to go the extra mile for my boss. So while I think I have a rough understanding of what we're doing, I can't say that I have completely mastered this code, and so there may very well be things in play here of which I am unaware. That said, I believe one reason we used dead code was to have the system actively detect hardware faults. Something like:
memory_location = SOME_VALUE; if !(memory_location == SOME_VALUE) faultyMemoryAlert();Now, without delving too far into what might prove to be tedious detail, there are probably redundant systems at work in the new setup that might make all of this "dead code" unnecessary. However, given a time constraint we are hoping to port as much of the previous system to the new one. (I've quickly learned that that the time granted for any given project is roughly = timeItTakesToDoItRight/4 ...) The current GCC has an optimization flag to opt out of dead code elimination, I just wanted to make sure that I wasn't overlooking a way to enable a similar flag in the NiosII compiler.
There are two things about this code example. First if you declare the memory_location as a volatile variable, I believe the compiler will not try to optimise this and force to read back the value after having read it (can a gcc guru confirm this?).Second on a hardware point of view, if the CPU has a data cache, when executing this code it will most probably read back this value from its cache rather than an external memory, meaning that this won't actually check the external memory. You'll have to declare this memory area as uncached. I'm just saying this to show you that you need to know the exact reasons why you would need those requirements, before finding out how to implement them. But you will learn about the compiler and the Nios II environment in the process ;)
Marking the data 'volatile', or using the asm statement I mentioned earlier, will force the compiler to generate the actual memory cycles - possibly just to the cache.Memory mapped IO registers should usually be marked 'volatile' (and be uncached), but if you are trying to verify the connections to cached or non-volatile 'memory' you need to force the compiler to flush any non-volatile data it has cached in registers, as well as flush and invalidate the data cache itself.
Thanks very much for the replies. Using volatile declarations and embedded assembly code where needed may well be what we end up doing - I think we were trying to avoid it just because it'll take up a good chunk of extra time to go through all the code and make the appropriate changes. On the bright side, I've now got a great opportunity to get some experience with assembly code!Again, thanks to everyone for the input.
You probably don't need to write any actual assembler, but it is probably worth learning to read the assembler to check (in a few places at least) that the compiler is doing what you want.Compiling with -S -fverbose-asm can make life a little easier.