Ada optimizations&mdash;an embedded systems view
Authors: Lawrence Collingbourne
Venue: Proceedings of the conference on TRI-ADA '90 (1990)

The simple definition of Ada optimization is uncontroversially stated as the generation of optimal code sequences and data representations for each and every source code program written by the user. In the embedded systems marketplace, `optimal` is taken to mean minimal code size and maximal execution speed. The requirements of embedded computing have more than expanded to fill the space created by advances in hardware technology. The consequence of this is that the cost, size and weight of embedded computers can be affected by as much as a factor of three by the quality of the Ada cross compiler used for software development. To meet this goal, designers of Ada compilation systems must employ a variety of important optimizations that together provide the performance demanded by critical real-time, embedded systems. The most important of these in the experience of the author in implementing the XD&trade; Ada family of cross-compilers may be summarized as the following: Efficient Run-time Organization The design of the run-time organization may not be traditionally thought of as an `optimization`, but if it is inefficient then no matter how good the local code generation is, programming in the large will never be optimal. Important optimizations are subprogram calling, exception handling and tasking implementation. Sub-optimal design in these areas leads to unacceptable overheads which cannot otherwise be overcome and eat into processor utilization. The major drawback with these optimizations, like others, is that they can be difficult to debug unless the debugger `understands` the optimizations, such as passing parameters in registers. Efficient Code Mapping Ada is a very large language and early implementations were content to implement code mappings for the general case, such as for array assignments, because the emphasis was on keeping in validation. With increased investment over time, compilers select more optimal code sequences according to the context of the construct being mapped. This is largely a middle phase function of the compiler and no amount of optimization later will compensate for its inefficiency. Embedded systems have strong requirements for efficient mappings is what might otherwise be fringe areas of the language, like partword operations and fixed point arithmetic. Source Code Transformations The Ada language contains may abstractions which aid software engineering principles, but which can result in very inefficient run-time overheads if implemented `directly`. By transforming the source code representation of compound statements, such as loops, case statements and tasking statements according to context, it is possible to significantly improve run-time performance. Tasking optimizations in this area include direct interrupts and server task transformations. These optimizations can upset source code correlation. Inlining of Subprograms Subprogram inlining is an important optimization for two reasons. Firstly, it eliminates the calling overhead, and when programming using Ada's separate compilation facilities and modern design methodologies many small functions can be encapsulated this way. However, it also enables the inlined code to be fully optimized in the context of the calling code sequence which will result in further optimization being made that could not otherwise have been applied. Selective Linking This is not a compiler optimization at all, but one applied by the linker. The overall code size of the program image can be reduced by including all subprograms not actually called. In some applications this may not amount to much, but when using Object Oriented Design (OOD) and reusable software components a significant amount of code can be eliminated. Further, elimination of 'dead' subprograms can simplify code verification in safety critical applications. This optimization can result in a large change in the program image for a small change in the source code. Global Optimization Under this banner I would include what many would think of when considering Ada optimizations. However, as I have tried to show, these are no more than the foundation of a good Ada compiler. They eliminate some inefficiencies that cannot be eliminated by either the programmer or the early transformation phases of the compiler and produced good local code sequences. Here is a list of some of the important ones: Common sub-expression elimination Code motion from loops and if/case statements Constant propagation and folding Unreachable code elimination Run-time check elimination Branch elimination Strength reduction Peephole optimizations Of less use to real programs, but nevertheless usually included, are optimizations such as eliminating unused variables and assignments. Register Allocation Good register allocation is the second foundation of an optimizing compiler. It is important that this is not just optimized locally, but across subprogram calls and to ensure that copying is eliminated wherever possible. Control over register pressure and spillage is important otherwise this 'optimization' becomes sub-optimal for large subprograms. It is important that compilers are evaluated performing real programs that do actual work. The 'standard' benchmarks can be over-optimized by compilers because they do not use the results of the operations and are not self checking. User-written benchmarks, while targeting specific language features of critical importance to the user, often fail very badly in this area. Benchmarks which subtract the execution time of two code sequences can even return negative values due to the effects of catches and processor optimizations being differentially applied! However good a compiler is, it will never produce the elusive `optimal` code. In fact conflicting requirements can often fail to be reconciled satisfactorily. One of the major embedded system requirements that can be destroyed by optimization is object code correspondence to the source code, although in general optimization reduces complexity in this area. The solution is to provide the user with control over the optimizations. However, there is one drawback to too much control: it becomes impossible to test the compiler for all optimization combinations. XD Ada has three major optimization modes and is tested in each: no optimization, optimization for time and optimization for space. In practice, time and space are closely linked, and the compiler uses space optimization to suppress space-inefficient transformations. Three classes of control are provided: On-off, for optimization and checks. Criteria, for time and space. Code correspondence, for inlining and code motion. The Ada language could be improved by further standardization, greater power of determinism and by giving the compiler implementer more flexibility. For example the rate monotonic scheduling theory and its associated enhancements show great potential for providing greater determinism in tasking applications which are predominantly periodic. However, there is currently too much generality in the language to apply this uniformly. Additional pragmas can be used in an implementation defined way to enable supporting run-time optimizations , particularly over queueing. However, the compiler needs to be able to reject the pragma to take greatest advantage of them, and then the separate compilation rules will require it to be conservative. What the user needs is the ability to be more specific about transformations and performance if necessary. How can an application be portable if the performance is not? The optimizations available in compilers today have matured significantly. Performances comparable to, or better than, optimizing `C` compilers. The reason for the improvement is increased investment over time, and growth in the understanding and experience of the implementers. We now have solutions for embedded Ada applications that will meet all but the most specialized requirements. Too much disturbance of the language will result in sub-optimal solutions once again in the short term. The ACM Portal is published by the Association for Computing Machinery. Copyright © 2010 ACM, Inc. Terms of Usage Privacy Policy Code of Ethics Contact Us Useful downloads: Adobe Acrobat QuickTime Windows Media Player Real Player