Freescale Semiconductor StarCore DSP Development Studio, C Compiler User Guide
PDF
Document
Advertentie
Advertentie
Freescale Semiconductor, Inc. MWEntComp.book Page 1 Monday, September 27, 2004 2:17 PM CodeWarrior™ Development Studio for StarCore® DSP Architectures v2.6 Metrowerks Enterprise C Compiler User Guide Revised 24 September 2004 For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 2 Monday, September 27, 2004 2:17 PM Metrowerks and the Metrowerks logo are registered trademarks of Metrowerks Corporation in the United States and/or other countries. CodeWarrior is a trademark or registered trademark of Metrowerks Corporation in the United States and/or other countries. All other trade names and trademarks are the property of their respective owners. Copyright © 2003, 2004 Metrowerks Corporation. ALL RIGHTS RESERVED. No portion of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, without prior written permission from Metrowerks. Use of this document and related materials are governed by the license agreement that accompanied the product to which this manual pertains. This document may be printed for non-commercial personal use only in accordance with the aforementioned license agreement. If you do not have a copy of the license agreement, contact your Metrowerks representative or call 1-800-3775416 (if outside the U.S., call +1-512-996-5300). Metrowerks reserves the right to make changes to any product described or referred to in this document without further notice. Metrowerks makes no warranty, representation or guarantee regarding the merchantability or fitness of its products for any particular purpose, nor does Metrowerks assume any liability arising out of the application or use of any product described herein and specifically disclaims any and all liability. Metrowerks software is not authorized for and has not been designed, tested, manufactured, or intended for use in developing applications where the failure, malfunction, or any inaccuracy of the application carries a risk of death, serious bodily injury, or damage to tangible property, including, but not limited to, use in factory control systems, medical devices or facilities, nuclear facilities, aircraft navigation or communication, emergency systems, or other applications with a similar degree of potential hazard. How to Contact Metrowerks Corporate Headquarters Metrowerks Corporation 7700 West Parmer Lane Austin, TX 78729 U.S.A. World Wide Web http://www.metrowerks.com Sales United States Voice: 800-377-5416 United States Fax: 512-996-4910 International Voice: +1-512-996-5300 E-mail: [email protected] Technical Support United States Voice: 800-377-5416 International Voice: +1-512-996-5300 E-mail: [email protected] For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 3 Monday, September 27, 2004 2:17 PM Table of Contents 1 Introduction 9 Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Cross-File Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Compiling Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2 Getting Started 11 Overview of the Development Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Creating and Running a Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3 Using the Metrowerks Enterprise C Compiler 13 Compiler Shell Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Compilation Stages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Cross-File Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 File Types and Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Invoking the Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Shell Control Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Option Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Controlling Shell Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Specifying Preprocessing Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Overriding Input File Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Output Filename and Location Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Specifying C Language Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Passing Options to Specific Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Setting Listing, Messages Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 Specifying Hardware Model, Configuration . . . . . . . . . . . . . . . . . . . . . . . . . 37 Language Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 C Language Dialects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Types and Sizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Fractional and Integer Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 Intrinsic Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Pragmas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 3 Freescale Semiconductor, Inc. MWEntComp.book Page 4 Monday, September 27, 2004 2:17 PM Table of Contents Predefined Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .98 4 Mixing C, Assembly Code 101 Inlining One Assembly Instruction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .101 Inlining an Assembly Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102 Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102 Defining an Inlined Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .103 Calling a Function in a Different File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .107 Writing the Assembly Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108 Calling the Assembly Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108 Integrating C, Assembly Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109 Including Offset Labels in Output File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .110 5 Runtime Environment 113 Startup Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113 Bare Board Startup Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .115 C Environment Startup Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .115 Configuring Your Startup Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116 Memory Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117 Memory Layout and Configuration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119 Stack and Heap Configuration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120 Static Data Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122 Configuring the Memory Map. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122 Machine Configuration File. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .123 Controlling Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126 Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126 Section Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .128 Section Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .129 Variable Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .130 Control Option Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .131 Calling Convention Setting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .133 Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .134 Affect on S1 Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .137 Calling Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .138 Stack Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .138 4 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 5 Monday, September 27, 2004 2:17 PM Table of Contents Stack-Based Calling Convention. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Stack Frame Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Creating a Calling Convention . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 Interrupt Handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 Frame and Argument Pointers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 Hardware Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Operating Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 6 Runtime Libraries 159 Character Typing and Conversion (ctype.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 Floating-Point Characteristics (float.h). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Floating-Point Library Interface (fltmath.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 Round_Mode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 FLUSH_TO_ZERO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 IEEE_Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 EnableFPExceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Integer Characteristics (limits.h). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 Locales (locale.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 Floating-Point Math (math.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Program Administrative Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 I/O Library (stdio.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 General Utilities (stdlib.h). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 String Functions (string.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Time Functions (time.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 7 Optimization Techniques and Hints 181 Optimizer Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 Code Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 Basic Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Linear and Parallelized Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Optimization Levels and Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 Using the Optimizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Invoking the Optimizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 Optimizing for Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 Cross-File Optimizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 5 Freescale Semiconductor, Inc. MWEntComp.book Page 6 Monday, September 27, 2004 2:17 PM Table of Contents Optimization Types and Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .187 Dependencies and Parallelization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .188 Target-Independent Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .188 Target-Specific Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203 Optimizer Assumptions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .216 A Icode Options and Option Files 217 Specifying Icode Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .217 Option File Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .217 ICode Options List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .218 B Induction-Related Loop Optimizations 221 Loop Detection and Normalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .221 Detecting Hardware-Mappable Loops. . . . . . . . . . . . . . . . . . . . . . . . . . . . .221 Normalizing Hardware Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .225 Loop-Invariant Code Motion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .226 Scalarization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .227 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .227 Scalarization Result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .228 Pointer Promotion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .230 Single-loop Induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .231 Simple Induction Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .232 Multi-Step Induction Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .235 Composition of Induction Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .238 Wraparound Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .241 Monotonic Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .242 Modulo-Induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .243 Bit-Reverse Induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251 Min/Max Function Induction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .257 Simplifying Redundant IVs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .259 Sequential Accesses, Related Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . .263 Transformation Control Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .264 Simplifying Redundant Memory Accesses . . . . . . . . . . . . . . . . . . . . . . . . .271 Access Packing (Vectorization) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .274 Cross-Loop Induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .280 6 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 7 Monday, September 27, 2004 2:17 PM Table of Contents Simple Matrix Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 Cross-File Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 Controlling Cross-Loop Induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295 C Loop Restructuring and Reordering 297 Loop-Collapse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 Loop Peeling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 Loop Unrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 Loop Unrolling Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 Loop Unrolling Example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 Loop Unroll-and-Jam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 Loop Unroll-and-Jam Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 Unroll-and-Jam Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 Loop Multi-Sampling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 Multi-Sampling Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 Multi-Sampling Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 Partial Summation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315 Partial Summation Restrictions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 Immediate Accumulator Example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 Array-Cell Accumulation Example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 D Loop Restrictions 323 Choosing Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 Single-Loop Induction Limitations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 Induction Variable Redefinition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 Ambiguous Definition Due to Function Call . . . . . . . . . . . . . . . . . . . . . . . 326 Multiple Conditional Induction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 Second Order Induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 Cross-Loop Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 Loop Step General Restriction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 Reused Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 Implicit Cross-Loop Combination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 Conditional Inner Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 Bypassed Inner Loop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 Sequential Access, Packing Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 7 Freescale Semiconductor, Inc. MWEntComp.book Page 8 Monday, September 27, 2004 2:17 PM Table of Contents Aliasing and Conflicting Interleaved Read/Write Accesses . . . . . . . . . . . .338 Aliasing and Interprocedural Effect. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .340 Missing Initial Alignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .341 Case Study: G729 cor_h Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .342 Step 1: Removing Reused IVs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .344 Step 2: Removing Implicit Cross-Loop Combination . . . . . . . . . . . . . . . . .346 Step 3: Removing Redefined IVs from Outer Loop . . . . . . . . . . . . . . . . . .347 E Migrating from Other Environments 351 Code Migration Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .351 Migrating DSP56600 Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .352 Integer Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .352 Fractional Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .352 Floating-Point Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .353 Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .353 Fractional Arithmetic. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .353 Inlined Assembly and C Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .354 Intrinsic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .354 Pragmas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .355 Interrupt Handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .356 Storage Specifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .356 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .357 Migrating TI6xx Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .357 Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .357 Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .357 Pragmas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .358 Inlined Assembly Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .358 Intrinsic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .358 F Modulo Addressing Example 359 Index 8 365 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 9 Monday, September 27, 2004 2:17 PM 1 Introduction This manual explains the features of the Metrowerks Enterprise C compiler and explains how to use it from the command line. This Enterprise C compiler is part of the CodeWarrior™ for StarCore™ DSP Architectures product. For information that explains how to use this compiler with the CodeWarrior IDE, see the CodeWarrior™ for StarCore™ DSP Architectures Targeting Manual. This chapter contains these sections: • Overview • Cross-File Optimization • Compiling Applications Overview A key feature of the Metrowerks Enterprise C compiler is its ability to generate code that is exceptionally compact. This code approaches the density of the best RISC microprocessors, while demonstrating high performance comparable to assembly code running on other DSP devices. To achieve such a high performance, the compiler optimizes code for maximum parallelism. This takes full advantage of the core’s multiple execution units. In addition to its extensive optimization capabilities, the compiler offers many other features that make it ideal for DSP software development, including: • Conformance to the ANSI C standard • Intrinsic function support for ITU/ETSI primitives: saturating, non-saturating, and double-precision arithmetic • Runtime libraries and environments • Easy integration of assembly code into C code Cross-File Optimization The SC100 optimizer converts preprocessed source files into assembly-language output code, applying a range of code transformations that can significantly improve the Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 9 Freescale Semiconductor, Inc. MWEntComp.book Page 10 Monday, September 27, 2004 2:17 PM Introduction Compiling Applications efficiency of the executable program. The optimizer improves code performance in terms of execution time or code size, by producing output code that is functionally equivalent to the original source code. Traditional compilers optimize each source file individually, before compiling the optimized code and submitting all the compiled files to the linker. But this individual optimization of files means that not all information is available during optimization. Consequently, the compiler must make certain assumptions, so cannot produce the most efficient result. For optimal performance, the optimizer should examine as much of the application as possible. The SC100 global binder links all modules into a single module; the compiler can perform all optimizations on this single module. This cross-file approach sub tan ti ally improves the performance of the optimizer. The resulting generated code usually is more efficient than code produced without cross-file optimization. Compiling Applications SC100 compiling begins with submitting source files and options to the C Front End (CFE). It continues with the creation of Intermediate Representation (IR) files and the optimization of these files. Finally, this process outputs optimized assembly code for linking into the final executable program. The compiler shell program lets perform all these compiler processes as one single step. Chapter 3 explains more detail about the compiler shell and the stages of C compiling. 10 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 11 Monday, September 27, 2004 2:17 PM 2 Getting Started This chapter explains how to build and run a simple program using the Metrowerks Enterprise C compiler. This chapter contains these sections: • Overview of the Development Process • Creating and Running a Program Overview of the Development Process At a high level, this is the process for creating and executing programs at the command line: 1. Write your program’s C language source code using the editor of your choice. 2. Compile and link your source code files using the compiler shell. 3. Run the executable file. Creating and Running a Program To create and run a program from the command line, follow these steps: 1. Start a text editor, such as vi or Notepad. 2. Type (or copy and paste) the C source code of Listing 2.1 into the editor window. Listing 2.1 Sample C Language Source Code: hello.c #include <stdio.h> void main() { printf("Hello there!\n"); } 3. Save the source code in a file named hello.c in your working directory. 4. Exit the text editor. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 11 Freescale Semiconductor, Inc. MWEntComp.book Page 12 Monday, September 27, 2004 2:17 PM Getting Started Creating and Running a Program 5. At the command line, type scc -o hello.eld hello.c The shell program compiles and links hello.c to build the executable file hello.eld. 6. At the command line, type runsc100 hello.eld Your computer runs hello.eld and displays the output message Hello there! You have successfully used the Metrowerks Enterprise C compiler to compile, link, and execute a program. 12 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 13 Monday, September 27, 2004 2:17 PM 3 Using the Metrowerks Enterprise C Compiler This chapter explains how to use the Metrowerks Enterprise C compiler. It also describes the options and features that the compiler supports. This chapter contains these sections: • Compiler Shell Program • Invoking the Shell • Shell Control Options • Language Features Compiler Shell Program The shell program controls the processing of C source files and other files into an executable application, through the preprocessing, compilation, optimization, assembly, and linking stages. The shell provides a one-step command-line interface, which you use to specify the files for each compilation. At each stage, a different tool accepts input files according to their file extensions, processes these files, then outputs the transformed code to the next development tool. The default arrangement is that the input files automatically progress through all the processing stages. The command line lets you select the exact development tools and processing stages that you require. You also use the command line to define any options, settings, or default overrides that are appropriate for your application. Compilation Stages Figure 3.1 depicts the stages of compiling C source files into an executable program. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 13 Freescale Semiconductor, Inc. MWEntComp.book Page 14 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Compiler Shell Program Figure 3.1 The C Compilation Process STAGE 1 C source files SHELL STAGE 2 Library IR files C Front End (CFE) Intermediate Representation (IR) files Application, machine configuration files STAGE 3 STAGE 4 Target-independent, target-specific optimizations Optimized assembly code External assembly files STAGE 5 ASSEMBLER Library object modules LINKER Executable program Stage 1 — You invoke the shell, specifying the C source files and assembly files to be processed, and specifying the appropriate options. Stage 2 — The C Front End (CFE) identifies C source files by their file extension, preprocesses the source files, converts the files to Intermediate Representation (IR) files, then passes these converted files to the optimizer. 14 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 15 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Compiler Shell Program Stage 3 — In the high-level optimizer phase, the optimizer translates each IR file to an assembly ASCII file, then performs target-independent optimizations. The optimizer can extract library files created in IR form, including these library files at this stage of processing. Additionally, optimization includes any relevant information that the application and machine-configuration files contain. The output of this stage is linear assembly code. Stage 4 — In the low-level optimizer phase, the optimizer carries out target-specific optimizations. It transforms the linear assembly code to parallel assembly code. Stage 5 — The optimizer sends the optimized assembly files to the assembler. The assembler assembles these files, together with any specified external assembly files, outputting these files to the linker. The linker combines the assembly object files, together with any specified external assembly files, extracts any required object modules from the library, and produces the executable application. Cross-File Optimization The SC100 optimizer converts preprocessed source files into assembly output code. It applies a range of code transformations that can significantly improve the efficiency of the executable program. The optimizer’s goal is producing code that is functionally equivalent to the original source code, yet which executes in less time or has a smaller size. Figure 3.2 represents traditional optimization: the compiler optimizes each source file individually, before compiling the optimized code. Then the compiler submits all the compiled files to the linker. But this individual optimization means that not all appropriate information is available to the optimizer. Accordingly, the compiler must act according to various assumptions. In turn, this means that the resulting code is not the most efficient possible code. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 15 Freescale Semiconductor, Inc. MWEntComp.book Page 16 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Compiler Shell Program Figure 3.2 Traditional Optimization C source file 1 C source file 2 C Front End C Front End IR file 1 IR file 2 OPTIMIZER OPTIMIZER Optimized code 1 Optimized code 2 ASSEMBLER ASSEMBLER ... C source file n C Front End ... IR file n OPTIMIZER ... Optimized code n ASSEMBLER LINKER For optimal performance, the SC100 optimizer examines as much of the application as possible. Its global binder links all modules into a single module, then performs all optimizations on this one module. This cross-file approach (Figure 3.3) substantially improves optimizer performance. Its generated code almost always is more efficient than code produced without cross-file optimization. 16 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 17 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Compiler Shell Program Figure 3.3 Cross-File Optimization C source file 1 C source file 2 C Front End C Front End IR file 1 IR file 2 ... C source file n C Front End ... IR file n ... Optimized code n OPTIMIZER Optimized code 1 Optimized code 2 ASSEMBLER ASSEMBLER ASSEMBLER LINKER Traditional optimization means faster compilation, but produces less-optimized code. Accordingly, traditional optimization may be appropriate during the early stages of development, particularly if you must compile different parts of the application separately. Cross-file optimization produces more efficient code, but increases overall compiling time. NOTE The shell’s default setting is to compile source files without cross-file optimization, for development purposes. When cross-file optimization is appropriate, you specify this option as you invoke the shell. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 17 Freescale Semiconductor, Inc. MWEntComp.book Page 18 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Compiler Shell Program File Types and Extensions The shell program recognizes the options and option arguments in your command line; it treats all other command-line items as the names of input files. Each filename extension identifies the file type, determining at which stage the shell will start processing the file. If none of the compiler tools recognize a filename extension, the compiler treats the file as an input file for the linker. Table 3.1 lists the filename extensions and their corresponding file types. The table also shows which compiler tool processes each file type. Table 3.1 File Types and Extensions Extension File Tool .c C source file C Preprocessor .h C header file .i Preprocessed C source Front End .obj IR language file Optimizer .lib IR library Optimizer .s1 IR linear assembly file Optimizer .asm, .sl Assembly file Assembler .eln Relocatable ELF object file Linker .cmd, .mem Linker command file Linker NOTE It is possible to force the shell to process a file as if it were a different file type. The final result of compilation is an executable object file, which has the filename extension .eld. Figure 3.4 shows filename extensions at each stage of shell processing. 18 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 19 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Compiler Shell Program Figure 3.4 File Extensions in the Shell Cycle C source files SHELL C Preprocessor .i Library IR files C Front End (CFE) .obj .lib Application, machine configuration files OPTIMIZER .sl External assembly files ASSEMBLER Library object modules .asm .eln .elb LINKER .eld Executable program Environment Variables During shell execution, environment variables determine specific aspects of shell behavior. The definition of these environment variables takes place during installation. These variables are: • $SCTOOLS_HOME — Defines the root directory: the storage location for the configuration files, executable files, libraries, and tools. Installation sets this variable to its default value. • SAXOHOME — Set to SCTOOLS_HOME/etc during installation. The high-level optimizer uses this variable. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 19 Freescale Semiconductor, Inc. MWEntComp.book Page 20 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Invoking the Shell If you want to place certain tools in non-default locations, you can define the environment variables listed below. Each lets you specify the location of the related tool. • COBJ_PATH — path to the C front-end • ICODE_PATH — path to the high-level optimizer • LLT_PATH — path to the low-level optimizer Invoking the Shell To invoke the shell, enter a single command line at a UNIX® or MS-DOS® prompt. This command line consists of the shell invocation command, one or more file names, plus any appropriate shell options. The syntax of the shell command line is: scc [option...] file... Table 3.2 describes the command line syntax items: Table 3.2 Command Line Syntax Descriptions Syntax Item Description scc (Formerly ccsc100). Invokes the compiler shell. option One or more shell options. These options control how the shell and the development tools operate. file The names (including extensions) of the files that the shell is to process — source, object, library, or command files. These syntax rules apply: • The command line must consist of only one line. • Individual options and filenames in the command line can be in any order. • At least one space must separate options and filenames. • Option specifications must be individual; you may not combine them. • Option arguments, such as filenames or directory names, must immediately follow their options; at least one space must separate options and arguments. • All filenames, options, and arguments are case sensitive. Filenames may be any combination of alphanumeric characters and the underscore (_) character. The shell command line of Listing 3.1 specifies three C source files and the option -c, which instructs the shell to compile and assemble these files. 20 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 21 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Listing 3.1 Invoking the Shell scc -c one.c two.c three.c The command line can include one or more shell command files. These are files that you can create, files that contain any number of options and arguments. The shell uses a shell command file as if it were part of the command line. Shell Control Options The options in the command line (and in shell command files) control how the shell and other development tools operate. This section explains these control options, Topics are: • Option Summary • Controlling Shell Behavior • Specifying Preprocessing Options • Overriding Input File Extensions • Output Filename and Location Options • Specifying C Language Options • Passing Options to Specific Tools • Setting Listing, Messages Options • Specifying Hardware Model, Configuration Option Summary The StarCore build tools support these categories of command-line options: • Shell behavior control • Preprocessing • Output file extensions • Output filename and location • C language • Optimization and code • Passthrough • Listing file and message output • Hardware model and configuration • Library and other Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 21 Freescale Semiconductor, Inc. MWEntComp.book Page 22 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.3 is a summary of the available options. Table 3.3 Shell Options Summary Option Category Shell Option Effect Shell Behavior Control -C Compiles and assembles only; does not invoke linker. -cfe Stops after Front End; does not invoke optimizer. Enables creation of object-file libraries, for use with cross-file optimization. -E [file] Stops after preprocessing source files; removes comments. -F file Reads additional shell options from specified file; appends them to command line. -h or none Displays the shell Help page: invocation syntax and all available options. -S Stops after compilation; does not invoke assembler. -C [file] Preprocesses only, preserving comments. -Dmacro Defines specified preprocessor macro. (No space required before macro name.) -Idir Adds specified directory to include file paths. (No space required before directory name.) -M [file] Preprocesses only, generating dependencies in make syntax. -MH [file] Preprocesses only, generating a list of #include files. -Umacro Undefines specified preprocessor macro. (No space required before macro name.) -xasm file Treats specified file as .asm assembler source file. -xc file Treats specified file as C source file. -xobj file Treats specified file as intermediate code file. -o file Assigns specified name to output file. -r dir Redirects all output to specified directory. Preprocessing Output File Extensions Output Filename, Location 22 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 23 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.3 Shell Options Summary (continued) Option Category Shell Option Effect C Language -ansi Specifies strict ANSI mode: all C source files must be in ANSI/ISO C, with no extensions. (Default mode is ANSI/ ISO C with extensions.) -g Adds DWARF debug information to generated files. -ge Adds DWARF debug extensions to generated files. -kr Specifies K&R/pcc mode: all C source files must be in K&R/pcc C. (Default mode is ANSI/ISO C with extensions.) -sc Makes char type variables signed. (Default setting.) -usc Makes char type variables unsigned. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 23 Freescale Semiconductor, Inc. MWEntComp.book Page 24 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.3 Shell Options Summary (continued) Option Category Shell Option Effect Optimization and Code -align Forces alignment: 0 = disable alignment; 1 = align hardware loops; 2 = align hardware and software loops; 3 = align all labels; 4 = align all labels and function call return points. -mod Enables modulo buffer support. -O (or -O2) Default: Performs all optimizations, with high-level local register allocation; produces optimized, non-linear assembly code. (Usually not as effective as -O3 low-level global register allocation.) -O0 Disables all optimizations; produces unoptimized assembly code. -O1 Performs all ICODE optimizations; disables the LLT optimization. -O3 Performs enhanced register allocation. -Og Performs optimization across source file boundaries. -Os Adds space optimization to existing level of optimization; reduces size of assembly code. (Not valid with level O0.) -u0 Disables loop unrolling. -u2 Enables loop unrolling, with maximum unrolling factor 2. -u4 Enables loop unrolling, with maximum unrolling factor 4. -Xasm option Passes specified options and arguments to the assembler. -Xcfe option Passes specified options and arguments to the front end. -Xicode option Passes specified options and arguments to the highlevel optimizer. -Xllt option Passes specified options and arguments to the low-level optimizer. -Xlnk option Passes specified options and arguments to the linker. Passthrough 24 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 25 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.3 Shell Options Summary (continued) Option Category Shell Option Effect Listing File, Message Output -dc [0-4] Generates postscript call tree file; integer value 0 — 4 specifies paper size A0 — A4. -de Keeps generated error file for each source file. -dL [file] Generates default C list file for each (or specified) source file. -dL1 [file] Generates C list file with includes for each (or specified) source file. -dL2 [file] Generates C list file with expansions for each (or specified) source file. -dL3 [file] Generates a C list file with includes and expansions for each (or specified) source file. -dm [file] Generates a link map file. -do Generates structure field definition offsets, as EQUs. -dx [file] Generates a cross-reference information file. -n Displays command lines without executing them. -q or -w Quiet mode: displays errors only. (Default setting.) -s Makes compiler keep all assembly language (.sl) files that it generates). (The shell still can performing assembly and linking.) -v Verbose mode: displays full information. -Wall Reports all warnings and remarks. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 25 Freescale Semiconductor, Inc. MWEntComp.book Page 26 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.3 Shell Options Summary (continued) Option Category Shell Option Effect Hardware Model, Configuration -arch [target] Specifies target architecture, such as sc110, sc120, sc1200, sc140 (default), sc1400, sc140e, msc8101, and msc8102. To list all possible targets, omit the argument value. -be Compiles for big-endian target configuration. (Default is little-endian.) -crt file Specifies a different startup file — not the default file defined during installation. -ma file Specifies a different application configuration file — not the default file defined during installation. -mb Compiles in big memory model; appropriate if code, static data, and runtime library require 64 kilobytes to 1 megabyte of memory. -mb1 Compiles in big memory model with runtime library calls in huge memory model; appropriate if (1) code and static data require 64 kilobytes — 1 megabyte of memory, and (2) runtime library is more than 1 megabyte away from the rest of the program. -mc file Specifies a different machine configuration file — not the default file defined during installation. -mem file Specifies a different linker command file — not the default file defined during installation. -mh Compiles in huge memory mode; appropriate if code and static data require more than 1 megabyte of memory. -mrom Copies all initialized variables from ROM at startup. -view Selects view for the application file. 26 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 27 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.3 Shell Options Summary (continued) Option Category Shell Option Effect Library, Other -complib [name] Creates self-contained component with specified name. -lfile Supplies specified library file. no_runtime_lib Does not link with default runtime libraries. -npr Disables replacement of prototype function. -pic Generates position-independent code. -reentrant Links with reentrant library and startup file. scllc_bintools Uses assembler and linker from StarCore LLC. -selflib Creates self-contained library. -slld Uses FE and ICODE options that support long long and doubles. Controlling Shell Behavior The section explains options that control the overall actions of the shell. You can specify the stage at which the shell program stops processing, define files that contain command line options, and display invocation commands. Controlling Shell Processing Stops The default arrangement is that the shell completes the entire processing cycle, from source-file input to executable-file output. If you want to stop the processing at a specific stage, use option -E, -cfe, -S, or -c. This lets you process and check individual files (or groups of files) as they progress through different stages, until the files finally are ready to be compiled and linked together. Table 3.4 gives more information about these four options. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 27 Freescale Semiconductor, Inc. MWEntComp.book Page 28 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.4 Options to Stop Processing in the Shell Option Description -E [file] The shell stops after preprocessing the C source files. Use the .i extension if you will input the file to the compiler at a later time. To send output to stdout, do not specify a filename, but do specify the -c option. For example, this command sends preprocessor output to file alpha.i: scc -E “alpha.i” “alpha.c” This example sends preprocessor output to stdout: scc -E -c “alpha.c” Preprocessing output does not preserve comments, unless you specify option -C. -cfe The shell stops after processing the input source files through the C Front End. This option confirms that the files have no syntax errors, and that the shell can process the files. This option is useful when you preparing files for cross-file optimization. Output files are IR files, receiving the filename extension .obj. The -cfe option lets you to create libraries of object files for compiling later in cross-file optimization mode. -S The shell stops after compiling the source files to assembly files, without invoking the assembler. Output files receive the filename extension .sl. -c The shell stops after compiling C and assembly source files to object code, without invoking the linker. The object code output files receive the filename extension .eln. If you specify any of the above options, the shell processes files appropriately, then writes the output files to the current directory. (If you also specify the -r option, the shell instead writes the outputs files to the specified directory.) The output files have the same names as the input files, with the filename extensions that correspond to the specified option. If any existing files in the directory have the same name and extension, this process overwrites these older files. The filename extension determines the starting point for processing each input file. Specifying a Shell Command File You can create command files containing options and arguments; the shell program treats these options and arguments as if they were in the command line. Such command files can save you input time when you invoke the shell program, helping overcome any limitations on the length of the command line. Each time you invoke the shell, you can select the command file that has the most appropriate set of options. 28 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 29 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options To specify a shell command file, include the option -F, followed by the filename. A command file itself can contain the -F option, so that it specifies yet another shell command file. Listing 3.2 uses the -F option to specify the command file proj.opt. Listing 3.2 Defining a Shell Command File scc -F proj.opt Within the command file, each separate option (with or without an argument), file, or list of files must be on a new line. You can specify as many lines as you wish, in any order. To include comments, use the # character: the shell ignores all characters between # and the end of the line. Listing 3.3 is a four-line command file. These lines tell the shell to invoke the linker with three application object files and one library file, to generate a link map file, and to output the executable program file appl.eld. Listing 3.3 Contents of a Shell Command File -o appl.eld -dm appl.map file1.eln file2.eln file3.eln -l mylib.elb NOTE # # # # output file name generate map file object files shared library If you do not specify a name for the map file is specified, the shell uses the name of the .eld file, but with extension .map. Displaying Shell Help Page To display the shell help page, include the -h option. This help page is a list of all available shell options and arguments; Listing 3.4 shows a section: Listing 3.4 Shell Help Page (Extract) -c -cfe -S -E -C Compile and assemble only. Don't invoke the linker Stop after Front-End. (Used for cross-file optimization) Generate assembly output file. Don't invoke assembler Preprocess only Preprocess only and keep comments Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 29 Freescale Semiconductor, Inc. MWEntComp.book Page 30 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Specifying Preprocessing Options This section explains options for controlling the preprocessing stage, before input files proceed through the C Front End. You can change the preprocessor output, define preprocessor macros, or define the directories to be searched for #include files. Changing Preprocessed Output The options of Table 3.5 change the format and content of the preprocessor output. These options can modify the -E option, or substitute for the -E option. Table 3.5 Options to Change Preprocessed Output Option Description -C Keeps all comments (preprocessor directives) in the preprocessing output. Without this option, the -E option tells the shell to write preprocessed text to the output file with only line control information, removing all comments. -M [file] Substitutes MAKE-format output file for the normal preprocessing output. This MAKE-format file lists dependencies among the input source files. If you do not specify a file, the shell sends the output to stdout. -MH [file] Substitutes an #include-file list for the normal preprocessing output. The output file lists all the #include files, their levels, and any nested files. If you do not specify a file, the shell sends the output to stdout. Defining Preprocessor Macros You can define preprocessor macros, or remove macro definitions; Table 3.6 lists the macro options. You can specify the macro options multiple times in the command line, to define or undefine different preprocessor macros. 30 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 31 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.6 Macro Options Option Description -D macro [=value] Defines the named macro as a preprocessor macro, with the specified value. The default vale for the value parameter is 1. Once you use this option to define a preprocessor macro, the shell passes this macro to the preprocessor for all subsequent compilations. This condition continues until you use the -U option to undefine the macro. The space between the -D option and the macro name is optional. -U macro Undefines the named macro; the shell no longer passes this macro to the preprocessor. To reverse this condition, you must use the -D option to redefine the macro. The space between the -U option and the macro name is optional. NOTE The shell processes all -D options of the command line before it processes the -U options. Adding Directories to the #Include File Path Use the option -I dir to add the specified directories to the path in which the shell searches for #include files. The dir value can be one directory name, or a list of directories. The space between the -I option and the dir string is optional. On a UNIX host, use colons (:) to separate the directories of a list; on PC hosts, use semicolons (;). You can use this option multiple times in a command line. The order of the options determines the shell’s search order for directories. Overriding Input File Extensions You can change how the shell treats an input file, by overriding the default behavior for the filename extension. To do so, use any of the options in Table 3.7, as many times as is appropriate. Specify one or more filenames after each such option; separate multiple filenames with spaces. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 31 Freescale Semiconductor, Inc. MWEntComp.book Page 32 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.7 Options to Override Input File Extensions Option Description -xc file [file2 ...] Forces .c treatment of specified files. The shell processes these files as it does actual C source files, subject to other options you specify. -xobj file [file2 ...] Forces .obj treatment of specified files. The shell processes these files as it does actual IR language files, output by the C Front End. The files become inputs for the optimizer. -xasm file [file2 ...] Forces .asm or .sl treatment of specified files. This shell sends these files to the assembler, just as it would actual assembler source files. The resulting object files become input files to the linker. These options can appear multiple times in the command line; each such multiple option pertains to its own argument file or file list. In all other respects, the shell processes these files normally, in the same relative order as other listed files. Listing 3.5 tells the compiler shell to process input files file1.ext and file2.bar as if they were C source files. Listing 3.5 Overriding File Extensions scc -c -xc file1.ext file2.bar Output Filename and Location Options These options let you specify the name or directory for the shell’s output files. The default arrangement is that each output file receives the same name as the input file, and that the current directory is the storage location. Table 3.8 lists these options. 32 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 33 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.8 Output File Name and Location Options Option Description -o file The output file takes the specified filename. This includes the extension you specify, but an extension is optional. You can use this option multiple times in the command line, for different files. If you include the -r option, such output files overwrite any existing files that have the same name in the current (or specified) directory. -r dir Redirects all output files to the specified directory. This option can appear only once in the command line. The stage where processing stops determines the default file type and filename extension for each output files. For example, if the command line includes the -cfe option, the output files from the C the Front End have the filename extension .obj. You can specify a different extension when you specify the file name, but this changes the way the shell treats this file. Listing 3.6 tells the shell to treat input file file1.alpha as an input file to the linker. Listing 3.6 Specifying Output Files scc -o file.eld file1.alpha Specifying C Language Options This section explains the C language options. These options tell the shell the language version of in the source files, to add debugging information to generated files, or to signed or unsigned the default for char variables. Defining Language Version The default C language mode is the normal ANSI/ISO version with extensions; all source files have the standard .c filename extension. You do not need to specify any language option if you use this mode. But if you use a different language version, you must include the -ansi or -kr option. If you use strict ANSI/ISO C, include the -ansi option. This tells the C Front End that all input source files are in strict ANSI/ISO C, with no extensions. Any files that do have extensions will trigger warnings. If you use K&R C, or if you use Portable C Compiler (PCC) C, include the -kr option. This tells the shell program that all source files conform to this version of C. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 33 Freescale Semiconductor, Inc. MWEntComp.book Page 34 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options You cannot compile source files of different C language versions at the same time. If you must compile source files of different C versions, use a separate shell command line for each version. Adding Debugging Information to Files The -g option tells the shell program to include source-level debugging information in the output files. This makes object files somewhat larger (on disk). However, the -g option does not affect the amount of code in these object files. Downloading sends the same amount of code to your development board whether or not you compile with the -g option. NOTE Including the -g option disables optimization, because no optimization is appropriate for debugging. If you specify an optimization level other than -O0 and include the -g option, the compiler issues a warning. Changing Default Char Sign Setting The default setting for all char variables is signed. To change this default to unsigned, use the -usc option. To change the setting back to signed, use the -sc option. Passing Options to Specific Tools Table 3.9 lists the options that tell the shell to pass other options to specific tools. Table 3.9 Options Used to Pass Options to Specific Tools Option Description -Xasm option Passes specified options and arguments to the assembler. -Xlnk option Passes specified options and arguments to the linker. For example: scc -Xlnk "-map "alpha.map"" alpha.eln -Xllt option Passes specified options and arguments to the low-level optimizer. -Xcfe option Passes specified options and arguments to the C Front End. -Xicode option Passes specified options and arguments to the high-level optimizer. One such passthrough option can specify multiple options. For example, the -Xllt option can tell the shell to pass several options, along with each option’s arguments, to the 34 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 35 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options low-level optimizer. If such multiple options are relevant, you must list the options and their arguments within quotation marks. If you invoke a tool several times, these options get passed to the tool during each invocation. Listing 3.7 tells the shell to pass the -occ option to the assembler. Listing 3.7 Passing Multiple Options to the Same Tool -Xasm -occ NOTE Use the -mem option to pass a command file other than the default to the linker. If you use the -Xlnk option to do this, both the command file you specify and the default command file get passed to the linker. This leads to error messages. Setting Listing, Messages Options This section explains options for retaining, displaying, and printing diagnostic and other messages, as well as generating listing and map files. Generating Listing, Map Files The default arrangement is that the shell program does not retain the diagnostic and crossreference information produced at different processing stages. To override this default arrangement, use the options of Table 3.10. Use any combination of these options, to have the shell generate listing files for the types of information you need. However, each option can appear only once in a shell command line. Table 3.10 Options to Generate Message Listing Files Option Description -de Retains the C Front End’s files of compilation error messages. If you do not include the -de option, the shell displays error messages during processing, but does not keep them. The result of this option is an error file for each source file; these files have the same names as the source files, but extension .err. -dm [file] Generates a link map file that lists all the specific variables, applications, and addresses the linker uses. If you do not specify a name, the link map file has the same name as the executable file, but extension .map. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 35 Freescale Semiconductor, Inc. MWEntComp.book Page 36 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.10 Options to Generate Message Listing Files (continued) Option Description -do Includes the details of C data structures in the output assembly file. These details include offsets for all field definitions in each data structure. -dL Generates a C list file for each source file. Each file lists the entire contents of the source file. Each list file has the same name as its source file, but extension .lis. -dL1 Generates a C list file for each source file. Each file lists the entire contents of the source file, and the list of #include files the source used. Each list file has the same name as its source file, but extension .lis. -dL2 Generates a C list file for each source file. Each file lists the entire contents of the source file. List files also include expansions, such as macro expansions, line splices, and trigraphs. Each list file has the same name as its source file, but extension .lis. -dL3 Combination of -dL1 and -dL2: generates a C list file for each source file. Each file lists the entire contents of the source file, all #include files, and all expansions. Each list file has the same name as its source file, but extension .lis. -dx [file] Generates a cross-reference information file, providing details of cross-references in the source file. If you do not specify a name, this new file has the same name as the source file, but extension .xrf. -dc [0-4] Generates a file showing calls in graphical tree form; your can use a postscript printer for a hard copy of this tree. Specify the size of the paper 0 for paper size A0, 1 for A1, and so on. Controlling Information Display You can control the level and type of messages and information that the shell program displays using the options in Table 3.11. 36 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 37 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Table 3.11 Options to Control Information Displayed by the Shell Option Description -q or -w Quiet mode (the default). The shell program displays the minimum amount of information: error messages, but no normal notices or banners. This option is useful if you run the shell in batch mode or with the MAKE utility, when display of progress information is not required. -v Verbose mode. The shell program displays/prints all the commands and command line options, as it proceeds through processing stages and invokes individual tools. The exact information output depends on the stages the shell performs. -n Displays specified shell processing actions without executing them. You can use this option before you invoke the shell, to check the actions the shell will take. Reporting Remarks and Warnings The default arrangement is that the shell reports all error messages and warnings, but does not report remarks. To have the shell also report remarks, include the -Wall option. Specifying Hardware Model, Configuration This section explains options for overriding default hardware and configuration settings. Defining Architecture The default architecture is SC140, which has four MAC units. This means that the compiler parallelizes code for four execution units. But if you compile for any other hardware configuration, you must specify the correct architecture. To do so, include the -arch target option, as Listing 3.8 shows. Valid values for target are sc110, sc140 (the default), sc140e, sc120, sc1200, sc1400, msc8101, and msc8102. Listing 3.8 Defining the Architecture scc -arch sc110 file1.c Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 37 Freescale Semiconductor, Inc. MWEntComp.book Page 38 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Shell Control Options Defining Configuration, Startup Files Installation includes definition of the default machine and application configuration files that the compiler use. Installation also includes definition of the startup file that the linker uses. These files contain: • Machine configuration file — information about the logical and physical memory maps. This information enables the global optimizer to dispatch variables to different memory areas in internal ROM or RAM. • Application configuration file — information about how the application software and the hardware interact. This file has sections about binding interrupt handlers, overlays, and application objects to specific addresses. • Startup file — definitions of such items as the interrupt vector and set-up code executed upon system initialization. The linker uses this information when it links assembly code files with standard libraries. In some circumstances, you want the shell to use other files for configuration setup and initialization. For example, you may want to specify additional devices for initialization at startup. To specify such different files, include any or all the options in Table 3.12. For each option, specify the file name. If file is not in the current directory, specify the path. Table 3.12 Options to Specify Configuration and Startup Files Option Description -mc file Compiler reads the specified file instead of the default machine configuration file. -ma file Compiler reads the specified file instead of the default application configuration file. -crt file Linker links the specified file into the application, instead of the default startup file. -mem file Linker uses the specified command file instead of the default linker command file (crtscsmm.cmd or crtscbmm.cmd). -reentrant Linker uses reentrant startup code and runtime libraries. (Mainly for the MSC8102.) Defining Memory Addressing Mode The SC100 architecture supports 16-bit and 32-bit addressing modes. The memory model you specify determines which addressing mode the Enterprise C Compiler uses. 38 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 39 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features If your program’s code and static data fit into 64 kilobytes, use the small memory model (the default). In this model, the compiler uses only 16-bit addresses. If your program’s code and static data need more than 64 kilobytes, but less than 1 megabyte of memory, specify the big memory model. To do so, include the -mb or -mb1 command line option: • Use -mb for programs whose code and static data (including the runtime library) require more than 64 kilobytes, but less than 1 megabyte of memory. • Use -mb1 for programs whose code and static data require more than 64 kilobytes, but less than 1 megabyte of memory — and whose runtime library is more than 1 megabyte away from the rest of the program. If your program’s code and static data need more than 1 megabyte of memory, use the huge memory model. To do so, include the -mh command line option. Copying Initialized Variables from ROM During development you normally use a loader, which sets the values of global variables. At startup, this loader loads these initialized variables and the executable application into RAM. But when you have finished development, your final application may not use a loader. In such a case, you must make sure that initialized variables get copied from ROM into RAM as the application executes. This means that your should include the command-line option -mrom when you compile the final application version. Specifying Big-Endian Mode The default arrangement is that the compiler generates code for little-endian mode. This means that the least significant bits are in the lower addresses. If you will run the application in big-endian environment (the most significant bits in the lower addresses), include the command-line option -be. Language Features This section describes the different language modes that the Metrowerks Enterprise C compiler accepts — including supported data types and sizes, fractional arithmetic representation, intrinsic functions, pragmas and predefined macros. Topics are: • C Language Dialects • Types and Sizes • Fractional and Integer Arithmetic Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 39 Freescale Semiconductor, Inc. MWEntComp.book Page 40 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • Intrinsic Functions • Pragmas • Predefined Macros C Language Dialects The compiler accepts three variations of C. The default mode is normal ANSI/ISO, with extensions. Table 3.13 lists the other two modes. Table 3.13 Additional C Language Modes C Language Mode Description Strict ANSI/ISO To specify, use shell option -ansi. Flags any ISO C extensions with warnings. K&R/PCC To specify, use shell option -kr. Compiler accepts older K&R dialect, providing almost complete compatibility with the widely used UNIX PCC (pcc) dialect. You may not compile source files of different C language types together. However, once you compile source files, you can link them together regardless of the C version of the original source files. Standard Extensions This section lists the extensions that are valid for standard (normal ANSI/ISO) C programs. However, if you compile in strict ANSI/ISO mode (the -ansi option), the compiler issues warnings for these extensions. Preprocessor Extensions The compiler accepts these preprocessor extensions: • Comment text can appear at the end of preprocessing directives. • Number syntax determines number scanning. This means that the compiler scans 0x123e+1 as three tokens instead of one invalid token. • The #assert preprocessing extensions of AT&T System V release 4 are valid. These extensions enable definition and testing of predicate names. Such names are in a name space distinct from all other names, including macro names. To define a predicate name, use the #assert preprocessing directive — either of the forms in Listing 3.9: 40 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 41 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Listing 3.9 Defining a Predicate Name #assert name #assert name(token-sequence) – In the first form, the predicate name does not receive an initial value. – In the second form, the predicate name receives the initial value tokensequence. You can use a #if expression to test such a predicate: #name(token-sequence). This expression has the value 1 if a #assert of that name with that token-sequence has appeared; otherwise, this expression has the value 0. A predicate may be assigned more than one value at a given time. • To delete a predicate, use the #unassert preprocessing directive — either of the forms in Listing 3.10: Listing 3.10 Deleting a Predicate #unassert name #unassert name(token-sequence) – The first form removes all definitions of the specified predicate name. – The second form removes only the specified definition, without changing any other definitions of the predicate name. NOTE The compiler includes a number of predefined preprocessor macros. The pragmas that the compiler supports are available in all modes. Syntax The compiler accepts these syntax extensions: • A translation unit (input file) can be empty, containing no declarations. • An extra comma is allowed at the end of an enum list. However, if you are not compiling in pcc mode, the compiler issues a remark about the comma. • It is permissible to omit the final semicolon before the close brace (}) of a struct or union specifier. However, if you are not compiling in pcc mode, the compiler issues a remark. • A close brace (}) may follow a label definition immediately, but the compiler issues a warning. (Normally, a label definition must be followed by a statement.) • An empty declaration (a semicolon with nothing before it) is allowed. The compiler issues a remark. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 41 Freescale Semiconductor, Inc. MWEntComp.book Page 42 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • In either normal mode or K&R/PCC mode, braces need not enclose an initializer expression, provided that the expression is a single value, and that the expression initializes an entire static array, struct, or union. In strict ANSI C mode, braces must enclose such an initializer expression. • A default arrangement is that the compiler accepts a struct that has no named fields, but which has at least one unnamed field. In strict ANSI C mode, the compiler issues a diagnostic message (a warning or error message). Declarations The compiler accepts these declaration extensions: • Declarations of static functions may be in function and block scopes, but the compiler moves such declarations to the file scope. • Benign redeclarations of typedef names are allowed. This means that you may redeclare a typedef name in the same scope as the same type, but the compiler issues a warning. • In either normal mode or K&R/PCC mode, the compiler always accepts asm statements and declarations. However, in strict ANSI C mode, this would be a conflict with the ANSI C standard. For example, the default behavior of the C Front End would be to interpret asm("xyz"); as an asm statement, but ANSI C would interpret this as a call of an implicitly-defined function asm. • The compiler accepts functions declared as asm functions, and recognizes __asm as a synonym for asm. The representation of an asm function body is an uninterpreted, null-terminated string that contains the text that appears in the source. • An asm function must be declared with no storage class, with a prototyped parameter list, and with no omitted parameters. Listing 3.11 shows such a declaration: Listing 3.11 Declaring an Asm Function asm void f(int,int) { ... } • As an asm function must be output with a prototyped parameter list, such functions are valid for ANSI C modes only. Types The compiler accepts these type extensions: 42 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 43 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • Bit-fields may have base types that are enums or integer types, as well as the types int and unsigned int. Using any signed integer type is equivalent to using type int; using any unsigned integer type is equivalent to using type unsigned int. • The last member of a struct may have an incomplete array type. But this member may not be the only member of the struct (otherwise, the struct would have zero size). • A file-scope array may have an incomplete struct, union, or enum type as its element type. If the array is subscripted, the type must be completed before this subscription. If the array is not extern, the type must be completed by the end of compilation. • The enum tags may be incomplete. You can define a tag name, specifying a braceenclosed list, to indicate resolution at a later time. • Object pointer types and function parameter arrays that decay to pointers may use restrict as a type qualifier. The compiler records restrict, making possible optimizations that aliasing otherwise would prevent. • The compiler accepts type long float as a synonym for double. • Assignment of pointer types is allowed in cases where the destination type has added type qualifiers that are not at the top level. An example is int ** to const int **. Expressions and Statements The compiler accepts these extensions for expressions and statements: • Assignment and pointer differences are allowed between pointers to types that are interchangeable, but not identical. Examples are unsigned char * and char *. This includes pointers to same-sized integral types, such as int * and long *. Except in pcc mode, the compiler issues a warning. A string constant may be assigned to a pointer to any kind of character, without any warning. • In operations on pointers, the compiler always implicitly converts a pointer to void to another type, if necessary. The compiler always implicitly converts a null pointer constant to a null pointer of the right type, if necessary. In ANSI C, some operators allow such conversions, but other operators do not — as where such a conversion would not be logical. • In an initializer, a pointer constant value may be cast to an integral type, if the integral type is big enough to contain it. • In an integral constant expression, an integer constant may be cast to a pointer type, and then back to an integral type. • In character and string escapes, if the character following the \ has no special meaning, the value of the escape is the character itself. Thus, “\s” == “s”. The compiler issues a warning. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 43 Freescale Semiconductor, Inc. MWEntComp.book Page 44 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • The compiler does not concatenate adjacent wide and non-wide string literals. • The compiler ignores redundancy in duplicate size and sign specifiers, such as short short or unsigned unsigned. However, the compiler issues a warning. • __ALIGNOF__ is similar to sizeof, but returns the alignment requirement value for a type, or 1 if there is no alignment requirement. A type or expression in parentheses may follow __ALIGNOF__, as Listing 3.12 shows: Listing 3.12 Returning the Alignment Requirement __ALIGNOF__(type) __ALIGNOF__(expression) (The compiler does not evaluate the expression in the second form.) • Identifiers may not contain dollar signs. • __INTADDR__(expression) scans the enclosed expression as a constant expression, and converts it to an integer constant. (The offsetof macro uses this constant.) • The values of enumeration constants may be given by expressions that evaluate to unsigned quantities which fit in the unsigned int range but not in the int range. The compiler issues a warning if an out-of-range result is possible, as Listing 3.13 shows: Listing 3.13 Out of Range Warning /* When ints are 32 bits: */ enum a {w = -2147483648}; /* enum b {x = 0x80000000}; /* enum c {y = 0x80000001}; /* enum d {z = 2147483649}; /* No warning */ No warning */ No warning */ Warning */ • The address of a variable with register storage class may be taken, but the compiler issues a warning. • The expression &... is accepted in the body of a function in which an ellipsis appears in the parameter list. • An ellipsis may appear by itself in the parameter list of a function declaration, for example, f(...). In strict ANSI mode, the compiler issues a diagnostic message. • External entities declared in other scopes are visible, as Listing 3.14 shows. The compiler issues a warning. 44 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 45 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Listing 3.14 External Entities in Other Scopes void f1(void) { extern void f(); } void f2() { f(); /* Using out of scope declaration */ } • Pointers to incomplete arrays may be used in pointer addition, subtraction, and subscripting, as Listing 3.15 shows. Listing 3.15 Pointers to Incomplete Arrays int (*p)[]; ... q = p[0]; – The compiler issues a warning if the value added or subtracted is anything other than a constant zero. As the pointer points to a type that has zero size, the value added to or subtracted from the pointer is multiplied by zero, so has no effect on the result. – Comparisons and pointer differences of such pairs of pointer types also are allowed, but the compiler issues a warning. • Pointers to different function types may be assigned or compared for equality (==) or inequality (!=), without an explicit type cast. However, the compiler issues a warning. • A pointer to void may be implicitly converted to or from a pointer to a function type. • Only in the default mode (ANSI C with extensions) does the compiler recognize intrinsic functions as extensions. In other modes, the compiler treats intrinsic functions as function calls.<$startrange>C dialects:standard extensions; standard C extensions. K&R/PCC Mode If you specify pcc mode, the Metrowerks Enterprise C compiler accepts the traditional C language defined by The C Programming Language, first edition, by Kernighan and Ritchie (K&R), Prentice-Hall, 1978. This mode provides almost complete compatibility with Reiser CPP and Johnson PCC (pcc), both widely used in UNIX systems. However, as there is no documentation of those programs’ exact behavior, it is not possible to guarantee complete compatibility. In general, in pcc mode, the compiler tries to interpret a source program that is valid to pcc in the same way that pcc would interpret the source program. However, ANSI features that do not conflict with this behavior are not disabled. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 45 Freescale Semiconductor, Inc. MWEntComp.book Page 46 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features In some cases where pcc allows a highly questionable construct, the compiler accepts the construct, but issues a warning. For example, the compiler accepts the degenerate hexadecimal number 0x as zero, but issues a warning. Preprocessor Differences The K&R/PCC preprocessor differences from the standard mode are: • In generated preprocessing output, the line-identifying directives have the pcc form instead of the ANSI form. • __STDC__ is left undefined. • In preprocessing output, comments are deleted entirely (instead of being replaced by one space). The preprocessor does not generate extra spaces in textual output, to prevent pasting of adjacent confusable tokens. As a result, the characters a/**/b become ab in preprocessor output. • The first directory the compiler searches for include files is the directory containing the file that contains the #include. (In standard mode, the first directory is the one that contains the primary source file.) • The compiler does not recognize trigraphs. • Macro expansion implementation is different. The compiler inserts macro arguments into the macro expansion before macro- expanding the arguments. When the compiler rescans the macro expansion, it expands any macro invocations in the argument text. This method permits, and checks for, macro recursion. • Token pasting implementation, inside macro expansions, is different. The compiler does not maintain end-of-token markers, so tokens that abut after macro substitution may be parsed as a single token. • The compiler recognizes macro parameter names inside character and string constants, and gives them substitutes. • The compiler flags macro invocations having too many arguments with a warning rather than an error message. The compiler ignores the extra arguments. • The compiler flags macro invocations having too few arguments with a warning rather than an error message. The compiler uses a null string as the value of the missing parameters. • The compiler ignores extra occurrences of #else (after the first has appeared in an #if block), but issues a warning. Syntax Differences The K&R/PCC syntax differences from the standard mode are: 46 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 47 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • The keywords signed, const, and volatile are disabled, so that they can be user identifiers. The other non-K&R keywords enum and void probably exist already in code, so are not disabled. • The = preceding an initializer may be omitted, but the compiler issues a warning. (This was an anachronism even in K&R.) • The compiler accepts 0x as a hexadecimal 0, but issues a warning. • The compiler accepts 1E+ as a floating-point constant with an exponent of 0, but issues a warning. • You may write the compound assignment operators as two tokens. For example, you may write += as + =. • You may write the compound assignment operators in their old-fashioned reversed forms, but the compiler issues a warning. For example, you may write -= as =-. • The digits 8 and 9 are allowed in octal constants. (For example, the constant 099 has the value 9*8+9, or 81.) • The compiler does not recognize the escape \a (alert) in character or string constants. Declaration Differences The K&R/PCC declaration differences from the standard mode are: • The compiler ignores declarations of the form typedef some-type void;. • The names of functions, and of external variables, always must be entered at the file scope. • The compiler treats a function declared static, which is used but never defined, as if its storage class were extern. (The compiler to does not issue an error message because of the undefined function.) • The compiler treats a file-scope array that has an unspecified storage class, and remains incomplete at the end of compilation, as if its storage class is extern. (In ANSI mode, the compiler would change the number of elements 1, leaving the storage class unspecified.) • If a function parameter list begins with a typedef identifier, the compiler considers the parameter list to be prototyped only if something other than a comma or close parenthesis follows the typedef identifier. Listing 3.16 shows this arrangement: Listing 3.16 Prototyped Parameter List typedef int t; int f(t) {} int g(t x) {} /* Old-style list */ /* Prototyped list, parameter x of type t */ Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 47 Freescale Semiconductor, Inc. MWEntComp.book Page 48 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • Function parameters can have the same names as typedef identifiers. (In normal ANSI mode, the compiler would consider any parameter list that began with a typedef identifier to be prototyped. So in response to the declaration of Listing 3.16, the compiler would issue an error message.) • The empty declaration struct x; does not hide an outer-scope declaration of the same tag. The compiler takes this empty declaration as a reference to the outer declaration. • In a declaration of a struct or union member, you may omit the declarator list entirely, to specify an unnamed field that requires padding. Listing 3.17 shows this omission. Such a field may not be a bit-field. Listing 3.17 Omitting the Declarator List struct s {char a; int; char b[2];} v; /* sizeof(v) is 3 */ • The compiler does not generate a warning for a storage specifier appearing in other than the first position, in a list of specifiers. (as in int static). • The compiler treats keywords short, long, and unsigned as adjectives in type specifiers, so you may use them to modify a typedef type. For example, the declarations of Listing 3.18 give s the type unsigned long: Listing 3.18 Keywords in Type Specifiers typedef long size; unsigned size s; • Free-standing tag declarations are allowed in the parameter declaration list for a function with old-style parameters. • You may completely omit declaration specifiers, but the compiler issues a warning. (ANSI C allows this omission only for function declarations.) Thus, i; declares i as an int variable. • An identifier in a function can have the same name as a parameter of that function, but the compiler issues a warning. Type Differences The K&R/PCC type differences from the standard mode are: • The compiler considers integral types identical if they have the same representation (size, signedness, and alignment); you may use such types interchangeably. For example, this int and long are interchangeable if they have the same size. 48 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 49 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • The compiler gives all enums the type int. (In ANSI mode, the compiler uses smaller integral types where possible.) • The compiler considers a plain char to be the same as either signed char or unsigned char, according to command-line options. (In ANSI C, plain char is distinct from the two other types.) • The compiler promotes all float functions to double functions, promoting any float-function parameters to double-function parameters. • The compiler executes all float operations as double. • The compiler determines the types of large integer constants according to K&R rules. The constant type is not unsigned in some cases where ANSI C would define them that way. Expression and Statement Differences The K&R/PCC expression and statement differences from the standard mode are: • The compiler allows assignment between pointers and integers, and between incompatible pointer types, without an explicit cast, but issues a warning. • The compiler allows a field selection of the form p->field, even if p does not point to a struct or union that contains field. In this context, p must be a pointer or an integer. Similarly, the compiler allows x.field, even if x is not a struct or union that contains field. In this case, x must be an lvalue. In both cases, if you declare field as a field in more than one struct or union, it must have the same offset in all instances. • If the compiler detects overflows detected while folding signed integer operations on constants, it issues warnings instead of error messages. • The compiler issues a warning for an & operator applied to an array. The type of such an operation is address of array element, rather than address of array. • For the shift operators << and >>, the compiler performs usual arithmetic conversions on the operands, as it would for other binary operators. Then the compiler converts the right operand to int, and the result type is the type of the left operand. (In ANSI C, the compiler performs integral promotions on the two operands separately, although the result type also is the type of the left operand.) This means that in pcc mode, a long shift count forces the shift to be done as long. • The compiler does not share string literals. For identical string literals, the compiler allocates multiple copies of the string. • You may apply the expression sizeof to bit-fields. The size is that of the underlying type (for example, unsigned int). • Any lvalues cast to a type of the same size remain lvalues, unless they involve a floating-point conversion. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 49 Freescale Semiconductor, Inc. MWEntComp.book Page 50 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • The compiler issues a warning, instead of an error message, for integer constants too large for an unsigned long to accommodate. The compiler truncates the value to an acceptable number of low-order bits. • The compiler casts expressions in a switch statement to int. This differs from ANSI C, in that a long expression may be truncated. • The promotion rules for integers are different: unsigned char and unsigned short get promoted to unsigned int. Remaining Incompatibilities The additional known cases in which the compiler is not compatible with pcc are: • The compiler does not implement token pasting outside of macro expansions (that is, in the primary source line) if only a comment separates two tokens. For example, the compiler does not consider a/**/b to be ab. To obtain the pcc compiler’s behavior in such a case, preprocess to a text file, then compile that file. Similarly, the preprocessing textual output is equivalent but not identical. Spaces and blank lines are not exactly the same as those produced in pcc. • The pcc compiler considers the result of a ?: operator to be an lvalue, if the first operand is constant and the second and third operands are compatible lvalues. The compiler never treats the result of the ?: operator as an lvalue. • The pcc compiler misparses the third operand of a ?: operator in a way that some programs exploit. For example, the pcc compiler parses i ? j : k += l as i ? j : (k += l) This is not correct, as the += operator has lower precedence than the ?: operator. In such a case, the compiler generates an error message. • The lint utility recognizes the keywords for its special comments anywhere in a comment, regardless of any other preceding text in the comment. The compiler recognizes such a keyword only if it is the first identifier after an optional initial series of blanks or horizontal tabs. In addition, lint recognizes only a single digit of the VARARGS count. The compiler accumulates as many digits as appear in the count. Types and Sizes Table 3.14 shows information for the supported data types, including: • The size for each data type in memory • The size for each data type in the two register types (the Dn 40-bit data register and the Rn 32-bit address register) • The required alignment for each data type • The value range for each data type. 50 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 51 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.14 Data Types and Sizes Size (in Bits) Range Type Memory Dn Rn Align Minimum Maximum char 8 40 32 8 -128 127 unsigned char 8 40 32 8 0 255 short 16 40 32 16 -32,768 32,767 unsigned short 16 40 32 16 0 65,535 int 32 40 32 32 -2,147,483,648 2,147,483,647 unsigned int 32 40 32 32 0 4,294,967,295 long 32 40 32 32 -2,147,483,648 2,147,483,647 unsigned long 32 40 32 32 0 4,294,967,295 long double 32 40 32 32 -1.17E-38 1.17E+38 fractional short 16 40 - 16 -1 0.99969842 fractional long / int 32 40 - 32 -1 0.9999999953 pointer 32 40 32 32 0 0xFFFFFFFF NOTE Fractional short and fractional long/int are not language types. You can use these types only with intrinsic functions. The compiler maps them to the predefined types short and long/int. Option -slld: 64-bit Long Longs and Doubles If you use the -slld option, long long and double variables are 64 bits wide instead of 32 bits wide. The default arrangement is that the only pre-built runtime libraries that provide long long and double support are those for the SC140. For all the other targets, users must build the runtime libraries themselves. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 51 Freescale Semiconductor, Inc. MWEntComp.book Page 52 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features NOTE If you use the -slld option with the -reentrant flag, the IEEE exception flags may not be set correctly. Also note that the linker issues a warning if you link objects compiled with the -slld option with objects compiled without this option. This situation cannot arise if you write all project source files in C, because compilation of all C language files happens in the mode you specify. If you compile with the -slld, compilation supports 64-bit long longs and doubles; if you compile without this option, compilation supports 32-bit long longs and doubles. However, if your project includes some assembly language files, and you compile with the -slld option, the linker issues a warning. This follows from the initial assumption that assembly language files do not have long long or double support. To avoid this warning: 1. Make sure that the assembly language files do not use the double data type as a 4-byte type. 2. If the assembly language files do not use double, or they use double incorrectly (that is, as an 8-byte type), assemble the files with the -d.slld 1. To do so, enter -d.slld 1 in the To Assembler text box of the Passthrough/Hardware target settings panel. (The Targeting Manual includes instructions for displaying and using the Passthrough/Hardware target settings panel.) Characters The compiler stores a character in one byte (8 bits) of memory, whether the character is signed or unsigned. The compiler always aligns a character on an 8-bit boundary. Arrays of characters occupy one byte per character. Figure 3.5 shows the memory layout for characters. Figure 3.5 Characters — Memory Layout Bytes * * * * char 1 char 2 char 3 char 4 As it loads characters into registers, the compiler sign-extends signed characters, but zeroextends unsigned characters. Figure 3.6 depicts the layout for signed and unsigned characters in the Dn (40-bit) data register. The letter S indicates the signed extension of the value. 52 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 53 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Figure 3.6 Characters — Dn Register Layout Bytes * * char (signed) Bytes char (unsigned) S * S * * 0 * 0 * * S char * * 0 char Figure 3.7 shows the layout for signed and unsigned characters in the Rn (32-bit) address register. Figure 3.7 Characters — Rn Register Layout Bytes * * char (signed) Bytes char (unsigned) S * * 0 * * S char * * 0 char Integers The compiler performs integer arithmetic using data sizes appropriate to the operation. Short integers use at least 16-bit-wide operations (single-precision integer arithmetic); long integers use at least 32-bit-wide operations (double-precision integer arithmetic). To stores short and long integers in memory, the compiler uses little-endian representation (least significant bits in the lower addresses). However, if you include the option -be , the compiler uses big-endian representation (most significant bits in the lower addresses.) Unsigned integer arithmetic overflow wraps, but does not result in any additional side effects. However, in accordance with the ANSI C specification, the result of signed integer arithmetic overflow is undefined. Figure 3.8 shows the memory layout for short and long integers. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 53 Freescale Semiconductor, Inc. MWEntComp.book Page 54 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Figure 3.8 Integers—Memory Layout Bytes * * * short 2 short 1 Bytes * * * * * long 1 Short integers must be aligned on 2-byte (16-bit) boundaries, while long integers must be aligned on 4-byte (32-bit) boundaries. Figure 3.9 shows this alignment of short and long integers, in conjunction with characters. Figure 3.9 Integers—Alignment Bytes * * * char 1 * short 1 long 1 short 2 char 2 long 2 As with characters, when the compiler loads integers into registers, it sign-extends signed integers and zero-extends unsigned integers. Figure 3.10 shows the layout for signed and unsigned short and long integers in the Dn (40-bit) data register. The letter S indicates the signed extension of the value. 54 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 55 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Figure 3.10 Integers—Dn Register Layout Bytes * short (signed) Bytes short (unsigned) * S * long / int (signed) S Bytes * * * 0 * * short * 0 * * S * Bytes long / int (unsigned) * short * * * long / int * * 0 * * long / int Figure 3.11 shows the layout for signed and unsigned short and long integers in the Rn (32-bit) address register. Figure 3.11 Integers—Rn Register Layout Bytes * * * * * * short * * * long / int long / int (signed) Bytes * short 0 short (unsigned) Bytes * S short (signed) Bytes * * long / int (unsigned) * * * long / int Floating-Point Values The compiler’s default arrangement is that it maps floating-point, double and long double type integers to a single precision IEEE-754 type, using 32 bits (4 bytes). The compiler Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 55 Freescale Semiconductor, Inc. MWEntComp.book Page 56 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features generates calls for library functions to evaluate floating-point expressions. The representation of these integers in memory and in the registers is exactly the same as for long integers. However, you can use the -slld option to make both long double and double variables 8 bytes wide. Fractional Representation As C does not provide built-in support for fractional types, the compiler implements syntactic representation of fractional types and operations by intrinsic functions using integer data types. Fixed-point arithmetic uses 16-bit, 32-bit, 40-bit, and 64-bit operations. The compiler uses little-endian representation (lest significant bits in lower addresses) to store fractional integers in memory. (You can change this setting to big-endian by using the -be option. Fractional type overflows may saturate, without any side effects. Rounding and saturation modes follow the settings of startup code, or of optional intrinsic function calls. The compiler limits operations on double and extended precision type objects to assignments and fractional arithmetic using only intrinsic functions. The compiler does not support integer operations on extended precision types. The compiler maps fractional types to their corresponding, predefined types: • Fractional short to short • Fractional long to long • Fractional int to int Figure 3.12 shows the layout for fractional short and long integers in the Dn (40-bit) data register. This is the only register for fractional integer types. The letter S indicates the signed extension of the value. Figure 3.12 Fractional Integers—Dn Register Layout Bytes short fractional (signed) Bytes long / int fractional (signed) * 0 * S * * * short fractional * * * 0 * * long / int fractional When loading data from memory into data registers, the compiler aligns the data in the registers according to the context of data use. 56 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 57 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Pointers Pointers contain addresses of data objects or functions. The compiler uses 32 bits (4 bytes) to represent pointers in memory. In the small memory model, only 16 of these bits are meaningful. The representation of pointers in memory and in the registers is exactly the same as for unsigned long integers. Bit Fields The compiler always allocates members of structures on byte boundaries, aligning them according to their fundamental base type. However, you can allocate bit-fields in structures at any bit, and of any length not exceeding the size of a long word (32 bits). Signed and unsigned bit-fields are permitted; the compiler sign-extends them upon a fetch. A bit-field of type int is considered signed. The compiler always allocates bit-fields from the low-address end of a word (right to left or little-endian), even if you include the option -be. Bit-field sizes may not cross a long word boundary. In Listing 3.19, the structure more has 4-byte alignment and will have a size of 4 bytes. This is because the fundamental type long governs the bit-fields in the structure, and long requires a 4-byte alignment. Listing 3.19 Bit-Field Alignment to Long Word (1) struct more { long first : 3; unsigned int second : 8; }; The structure less, in Listing 3.20, requires only a 1-byte alignment — the requirement of the fundamental type char, which this structure uses. Listing 3.20 Bit-Field Alignment to Character struct less { unsigned char third : 3; unsigned char fourth : 8; }; Underlying type, not the width of fields, drives alignments. You should consider these alignments along with any other structure members. In Listing 3.21, the structure careful requires a 4-byte alignment. Its bit-fields require only a 1-byte alignment, but the field fluffy requires a 4-byte alignment due to its fundamental type, long. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 57 Freescale Semiconductor, Inc. MWEntComp.book Page 58 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Listing 3.21 Bit-Field Alignment to Long Word (2) struct careful { unsigned char third : 3; unsigned char fourth : 8; long fluffy; }; Fields within structures and unions begin on the next possible suitably aligned boundary for their data types. For fields that are not bit-fields, this is a suitable byte alignment. Bit-fields begin at the next available bit offset, with this exception: the first bit-field after a member that is not a bit-field is allocated on the next available byte boundary. In Listing 3.22, the offset of the field c is one byte. The structure itself has 4-byte alignment and is four bytes in size, because of the alignment restrictions introduced by the long underlying data type for the bit-field. Listing 3.22 Bit-Field Offset struct s { int bf: 5; char c; } Fractional and Integer Arithmetic The ability to perform both integer and fractional arithmetic is one of the strengths of the Metrowerks Enterprise C compiler. Fractional arithmetic is important for computation-intensive algorithms such as digital filters, speech coders, vector and array processing, digital control, or other signalprocessing tasks. In this mode, the compiler interprets data as fractional values, performing computations accordingly. Fractional arithmetic examples include: • 0.5 * 0.25 -> 0.125 • 0.625 + 0.25 -> 0.875 • 0.125 / 0.5 -> 0.25 • 0.5 >> 1 -> 0.25 NOTE 58 The notation of these examples is for illustration purposes only, as C does not let you use floating-point notation to specify fractional constants. The compiler implements fractional arithmetic using intrinsic functions based on integer data types. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 59 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features The compiler often uses saturation in this mode. This prevents the severe output-signal distortion due to computation overflows without saturation. You can selectively enable and disable saturation, so that limiting applies only to final results, not intermediate calculations. Integer arithmetic is important for controller code, array indexing, address computations, peripheral setup and handling, bit manipulation, and other general-purpose tasks. Integer arithmetic examples include: • 4 * 3 -> 12 • 1201 + 79 -> 1280 • 63 / 9 -> 7 • 100 << 1 -> 200 User-program needs determine whether the compiler interprets data in a memory location as fractional or integer. Table 3.15 shows both interpretations for a 16-bit value, depending on the location of the binary point. NOTE Table 3.15’s binary representation corresponds to the location of the binary point for fractional data interpretation. For integer data interpretation, the binary point is immediately to the right of the LSB. Table 3.15 Interpretation of 16-Bit Data Values Binary Representation Hexadecimal Representation Integer Value (Decimal) Fractional Value (Decimal) 0.100 0000 0000 0000 0x4000 16384 0.5 0.010 0000 0000 0000 0x2000 8192 0.25 0.001 0000 0000 0000 0x1000 4096 0.125 0.111 0000 0000 0000 0x7000 28672 0.875 0.000 0000 0000 0000 0x0000 0 0.0 1.100 0000 0000 0000 0xC000 -16384 -0.5 1.110 0000 0000 0000 0xE000 -8192 -0.25 1.111 0000 0000 0000 0xF000 -4096 -0.125 1.001 0000 0000 0000 0x9000 -28672 -0.875 This equation shows the relationship between a 16-bit integer and a fractional value: Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 59 Freescale Semiconductor, Inc. MWEntComp.book Page 60 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Fractional Value = Integer Value / (215) This similar equation relates 40-bit integers and fractional values: Fractional Value = Integer Value / (231) Table 3.16 shows interpretation of a 40-bit value as either an integer or fractional, depending on the location of the binary point. Table 3.16 Interpretation of 40-Bit Data Values Hexadecimal Representation 40-Bit Integer in Entire Accumulator 16-Bit Integer in MSP (Decimal) Fractional Value (Decimal) 0x0 4000 0000 1073741824 16384 0.5 0x0 2000 0000 536870912 8192 0.25 0x0 0000 0000 0 0 0.0 0xF C000 0000 -1073741824 -16384 -0.5 0xF E000 0000 -536870912 -8192 -0.25 The following code fragment illustrates the use of integer arithmetic: a = a + b*c; This next code fragment shows the use of an intrinsic function to implement fractional arithmetic: a = L_mac(a,b,c); Intrinsic Functions The compiler supports many intrinsic (built-in) functions that map directly to SC100 assembly instructions. As C does not support fractional types and operations, these intrinsic functions let you use integer data types to implement fractional operations. The syntax structure for the compiler group of intrinsic functions is compatible with the ETSI and ITU reference implementations of bit-exact standards. Data Types for Intrinsic Functions These four data types are for specific use with intrinsic functions: • Fractional short — a 16-bit fractional value mapped to a short • Fractional long — a 32-bit fractional value mapped to a long • Extended-precision fractional — a 40-bit value usable only in intrinsic functions 60 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 61 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • Double-precision fractional — a 64-bit value usable only in intrinsic functions The extended- and double-precision fractional types let you define algorithms that require precision greater than 32 bits. You can use these data types only with intrinsic functions and with assignments. You cannot use extended- or double-precision fractional variables for standard arithmetical or other operations. Extended-Precision Fractional The extended-precision fractional (Word40) is a 40-bit data type that occupies the entire Dn (40-bit) register, as Figure 3.13 shows: Figure 3.13 Extended-Precision Fractional—Dn Register Layout Bytes 0 1 2 3 extended-precision fractional guard bits high 4 low The compiler maps this data type as a structure containing two elements: • A 32-bit integer to the right of the binary point. • An 8-bit integer to the left of the binary point. This integers consists of guard bits that can provide a more accurate result if an overflow occurs. Stored in memory, an extended-precision fractional variable occupies 64 bits. The least significant 32 bits are stored in the first 32-bit word. The 8 most significant guard bits are stored in the second 32-bit word, in an undefined position. Double-Precision Fractional The double-precision fractional data type (Word64) consists of 64 bits, all to the right of the binary point. The compiler maps this data type as a structure containing two 32-bit elements. Fractional Constants Fractional constants require integer notation, as the compiler does not support floatingpoint notation. For example, to express the value 0.5 as a fractional constant, source code must use the hexadecimal integer representation 0x4000. Initializing Variables with Fractional Values Use these macros to initialize variables as fractional values: • WORD16 — initializes a value as a fractional short. • WORD32 — initializes a value as a fractional long. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 61 Freescale Semiconductor, Inc. MWEntComp.book Page 62 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features For example, short x = WORD16(0.5) initializes x as a fractional short with the value 0x4000. Intrinsic Function Categories The software includes many intrinsic functions, in these categories: • Fractional arithmetic primitives • Long fractional arithmetic primitives • Double-precision fractional arithmetic primitives • Extended precision fractional arithmetic primitives (with guard bits) • Long long and double support • Optimized primitives • Architecture primitives • Architecture primitives that generate identical assembly instructions • Miscellaneous Table 3.17 gives the declarations and explanations for all these intrinsic functions. 62 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 63 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions Category Function Declaration Explanation Fractional Arithmetic Primitives Word16 abs_s(Word16 var1) Returns short absolute value of a 16-bit argument. Word16 add(Word16 var1, Word16 var2) Performs short add of var1 and var2, with overflow control and saturation. If overflow occurs, 16-bit result is +32767; if underflow occurs, 16-bit result is -32768. Word32 add2(Word32 var1, Word32 var2); Adds 32-bit arguments. Word16 div_s(Word16 var1, Word16 var2); Performs short divide: fractional integer division of var1 by var2. Both arguments must be positive; var2 must not exceed var1. Result is positive (leading bit = 0), truncated to 16 bits. Word16 extract_h(Word32 L_var1); Returns most significant 16 bits of 32-bit argument. Word16 extract_l(Word32 L_var1); Returns least significant 16 bits of 32-bit argument. Word32 L_mac(Word32 L_var3, Word16 var1, Word16 var2); Performs multiply accumulate: multiplies var1 by var2 and shifts result left by 1. Adds 32-bit result to L_var3 with saturation, returning 32bit result. Word32 L_msu(Word32 L_var3, Word16 var1, Word16 var2); Performs multiply subtract: multiplies var1 by var2 and shifts result left by 1. Subtracts 32-bit result from L_var3 with saturation, returning 32-bit result. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 63 Freescale Semiconductor, Inc. MWEntComp.book Page 64 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category 64 Function Declaration Explanation Word16 mac_r(Word32 L_var3, Word16 var1, Word16 var2); Performs multiply, accumulate, and round: multiplies var1 by var2 and shifts result left by 1. Adds 32-bit result to L_var3 with saturation. Rounds the result’s least significant 16 bits into the most significant 16 bits with saturation, then shifts the result right by 16. Returns 16-bit result. Word16 max(Word16 var1, Word16 var2); Returns the greater of two 16-bit fractional arguments. Word32 max2(Word32 var1, Word32 var2); Returns the greater of two 32-bit fractional arguments. Word16 maxm(Word16 var1, Word16 var2); Returns the greater of two 16-bit fractional arguments. Word16 min(Word16 var1, Word16 var2); Returns the lesser of two 16-bit fractional arguments. Word32 min2(Word32 var1, Word32 var2); Returns the lesser of two 32-bit fractional arguments. Word16 msu_r(Word32 L_var3, Word16 var1, Word16 var2); Performs multiply, subtract, and round: multiplies var1 by var2 and shifts result left by 1. Subtracts 32-bit result from L_var3 with saturation. Rounds the result’s least significant 16 bits into the most significant 16 bits with saturation, then shifts the result right by 16. Returns 16-bit result. Word16 mult(Word16 var1, Word16 var2); Performs short multiply of var1 by var2, giving scaled, 16-bit result. Word16 mult_nomac(Word16 var1, Word16 var2); Identical to mult. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 65 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Function Declaration Explanation Word16 mult_r(Word16 var1, Word16 var2); Performs short multiply, with rounding. Word16 negate(Word16 var1); Negates var1 with saturation. Word16 norm_s(Word16 var1); Normalizes 16-bit fractional argument: shifts left enough times to normalize a positive var1 (interval 16384 — 32767), or to normalize a negative var 1 (interval -32768 — -16384). Word16 neg_norm_s(Word16 var1); Normalizes negatively: multiplies result of norm_s by -1. Word16 round(Word32 L_var1); Rounds least significant 16 bits of L_var1 into most significant 16 bits, with saturation. Shifts resulting bits right by 16, returning 16-bit result. Word16 saturate(Word32 L_var1); Limits 32-bit argument to the range of a 16-bit word. Word16 shl(Word16 var1, Word16 var2); Performs short shift left: arithmetically shifts var1 left var2 positions, zero-filling the var2 least significant positions of the result. If var2 is negative, arithmetically shifts var1 right by var2 with sign extension. Saturates result in case of underflow or overflow. Word16 shl_nosat(Word16 var1, Word16 var2); Performs short shift left without saturation. Like shl, but does not saturate result in case of underflow or overflow. Word16 shr(Word16 var1, Word16 var2); Performs short shift right: arithmetically shifts var1 right var2 positions with sign extension. If var2 is negative, arithmetically shifts var1 left by var2 with sign extension. Saturates the result in case of underflow or overflow. Word16 shr_nosat(Word16 var1, Word16 var2); Performs short shift right without saturation. Like shr, but does not saturate result in case of underflow or overflow. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 65 Freescale Semiconductor, Inc. MWEntComp.book Page 66 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Long Fractional Arithmetic Primitives 66 Function Declaration Explanation Word16 shr_r(Word16 var1, Word16 var2); Performs short shifr right with rounding. Like shr, but with rounded result. Word16 sub(Word16 var1, Word16 var2); Performs short subtract of var2 from var1, with overflow control and saturation. If overflow occurs, 16-bit result is +32767; if underflow occurs, 16-bit result is -32768. Word32 sub2(Word32 var1, Word32 var2); Subtracts 32-bit var2 value from 32-bit var1 value. Word32 div_iter(Word32 var1, Word16 var2); Performs iterative fractional division of destination operand by source operand; stores result in destination operand. Matches StarCore div instruction. Word32 Extract(Word32 val, UWord32 Mask); Extracts a bit field from a 32-bit signed long fractional; express mask as an unsigned 32bit long fractional. Matches StarCore extract instruction. Word32 ExtractU(UWord32 val, UWord32 Mask); Extracts a bit field from a 32-bit unsigned long fractional; express mask as an unsigned 32bit long fractional. Matches StarCore extractu instruction. Word32 L_abs(Word32 L_var1); Returns long absolute value of a 32-bit argument; saturates if value is -214783648. Word32 L_add(Word32 L_var1, Word32 L_var2); Performs long add of L_var1 and L_var2, with overflow control and saturation. If overflow occurs, result is +2147483647; if underflow occurs, result is -2147483648. Word32 L_deposit_h(Word16 var1); Deposits short in most significant bits: copies values of var1 16 bits into most significant 16 bits of 32-bit return value; zeros out the 16 least significant bits of the return value. Word32 L_deposit_l(Word16 var1); Deposits short in least significant bits: copies values of var116 bits into least significant 16 bits of 32-bit return value; sign-extends 16 most significant bits of the return vbalue. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 67 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Function Declaration Explanation Word32 L_max(Word32 L_var1, Word32 L_var2); Returns the greater of two 32-bit fractional arguments. Word32 L_maxm(Word32 L_var1, Word32 L_var2); Returns the greater of two 32-bit fractional arguments. Word32 L_min(Word32 L_var1, Word32 L_var2); Returns the lesser of two 32-bit fractional values. Word32 L_mult(Word16 var1, Word16 var2); Performs long multiply of var1 by var2, with one shift left, giving 32-bit result. Word32 L_mult_nomac(Word16 var1, Word16 var2); Identical to L_mult. Word32 L_negate(Word32 L_var1); Performs long negate: negates 32-bit L_var1. Saturates if value is -2147483648 (0x80000000). Word32 L_sat(Word32 L_var1); Saturates a 32-bit value. Word32 L_shl(Word32 L_var1, Word16 var2); Performs long shift left: arithmetically shifts L_var1 left var2 positions, zero-filling the var2 least significant positions of the result. If var2 is negative, arithmetically shifts L_var1 right by var2 with sign extension. Saturates result in case of underflow or overflow. Word32 L_shl_nosat(Word32 L_var1, Word16 var2); Performs long shift left without saturation. Like L_shl, but does not saturate result in case of underflow or overflow. Word32 L_shr(Word32 L_var1, Word16 var2); Performs long shift right: arithmetically shifts L_var1 right var2 positions with sign extension. If var2 is negative, arithmetically shifts L_var1 left by var2 and zero fills result’s var2 lest significant bits. Saturates the result in case of underflow or overflow. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 67 Freescale Semiconductor, Inc. MWEntComp.book Page 68 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category DoublePrecision Fractional Arithmetic Primitives 68 Function Declaration Explanation Word32 L_shr_nosat(Word32 L_var1, Word16 var2); Performs long shift right without saturation. Like L_shr, but does not saturate result in case of underflow or overflow. Word32 L_shr_r(long,short) Performs long shifr right with rounding. Like L_shr, but with rounded result. Word32 L_sub(Word32 L_var1, Word32 L_var2); Performs long subtraction of L_var2 from L_var1, with overflow control and saturation. If overflow occurs, 32-bit result is +2147483647; if underflow occurs, 32-bit result is -2147483648 Word16 norm_l(Word32 L_var1); Returns -1( norm_l() ) Word16 norm_l(Word32 L_var1); Normalizes 32-bit fractional argument: shifts left enough times to normalize a positive L_var1 (interval 1073741824 — 2147483647), or to normalize a negative L_var 1 (interval 2147483648 — -1073741824). Word64 Read_64(Word64 * Fifo); Returns 64-bit value to which the passed-in pointer Word64 points. void Write_64(Word64 * Fifo, Word64 Value); Writes input 64-bit value to the location that the passed-in pointer Word64 specifies. Word64 D_add(Word64 D_var1, Word64 D_var2); Performs double-precision add of D_var1 and D_var2, with overflow control and saturation. Word64 D_add_opt(Word64 D_var1, Word64 D_var2); Performs optimized double-precision add of D_var1 and D_var2, provided that the leastsignificant-parts range permits operation without intermediate carry. NOTE: Use this function only if you are sure it is safe, or if you can verify its result. int D_cmpeq(Word64 D_var1, Word64 D_var2); Performs double-precision compare equal. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 69 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Function Declaration Explanation int D_cmpgt(Word64 D_var1, Word64 D_var2); Performs double-precision compare greater than. Word32 D_extract_h(Word64 Val); Performs double-precision extract high: returns 32 most significant bits of passed-in, 64-bit value. (Identical to D_get_msb.) Word32 D_extract_l(Word64 Val); Performs double-precision extract low: returns 32 least significant bits of passed-in, 64-bit value. (Identical to D_get_lsb.) Word32 D_get_lsb(Word64 Val); Returns 32 least significant bits of passed-in, 64-bit value. (Identical to D_extract_l.) Word32 D_get_msb(Word64 Val); Returns 32 most significant bits of passed-in, 64-bit value. (Identical to D_extract_h.) Word64 D_mac(Word64 D_var3, Word32 L_var1, Word32 L_var2); Performs double-precision multiply accumulate: multiplies L_var1 by L_var2 and shifts result left by 1. Adds 64-bit result to D_var3 with saturation, returning 64-bit result. Word64 D_msu(Word64 D_var3, Word32 L_var1, Word32 L_var2); Performs double-precision multiply subtract: multiplies L_var1 by L_var2 and shifts result left by 1. Subtracts 64-bit result from D_var3 with saturation, returning 64-bit result. Word64 D_mult(Word32 L_var1, Word32 L_var2); Performs double-precision multiply of L_var1 by L_var2, with one shift left, giving 64-bit result. Word64 D_mult_msp(Word32 left, Word32 right); Performs double-precision multiply of the Q31 most significant parts of a 64-bit word, storing the result in a Q31. Word64 D_mult_opt(Word32 left, Word32 right); Performs optimized version of D_add and D_mult, provided that the least-significantparts range permits operation without intermediate carry. NOTE: Use this function only if you are sure it is safe, or if you can verify its result. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 69 Freescale Semiconductor, Inc. MWEntComp.book Page 70 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Extended Precision Fractional Arithmetic Primitives (with Guard Bits) 70 Function Declaration Explanation Word32 D_round(Word64 D_var1); Performs double-precision round: rounds least significant 32 bits of D_var1 into most significant 32 bits, with saturation. Shifts resulting bits right by 32, returning 32-bit result. Word64 D_sat(Word64 D_var1); Saturates a 64-bit value. Word64 D_set(Word32 L_var1, UWord32 L_var2); Concatenates two 32-bit values, L_var1 and unsigned L_var2, into one 64-bit value. Word64 D_sub(Word64 D_var1, Word64 D_var2); Performs double-precision subtraction of D_var2 from D_var1, with overflow control and saturation. Word40 X_abs(Word40 X_var1); Returns 40-bit absolute value of X_var1. Word40 X_add(Word40 X_var1, Word40 X_var2); Performs extended precision add of X_var1 and X_var2, without saturation. int X_cmpeq(Word40 X_var1, Word40 X_var2); Performs extended precision compare equal. int X_cmpgt(Word40 X_var1, Word40 X_var2); Performs extended precision compare greater than. Word40 X_extend(Word32 L_var1); Sign extends 32-bit L_var1 to a 40-bit value. Word16 X_extract_h(Word40 X_var1); Performs extended precision extract high: returns 16 most significant bits of X_var1. Word16 X_extract_l(Word40 X_var1); Performs extended precision extract low: returns 16 least significant bits of X_var1. Word32 X_guard(Word40 X_var1); Returns guard bits from passed-in, 40-bit X_var1. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 71 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Function Declaration Explanation Word40 X_mac(Word40 X_var3, Word16 var1, Word16 var2); Performs extended precision multiply accumulate: multiplies var1 by var2 and shifts result left by 1. Adds 40-bit result to X_var3 without saturation, returning 40-bit result. Word40 X_msu(Word40 X_var3, Word16 var1, Word16 var2); Performs extended precision multiply subtract: multiplies var1 by var2 and shifts result left by 1. Subtracts 40-bit result from X_var3 without saturation, returning 40-bit result Word40 X_mult(Word16 var1, Word16 var2); Performs extended precision multiply of var1 by var2, with one shift left, giving 40-bit result. Word16 X_norm(Word40 X_var1); Normalizes the 40-bit X_var1 value. Word40 X_or(Word40 X_var1, Word40 X_var2); Performs logical OR on two 40-bit values. Word40 X_rol(Word40 X_var1); Rotates left a 40-bit word. Word40 X_rol_unsafe(Word40 X_var1); Performs a simple rol instruction on 40-bit X_var1, but does not reset the carry. (After rotation, bit 0 contains former carry value.) NOTE: Safe only if unrotated carry value is zero. Word40 X_ror(Word40 X_var1); Rotate right a 40-bit word Word40 X_ror_unsafe(Word40 X_var1); Performs a simple ror instruction on 40-bit X_var1, but does not reset the carry. (After rotation, bit 39 contains former carry value.) NOTE: Safe only if unrotated carry value is zero. Word16 X_round(Word40 X_var1); Performs extended precision round: rounds least significant 16 bits of X_var1 into most significant 16 bits, without saturation. Shifts resulting bits right by 16, returning 16-bit result. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 71 Freescale Semiconductor, Inc. MWEntComp.book Page 72 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Long Long, Double Support 72 Function Declaration Explanation Word32 X_sat(Word40 X_var1); Saturates a 40-bit value. Word40 X_set(char var1, UWord32 L_var2); Concatenates 8-bit character value var1 and unsigned, 32-bit value L_var2, into one 40-bit value. Word40 X_shl(Word40 X_var1, Word16 var2); Performs extended precision shift left: arithmetically shifts _var1 left var2 positions, zero-filling the var2 least significant bits of the result. If var2 is negative, arithmetically shifts X_var1 right by var2 with sign extension. Word40 X_shr(Word40 X_var1, Word16 var2); Performs extended precision shift right: arithmetically shifts X_var1 right var2 positions with sign extension. If var2 is negative, arithmetically shifts X_var1 left by var2 and zero fills result’s var2 lest significant bits. Word40 X_sub (Word40 X_var1, Word40 X_var2); Performs extended precision subtraction of X_var2 from X_var1, without saturation. Word32 X_trunc(Word40 X_var1); Truncate guard bits, converting 40-bit X_var1 to a 32-bit value. Word40 X_xor(Word40 X_var1, Word40 X_var2); Performs logical exclusive OR (XOR) on two 40-bit values. Int64 Db_to_LL(double val); Converts a double value to a long long value. (Available only if long long and double support is enabled.) UWord32 DD_get_lsb(Int64 val); Extracts the 32 least significant bits of a double value, storing the result as a UWord32 value. (Available only if long long and double support is enabled.) Word32 DD_get_msb(Int64 val); Extracts the 32 most significant bits of a double value, storing the result as a Word32 value. (Available only if long long and double support is enabled.) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 73 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Optimized Primitives Architecture Primitives Function Declaration Explanation double LL_to_Db(Int64 val) Converts a long long value to a double value. (Available only if long long and double support is enabled.) UWord32 LL_get_lsb(Int64 val); Extracts the 32 least significant bits of a long long value, storing the result as a UWord32 value. (Available only if long long and double support is enabled.) Word32 LL_get_msb(Int64 val); Extracts the 32 most significant bits of a long long value, storing the result as a Word32 value. (Available only if long long and double support is enabled.) Word32 L_mult_ls(Word32 L_var1, Word16 var2); Performs optimized 32*16 fractional multiplication. (Result differs from standard 32*16 multiplication in the least significant bit — 2** -31 error.) Word32 L_mult_sl(Word16 var1, Word32 L_var2); Performs optimized 16*32 fractional multiplication. (Result differs from standard 16*32 multiplication in the least significant bit — 2** -31 error.) Word32 mpysu_shr16(Word16 var1, Word32 L_var2) Performs signed/unsigned fractional multiplication of the L_var2 least significant bit by var1, then shifts the result to the right 16 positions. Word32 mpyus_shr16(Word32 L_var1, Word16 var2) Performs unsigned/signed fractional multiplication of the L_var1 least significant bit by var2, then shifts the result to the right 16 positions. void clearSRbit(int bitmask); Clears (assigns 0 to) bits of the status register. Word32 Clip(Word32 value, Word32 mask); Simulates a clip instruction; performs a simple transfer. int Get_Overflow(); Returns value of status-register overflow flag. Word32 L_rol(Word32 L_var1); Performs long rotate left: rotates 32-bit L_var1 left into a 40-bit value, returning a 32-bit value. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 73 Freescale Semiconductor, Inc. MWEntComp.book Page 74 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category 74 Function Declaration Explanation Word32 L_ror(Word32 L_var1); Performs long rotate right: rotates 32-bit L_var1 right into a 40-bit value, returning a 40bit value. Word32 mpysu(Word32 L_var1, Word32 L_var2); Performs long multiply signed-unsigned: multiplies 16 most significant bits of L_var1, treated as a signed value, by 16 least significant bits of L_var2, treated as an unsigned value. Word32 mpyus(Word32 L_var1, Word32 L_var2); Performs long multiply unsigned-signed: multiplies 16 least significant bits of L_var1, treated as an unsigned value, by 16 most significant bits of L_var2, treated as a signed value. Word32 mpyuu(Word32 L_var1, Word32 L_var2); Performs long multiply unsigned-unsigned: multiplies 16 least significant bits of L_var1 by 16 least significant bits of L_var2. Treats both words as unsigned values. void * Ovl_Load_Address(void * Symb_Addr); Returns actual address of a symbol. void *read OSP(void); Returns value of other stack pointer. int readSR(void); Returns contents of the status register. void set2crm(); Sets rounding mode to two’s-complement. void setcnvrm(); Sets rounding mode to convergent. void setnosat(); Clears (assigns 0 to) status-register saturation mode bit. void setPPL(int value); Sets program interrupt priority level: disables interrupt; clears status-register interrupt mask bits (21 — 23); assigns bits 21 — 23 the value of the passed-in argument; then enables interrupt. (Argument must be an immediate value.) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 75 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Architecture Primitives that Generate Identical Assembly Instructions Function Declaration Explanation void setsat32(); Sets (assigns 1 to) status-register saturation mode bit. void setSRbit(int bitmask); Sets (assigns 1 to) bits of the status register. void Set_Overflow(Word32 L_var1); Assigns value of status-register overflow flag: 1 if L_var1 value is non-zero, 0 of L_var1 is 0. int Test_Overflow(); Tests overflow: returns value 1 if statusregister overflow flag is set, otherwise returns 0. (Must be used in a conditional expression, such as X = Test_Overflow();). int trap_d(int var); Executes trap exception, storing its argument in ALU register 0. To specify a different ALU register, include its number (trap1_d, trap2_d, or trap3_d). Available for the SC1000 processor, and for the SC100 V3 processor. void trap_r(void * var); Executes trap exception, storing its argument in AGU register 0. To specify a different AGU register, include its number (trap1_r, trap2_r, or trap3_r). Available for the SC1000 processor, and for the SC100 V3 processor. void writeOSP(void *); Writes other stack pointer. void writeSR(int value); Writes passed-in integer value to the status register. void debug(); Generates assembly instruction to enter debug mode. void debugev(); Generates assembly instruction to issue debug event. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 75 Freescale Semiconductor, Inc. MWEntComp.book Page 76 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Miscellaneo us 76 Function Declaration Explanation void di(); Generates assembly instruction to disable interrupts. void ei(); Generates assembly instruction to enable interrupts. void illegal(); Generates assembly instruction to execute an illegal exception. void mark(); Generates assembly instruction to write program counter to trace buffer, If trace buffer is enabled. void stop(); Generates assembly instruction to enter Stop low power mode. void trap(); Generates assembly code to execute Trap exception. void wait(); Generates assembly code to enter Wait low power mode. int br_inc(int x, int n); Reverses the n least significant bits of the x input value, so that max_val = 1<<n. void cw_assert(int); Lets you indicate certain source-code properties. NOTE: Technically not an intrinsic function, but may be useful for the range analyzer or for loop optimizations. Word32 L_shl_nosat(Word32 L_var1, Word16 var2); Avoids saturation check (useful for normalization); specifies that L_var1 << var2, where var1 is a Q31 number. Word32 L_shr_nosat(Word32 L_var1, Word16 var2); Avoids saturation check (useful for normalization); specifies that L_var1 >> var2, where var1 is a Q31 number. Word16 neg_norm_l(Word32 L_var1); Returns the count of the leading zero bit of L_var1 (a Q31 number). Maps straight to the sc1400 clb instruction. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 77 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.17 Intrinsic Functions (continued) Category Function Declaration Explanation Word16 neg_norm_s(Word16 var1); Returns the count of the leading zero bit of var1 (a Q15 number). Maps straight to the sc1400 clb instruction. Word16 shl_nosat(Word16 var1, Word16 var2); Avoids saturation check (useful for normalization); specifies that var1 << var2, where var1 is a Q15 number. Word16 shr_nosat(Word16 var1, Word16 var2); Avoids saturation check (useful for normalization); specifies that var1 >> var2, where var1 is a Q15 number. Intrinsic Functions Examples Listing 3.23 shows the use of a number of intrinsic functions. Listing 3.23 Intrinsic Functions #include <prototype.h> void Iir(short Input[], short Coef[], short FiltOut[]) { long L_Sum; short int Stage, Smp; FiltOut[0] = Input[0]; for (Smp = 1; Smp < S_LEN; Smp++) { L_Sum = L_msu(LPC_ROUND, FiltOut[Smp - 1], Coef[0]); for (Stage = 1; ((0 < (Smp - Stage)) && Stage < NP); Stage++) L_Sum = L_msu(L_Sum, FiltOut[Smp - Stage - 1], Coef[Stage]); L_Sum = L_shl(L_Sum, ASHIFT); L_Sum = L_msu(L_Sum, Input[Smp], 0x8000); FiltOut[Smp] = extract_h(L_Sum); } } Listing 3.24 shows the use of extended precision variables and intrinsic functions that use guard bits. Listing 3.24 Intrinsic Functions Using Extended Precision #include <prototype.h> Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 77 Freescale Semiconductor, Inc. MWEntComp.book Page 78 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features docorr() { int j, i; int shift_val; short corr_0; Word40 E_acc, E_sum; E_acc = X_extend(0); E_sum = X_extend(0); for (i = 0; i < M1; i++) { for (j = 0; j < M2; j++) E_acc = X_mac (E_acc, sample[j], coeff[j] ); L_sample[i] = X_sat(E_acc); E_acc = X_abs(E_acc); E_sum = X_add(E_sum, E_acc); } shift_val = X_norm(E_sum); corr_0 = 0; for (i = 0; i < M1; i++) { sample[i] = round (L_shr (L_sample[i], shift_val)); corr_0 = sub (corr_0, sample[i]); } corr = corr_0; } Pragmas Pragmas let you give the compiler specific additional information, expanding your control of how the compiler processes certain statements. The pragmas you specify provide context-specific hints that can save the compiler unnecessary operations, further enhancing optimization. You can include as many pragmas as necessary in your source code. The sections that follow describe the syntax and placement rules for pragmas. Syntax Compiler pragmas follow this general syntax: 78 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 79 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features #pragma pragma-name [argument(s)] Each pragma must fit on one line. One or more of the arguments may be optional; commas must delimit arguments. Placement Each pragma applies only to a certain context, so you must place pragmas accordingly: • Pragmas that apply to functions — place them only in the scope of the function, after the opening brace. • Pragmas that apply to statements — place them immediately before the relevant statement, or immediately before any comment lines that precede the statement. • Pragmas that apply to variables — place them after the object definition, or after any comment lines that follow that definition. If a pragma refers to objects, the objects must be defined explicitly. • Other pragmas — place them according to their individual requirements. Table 3.18 lists the pragmas that the compiler supports. Table 3.18 Pragmas Category Pragma Description Function #pragma dynamic Always maps the function in which it appears on a dynamic stack, regardless of optimizations. #pragma far func_name Mandates far calls for the specified function, even if you use the small memory model. #pragma far variable Mandates long addressing mode for move instructions that manipulate the specified variable, even if you use the small memory model. #pragma fct_never_return func_name Permits non-standard return from the specified function; enables optimization that involves removal of code that includes normal return instructions. You may place this pragma in a header file, or at the head of a source file. #pragma inline Directs the compiler to inline any function that contains this pragma. #pragma inline_call func_name Directs the compiler to inline the next call of the specified function; must be placed just before that call. (Has no effect on a function call made through a pointer.) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 79 Freescale Semiconductor, Inc. MWEntComp.book Page 80 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.18 Pragmas (continued) Category Statement 80 Pragma Description #pragma interrupt func_name Defines the specified function as an interrupt handler; makes the function an interrupt entry. #pragma near func_name Mandates near calls for the specified function, even if you use the big memory model. #pragma near variable Mandates short addressing mode for move instructions that manipulate the specified variable, even if you use the big memory model. #pragma never_return Permits non-standard return from the function that contains this pragma; enables optimization that involves removal of code that includes normal return instructions. #pragma noinline Directs the compiler to not inline any function that contains this pragma. #pragma safe_mod Forces the compiler to perform modulo optimization without checking whether the initial value belongs to the modulo range. #pragma align func_name al_val Applies specified alignment value to specified function; overrides compiler’s default alignment rule. Also applies to alignment given through an application file. #pragma noswitchtable Forces mapping of a C switch statement, using a set of conditional static gotos, instead of a computed goto. Must be placed just before the switch statement. #pragma profile value Sets profiling information for a statement. NOTE: value is a signed 32-bit value. Its maximum is therefore 0x7FFFFFFF #pragma switchtable Forces mapping of a C switch statement, using a computed jump; uses pointer type as default. Must be placed just before the switch statement. #pragma switchtablebyte Like #pragma switchtable, but forces the used type to match a byte, instead of a 32-bit integer. Must be placed just before the switch statement. NOTE: Saves memory bytes, but the chosen type must be wide enough for all values of the switch cases. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 81 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.18 Pragmas (continued) Category Variables Other Pragma Description #pragma switchtableword Like #pragma switchtable, but forces the used type to match a 16-bit word, instead of a 32-bit integer. Must be placed just before the switch statement. NOTE: Saves memory bytes, but the chosen type must be wide enough for all values of the switch cases. #pragma align var_name|*ptr 4|8} Forces alignment on an array or pointer variable object. Needed for paired moves. #pragma far variable Mandates long addressing mode for any move instructions manipulating the specified variable, even if you use the small memory model. #pragma near variable Mandates short addressing mode for any move instructions manipulating the specified variable, even if you use the big memory model. #pragma bss_seg_name "name" Renames bss segment in the ELF file. (You must define the name used to override the default in the linker command file.) #pragma call_conv call_conv_name func_name Specifies calling convention compiler uses for a given function. The application configuration file must define the calling convention name, and func_name must be a previously declared function. Example: #pragma call_conv My_Call_Conv func1 #pragma data_seg_name "name" Renames data segment in the ELF file. (You must define the name used to override the default in the linker command file.) #pragma default_call_conv call_conv_name Specifies calling convention for a module (file). The application configuration file must define the calling convention name. #pragma init_seg_name "name" Renames init segment in the ELF file. (You must define the name used to override the default in the linker command file.) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 81 Freescale Semiconductor, Inc. MWEntComp.book Page 82 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.18 Pragmas (continued) Category Pragma Description #pragma loop_count (min_iter, max_iter [, {modulo}, [remainder]]) Specifies: (1) Minimum number of iterations (the compiler can use this value to remove loop bypass tests), (2) Maximum number of iterations (the compiler can use this value to assess the inductionvariable ramge), (3) Modulo/remainder pair (the compiler uses these values to unroll loops with dynamic loop count). This pragma must be inserted after the loop starter; not all fields are mandatory. Example — Iterate the loop at least once, at most 16 times; the loop count is a multiple of 2: #pragma loop_count (1,16,2,0) #pragma loop_multi_sample constant_val For an enclosed loop nest, performs an unroll and jam, then unrolls the enclosed loop. The constant is the unroll-and-jam factor. This #pragma applies only to loop nests that are single instruction blocks without calls. Example: #pragma loop_multi_sample 8 #pragma loop_unroll constant_val Unrolls constant time in the loop in which this pragma appears. Applies only to a single instruction block loop without calls. Example: #pragma loop_unroll 2 #pragma loop_unroll_and_jam constant_val Performs an unroll and jam on the enclosed loop nest. The constant is the unroll-and-jam factor. This #pragma applies only to loop nests that are single instruction blocks, without calls. Example: #pragma loop_unroll_and_jam 8 #pragma opt_level "optimization_level" 82 Controls level of code optimization, at either function or module level. Valid optimization-level values are O0, O1, O2, O3, Os, and O3s. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 83 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.18 Pragmas (continued) Category Pragma Description #pragma pgm_seg_name "name" Renames text segment in the ELF file. (You must define the name used to override the default in the linker command file.) #pragma rom_seg_name "name" Rename the rom segment in the ELF file. (You must define the name used to override the default in the linker command file.) Pragmas that Apply to Functions This section provides additional information about pragmas that apply to specific functions. You must define these pragmas in the scope of their functions, directly after the open-brace character ({) that marks the start of the scope. Aligning a Function The compiler follows one function-alignment rule if you optimize for code speed, but a different rule if you optimize for code size. To override either default rule, use #pragma align at the beginning of a function. This pragma also overrides function alignment given through an application file. Listing 3.26 shows an example of this pragma, with alignment value 1024. Listing 3.25 #pragma align void alpha() { #pragma align alpha 1024 printf(“Hello!\n”]; } Inlining a Function The inlining optimization is substituting an entire function for a function call. For very small functions, the calling overhead can exceed the function size. Inlining such functions can be very efficient. Use #pragma inline to force the compiler to inline a specific function; use #pragma noinline to prevent the compiler from inlining a specific function. The code of Listing 3.26, for example, prevents inlining for the function that follows #pragma noinline. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 83 Freescale Semiconductor, Inc. MWEntComp.book Page 84 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Listing 3.26 #pragma Noinline static int proc_30(int a) { #pragma noinline int tab_30[1000]; tab_30[0] = 4*a; return(tab_30[0]); } However, #pragma inline and #pragma noinline apply to all program calls of their specified functions. This can result in inlining that is too aggressive or not aggressive enough. Use #pragma inline_call for more precise control: this pragma directs the compiler to inline only the next call of the specified function. You should place this pragma just before the function’s calling statement. (This pragma has no effect on function calls made through pointers.) In response to the code of Listing 3.27, the compiler would not inline the first call to function f1, but would inline the second call. Listing 3.27 #pragma Inline_call void alpha(int index) { ... f1(); ... #pragma inline_call f1 f1(); ... } Allowing Non-Standard Returns Use #pragma fct_never_return or #pragma never-return to permit nonstandard returns from functions to their calling routines. Ordinarily, the compiler cannot implement optimizations that involve removing function code that includes the normal return instructions. But either of these pragmas make such optimizations possible, by letting the compiler abort the function safely: 84 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 85 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • Use #pragma fct_never_return in a header file, or at the head of a source file. This pragma specifies its function, so does not need to be in the same module as the function definition. • Use #pragma never-return inside the definition of its function. Saving System Context During normal processing, the compiler saves only essential data, including the contents of changed registers. If you want to restore the exact state, at the point where a specific function’s execution began, such a normal save is not adequate — you must instead save the entire system context. To do so, use #pragma save_ctxt, as Listing 3.28 shows. This pragma tells the compiler to save the entire context, including all registers that your procedure uses. However, #pragma save_ctxt can incur a large overhead, so you should use it only where absolutely necessary. Listing 3.28 #Pragma save_ctxt void EntryPoint() { #pragma save_ctxt ... } Defining a Function as an Interrupt Handler A function that operates as an interrupt handler differs from other functions: • It must save and restore all registers, without assuming any conventions, as the interrupt handler may be called at any time. • It must run in exception mode, so the compiler must generate instructions slightly different from normal-mode instructions. • It must not receive passed parameters; it must not return a value. To define a function as an interrupt handler, use #pragma interrupt, as Listing 3.29 shows. Listing 3.29 #pragma Interrupt void IntHandler(); #pragma interrupt IntHandler extern long Counter; void IntHandler() { Counter++; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 85 Freescale Semiconductor, Inc. MWEntComp.book Page 86 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features } Forcing Modulo Optimization At one time, the compiler performed modulo optimization only if: 1. The initial value belonged to the modulo range. 2. The step was static. 3. The step was smaller than 2 * modulo_value. But the current version of your CodeWarrior software lets you force modulo optimization without verifying the initial value. To do so, use #pragma safe_mod in a function, as Listing 3.30 shows. NOTE The safe_mod pragma applies to all modulo candidates in the function. Listing 3.30 #pragma Safe_mod int func1(unsigned int init, short *pt, short *pt1, int Max) { #pragma safe_mod unsigned int i, j; int Acc = 0; i = init; for(j = 0; j<Max; j++, i++) { Acc = pt[i%3] + pt1[i%5]; } for(j = 0; j<Max; j++, i++) { Acc = pt[i%3] + pt1[i%5]; } return Acc; } Without this pragma, the compiler could not perform modulo optimization because init is unknown for the first loop. Furthermore, i in the second loop comes from the first loop, so its value also would be unknown. NOTE 86 If you use #pragma safe_mod, you still must pass the -mod option and enable optimizations. This is because modulo replacement relies heavily on loop analysis, which is not part of optimization level -O0. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 87 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Forcing Addressing Mode Compiler options settings, such as the big or small memory model, determine the default calls to functions and accesses to variables. For more precise control, use #pragma far or #pragma near: • #Pragma far directs a 32-bit absolute call for the specified function, or 32-bit absolute access to a variable. • #Pragma near directs a 20-bit, PC-relative call for the specified function, or 16bit absolute access to a variable. The scope of these pragmas is the whole file: if you use them, you must place them at the beginning of the file. (Another way to specify far/near behavior is to use the configuration application file.) Note that #pragma far supports position-independent code (PIC), provided that the branch distance does not exceed 220. (The branch distance is the distance between the calling function and the called function.) If you are not supporting PIC, the branchdistance range for #pragma far is 0..232-1. In general, the compiler should treat functions as far functions any time the expected branch distance exceeds 220, even if you are not supporting PIC. Otherwise, the compiler tries to reduce code size, by substituting the bsr instruction (20-bit relative) for the jsr instruction (32-bit absolute). #pragma far prevents such a substitution. Listing 3.31 shows a possible use of these pragmas. Listing 3.31 #pragma far, #pragma near #pragma far alpha2 #pragma near alpha3 void alpha1() { #pragma noinline alpha2(); alpha3(); } Pragmas that Apply to Statements Place pragmas that apply to statements immediately before their relevant statements. Specifying a Profile Value The default settings of your compiler’s profiler determine the number of times to execute a given statement. To override this default guidance, specifying the exact number of times to execute a statement, use #pragma profile. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 87 Freescale Semiconductor, Inc. MWEntComp.book Page 88 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features NOTE The value argument of #pragma profile statement must be a 32-bit signed integer. The maximum value is 0x7FFFFFFF. In Listing 3.32, #pragma profile tells the compiler to execute the loop only 10 times. But note that this loop has dynamic bounds — if #pragma profile were not present, the compiler would execute the loop 25 times (the default value for such loops). The 15 additional loop executions would not make the program results incorrect, but would impair optimization. Listing 3.32 #pragma Profile with Constant Value #include <prototype.h> int energy (short block[], int N) { int i; long int L_tmp = 0; for (i = 0; i < N; i++) #pragma profile 10 L_tmp = L_mac (L_tmp, block[i], block[i]); return round (L_tmp); } With if-then-else constructs, you can use #pragma profile to tell the compiler which branch executes more frequently. The pragma also can convey the frequency ratio — the number of times one branch executes in relation to the other branch. In Listing 3.33, for example, the two #pragma profile statements have values 5 and 50. These values tell the compiler that the else branch section executes 10 times more frequently than the first (implied then) branch section. For this use, the frequency ratio is more significant than the exact #pragma profile values. In this example, the values 1 and 10 would convey the same information. Listing 3.33 #pragma Profile with Frequency Ratio #include <prototype.h> int energy (short block[], int N) { int i; long int L_tmp = 0; if ( N>50) #pragma profile 5 for (i = 0; i < 50; i++) 88 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 89 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features L_tmp = L_mac (L_tmp, block[i], block[i]); else #pragma profile 50 for (i = 0; i < N; i++) L_tmp = L_mac (L_tmp, block[i], block[i]); return round (L_tmp); } Defining a Loop Count If static information is available, the compiler uses it to determine the number of iterations for a loop. If static information is not available, the compiler still can determine the number of loop iterations, provided that it knows the upper and lower iteration limits. To provide these limits to the compiler, use #pragma loop_count. For example, the compiler can use the lower iteration limit to remove loop bypass tests. It can use the upper iteration limit to assess the range of induction variables after the loop, even if the exact loop-count value cannot be known at compile time. Specifying a modulo divider — 2 or 4 — enables the optimizer to unroll loops in the most efficient way. This modulo value corresponds to the number of execution units. You also can tell the compiler whether to use any remainder to execute the loop additional times. The compiler can use the modulo/remainder pair to unroll loops with dynamic loop count. The syntax of this pragma is: #pragma loop_count (min_iter, max_iter,[{modulo}, [remainder]]) Note that: • The modulo parameter is optional; the only valid values are 2 or 4. • To tell the compiler to use a remainder for the loop count, specify a value for remainder. A remainder argument is valid only if you specify a divider value. • You must place #pragma loop_count inside its loop, but outside any subordinate, nested loops. In the code of Listing 3.34, the loop iterates at least 4 times, at most 512 times. The iteration count always will be divisible by 4. The pragma does not specify a remainder, so the compiler disregards any remainder from the division. Listing 3.34 #pragma Loop Count void correlation2 (short vec1[], short vec2[], int N, short *result) { long int L_tmp = 0; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 89 Freescale Semiconductor, Inc. MWEntComp.book Page 90 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features int i; for (i = 0; i < N; i++) #pragma loop_count (4,512,4) L_tmp = L_mac (L_tmp, vec1[i], vec2[i]); *result = round (L_tmp); } Mapping Switch Statements Two representations are available for mapping switch statements onto StarCore assembly code. They are based on: • A computed goto — this requires a table of switch cases, stored in a RAM .data section. • A succession of conditional branches, with static conditions. The optimization type (speed or size) guides the compiler in selecting the appropriate representation, as does the footprint of the switch cases. If there are only a few successive switch cases, computed goto mapping is superior. But if the switch-case table is large, with many holes, conditional-branch mapping yields smaller code size. To force either type of mapping, use the appropriate pragma just before the switch statement: • #pragma switchtable — forces computed goto mapping, forcing the used type to match a 32-bit integer. • #pragma switchtablebyte — forces computed goto mapping, forcing the used type to match a byte. • #pragma switchtableword — forces computed goto mapping, forcing the used type to match a 16-bit word. • For conditional-branch mapping, use #pragma noswitchtable. NOTE The default location for switchtables is the .data section in RAM. To move them to ROM, instead, set the Switch_To_Rom option, in the configuration application file. Use the correct switchtable pragma — its type (integer, byte, or word) must be wide enough to represent all the switch-case values. For the example code of Listing 3.35, the compiler executes one of three pragmas, according to the values of NOSWITCH and USEWORD: • If the compiler executes #pragma noswitchtable, it produces 2746 bytes of code and 434 bytes of data (no switch table). 90 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 91 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features • If the compiler executes #pragma switchtable, it produces 1964 bytes of code and 834 bytes of data (an integer-type switch table). • If the compiler executes #pragma switchtableword, it produces 1964 bytes of code and 634 bytes of data (a word-type switch table). Listing 3.35 #pragmas Noswitchtable, Switchtable, Switchtablewordt #include <stdio.h> int Tab[100]; void alpha(int i) { #pragma noinline #ifdef NOSWITCH #pragma noswitchtable #else #pragma switchtable #ifdef USEWORD #pragma switchtableword #endif #endif switch (i) { case 0: Tab[0] = case 1: Tab[1] = case 2: Tab[2] = case 3: Tab[3] = case 4: Tab[4] = case 5: Tab[5] = case 6: Tab[6] = case 7: Tab[7] = case 8: Tab[8] = case 9: Tab[9] = case 10: Tab[10] case 11: Tab[11] case 12: Tab[12] case 13: Tab[13] case 14: Tab[14] case 15: Tab[15] case 16: Tab[16] case 17: Tab[17] case 18: Tab[18] case 19: Tab[19] case 20: Tab[20] case 21: Tab[21] case 22: Tab[22] case 23: Tab[23] case 24: Tab[24] case 25: Tab[25] 0; break; 1; break; 2; break; 3; break; 4; break; 5; break; 6; break; 7; break; 8; break; 9; break; = 10; break; = 11; break; = 12; break; = 13; break; = 14; break; = 15; break; = 16; break; = 17; break; = 18; break; = 19; break; = 20; break; = 21; break; = 22; break; = 23; break; = 24; break; = 25; break; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 91 Freescale Semiconductor, Inc. MWEntComp.book Page 92 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case case 92 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: Tab[26] Tab[27] Tab[28] Tab[29] Tab[30] Tab[31] Tab[32] Tab[33] Tab[34] Tab[35] Tab[36] Tab[37] Tab[38] Tab[39] Tab[40] Tab[41] Tab[42] Tab[43] Tab[44] Tab[45] Tab[46] Tab[47] Tab[48] Tab[49] Tab[50] Tab[51] Tab[52] Tab[53] Tab[54] Tab[55] Tab[56] Tab[57] Tab[58] Tab[59] Tab[60] Tab[61] Tab[62] Tab[63] Tab[64] Tab[65] Tab[66] Tab[67] Tab[68] Tab[69] Tab[70] Tab[71] Tab[72] Tab[73] = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 26; 27; 28; 29; 30; 31; 32; 33; 34; 35; 36; 37; 38; 39; 40; 41; 42; 43; 44; 45; 46; 47; 48; 49; 50; 51; 52; 53; 54; 55; 56; 57; 58; 59; 60; 61; 62; 63; 64; 65; 66; 67; 68; 69; 70; 71; 72; 73; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; break; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 93 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: default: Tab[74] = 74; break; Tab[75] = 75; break; Tab[76] = 76; break; Tab[77] = 77; break; Tab[78] = 78; break; Tab[79] = 79; break; Tab[80] = 80; break; Tab[81] = 81; break; Tab[82] = 82; break; Tab[83] = 83; break; Tab[84] = 84; break; Tab[85] = 85; break; Tab[86] = 86; break; Tab[87] = 87; break; Tab[88] = 88; break; Tab[89] = 89; break; Tab[90] = 90; break; Tab[91] = 91; break; Tab[92] = 92; break; Tab[93] = 93; break; Tab[94] = 94; break; Tab[95] = 95; break; Tab[96] = 96; break; Tab[97] = 97; break; Tab[98] = 98; break; Tab[99] = 99; break; Tab[1] = 1; break } } void main() { int i; for (i = 0; i<100; i++) alpha(i); for i = 0; i<100; i++) if (Tab[i] != i) {printf(“Failed at %d\n”, i); exit(0);} i = clock(); printf(“Passes [%d cycles]\n”, i); } Other Pragmas Place these additional pragmas immediately after the definition of the objects to which the pragmas refer. The object definitions must be explicit. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 93 Freescale Semiconductor, Inc. MWEntComp.book Page 94 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Aligning Variables Size usually determines object alignment; the default array alignment is by base type. But certain external functions require array alignment to a specified value before you can pass the array to the function. Use #pragma align to force such alignment, specifying the defined array object and the value 4 or 8. The value 4 specifies 4-byte (32-bit double word) alignment; the value 8 specifies 8-byte (64-bit quad word) alignment. The syntax is: #pragma align var_name|*ptr 4|8 For example, #pragma align T1 8 specifies 8-byte alignment for array T1. Certain instructions, such as move.2w and move.4w, move words in pairs. This may require alignment more strict than the defined alignment for the data types involved. If the compiler cannot assess the alignment for dynamic objects, it uses base-type alignment requirements for the objects. Consequently, the compiler cannot use the multiword move instructions for these objects. But if #pragma align specifies the exact alignment for such objects, the compiler does use multiword moves, generating more efficient code. For such a case, #pragma align specifies a pointer to alignment information. For example, #pragma align *in_ptr 8 tells the compiler that *in_ptr points to alignment information. It also tells the compiler to use 8-byte alignment, if possible. In the first part of Listing 3.36, array a is forced to 8-byte alignment before being passed to the external function Energy. The second part of the example informs the compiler that both input vectors are aligned to 32 bits. The instruction move.2f may be used here. Listing 3.36 #pragma Align #include <prototype.h> short a[10]; #pragma align a 8 extern int Energy( short a[] ); int alpha() { return Energy(a); } short Cor(short vec1[], short vec2[], int N) { #pragma align *vec1 4 #pragma align *vec2 4 long int L_tmp = 0; 94 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 95 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features long int L_tmp2 = 0; int i; for (i = 0; i < N; i += 2) L_tmp = L_mac(L_tmp, vec1[i], vec2[i]); L_tmp2 = L_mac(L_tmp2, vec1[i+1], vec2[i+1]); return round(L_tmp + L_tmp2); } Specifying Optimization Level The opt_level pragma can apply to a single function or to the whole module. To apply opt_level to a function, place the pragma in the function body. To apply opt_level to a module, place the pragma at the module level. An opt_level pragma in a function supersedes an opt_level pragma at the module level. An opt_level pragma at the module level supersedes the optimization level the shell passes. Listing 3.37 shows the possible opt_level pragma statements. Listing 3.37 Possible Opt_level Pragma Statements # This statement equals scc #pragma opt_level = "O0" # This statement equals scc #pragma opt_level = "O1" # This statement equals scc #pragma opt_level = "O2" # This statement equals scc #pragma opt_level = "O3" # This statement equals scc #pragma opt_level = "Os" # This statement equals scc #pragma opt_level = "O3s" -O0. -O1. -O2. -O3. -Os. -Os -O3. You cannot use -O3 as a command-level option with the O0, O1, O2, and Os options; you can use -O3 only with O3s. At command level, the O0, O1, O2, and Os options are compatible with O0 O1 O2 Os as pragmas. Listing 3.38 shows a code example that uses the opt_level pragma. If the commandline is scc -Os opt.c, the compiler compiles func1 in O0 as the module-level option is O0. The compiler compiles the func2 function in O2 (which overrides O0 specified in the module and Os specified in the command line). Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 95 Freescale Semiconductor, Inc. MWEntComp.book Page 96 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Listing 3.38 Opt.c: Opt_level Pragma Code Example typedef struct { int a; int b; } S; #pragma opt_level = "O0" void func1() { typedef struct { short a; short b; } S; S v; v.a = 0; v.b = 1; } void func2() { #pragma opt_level = "O2" S v; v.a = 2; v.b = 3; } Renaming Segments of ELF Files Five pragmas let you rename segments or ELF files: • #pragma pgm_seg_name "name" — to rename a text segment. • #pragma data_seg_name "name" — to rename a data segment. • #pragma rom_seg_name "name" — to rename the ROM segment. • #pragma bss_seg_name "name" — to rename the bss segment. • #pragma init_seg_name "name" — to rename the init segment. For any of these pragmas, you must follow these rules: 1. The new segment name you define cannot include any spaces. 2. You can place the pragma anywhere in the module (file); it affects the entire file. 96 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 97 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features 3. You must define the name used to override the default segment name in the linker command file. NOTE To specify text-segment overlay, add an overlay value to the segment-name pragma: #pragma pgm_seg_name “name” “overlay”. Optimizing Loops The -u compiler option controls automatic loop unrolling. For greater control of this optimization, you can use #pragma loop_unroll to force loop unrolling, or to block automatic loop unrolling. But note that forcing loop unrolling can impair performance. Also note that the same restrictions apply to manual and automatic loop unrolling: • The loop count must be a multiple of the unrolling factor, • The loop body must not contain any flow control, • The loop body must not contain any call to a function returning structure, and • The loop body must not contain any modulo induction variable (IV). The syntax of this pragma is: #pragma loop_unroll factor The factor parameter is the unrolling factor, such as 2, 4, or 8. The factor value 0 blocks loop unrolling. Unrolling and Jamming a Loop Nest The unroll-and-jam transformation consists of unrolling an enclosing loop a specified number of times, then merging multiple instances of the enclosed loop. The unroll-andjam factor specifies the number of times to unroll the enclosing loop. The goal of this transformation is increasing the parallelism available for pipelining. However, this transformation changes the order of execution for the loop iterations. This means that unrolling-and-jamming is not always valid: it could violate data dependencies. Listing 3.39 shows the syntax of this pragma. Listing 3.39 Unroll and Jam Pragma Syntax ... for() { for() { #pragma loop_unroll_and_jam factor ... } } Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 97 Freescale Semiconductor, Inc. MWEntComp.book Page 98 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features ... Multi-Sampling a Loop Nest Multi-sampling consists of unrolling and jamming a loop nest, then unrolling the enclosed loop. This transformation reveals more opportunities for vectorizing memory access than does unroll-and-jam. The same restrictions apply to the multi-sampling transformation and to the unroll-andjam transformation. Listing 3.40 shows the syntax of this pragma. Listing 3.40 Multi-Sampling Pragma Syntax ... for() { for() { #pragma loop_multi_sample factor ... } } ... Predefined Macros The compiler shell includes several predefined macros. Some are standard C macros; others are specific to the Metrowerks Enterprise C compiler and the SC100 architecture. Table 3.19 lists all these macros. Table 3.19 Predefined Macros Macro Name Description __LINE__ The line number of the current source line. __FILE__ The name of the current source file. __DATE__ The compilation date, as a character string in the form Mmm dd yyyy (for example, Jan 23 1999). __TIME__ The compilation time, as a character string in the form: hh:mm:ss.t __STDC__ 98 Decimal constant 1, indicating ANSI conformance. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 99 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features Table 3.19 Predefined Macros (continued) Macro Name Description __STDC_VERSION__ Defined in ANSI C mode as 199409L. __SIGNED_CHARS__ Defined when char is signed by default __VERSION__ The version number of the compiler, as a character string in the form nn.nn. __INCLUDE_LEVEL__ Decimal constant, indicating the current depth of file inclusion. _ENTERPRISE_C_ Defined for use with the Enterprise compiler. If your source file may be compiled with other compilers apart from the Enterprise, this macro should be included in a conditional statement to ensure that the appropriate commands are activated, for example: #ifdef _ENTERPRISE_C_ (Enterprise-specific commands) #else .... #endif _SC100_ Defined for use with all compilers based on the SC100 architecture. If your source file may be compiled with other compilers apart from those based on the SC100 architecture, this macro should be included in a conditional statement to ensure that the appropriate commands are activated, as shown in the following example: #ifdef _SC100_ (SC100-specific commands) #else .... #endif _SC110_ _SC140_ The architecture variant, which specifies the number of MAC units to be used by the compiler: • _SC110_ indicates 1 MAC unit. • _SC140_ indicates 4 MAC units. Only one of these macros is valid for each invocation of the compiler. The macro that is selected, and the value of the architecture variant, are determined by the value set for the arch option when the compiler is invoked. If no value is specified for -arch, the default is SC140 (_SC140_). Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 99 Freescale Semiconductor, Inc. MWEntComp.book Page 100 Monday, September 27, 2004 2:17 PM Using the Metrowerks Enterprise C Compiler Language Features 100 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 101 Monday, September 27, 2004 2:17 PM 4 Mixing C, Assembly Code The Metrowerks Enterprise C compiler lets you use both C and assembly language statements within a C source file. In addition, the compiler lets you call assembly language functions implemented in other files from within a C source file. This chapter explains how to use these features and provides instructions, guidelines, and examples. It contains these sections: • Inlining One Assembly Instruction • Inlining an Assembly Sequence • Calling a Function in a Different File • Including Offset Labels in Output File Inlining One Assembly Instruction The Enterprise C compiler lets you place a single assembly language instruction inline within a sequence of C statements. For successful compilation of such an inlined assembly instruction, follow these guidelines: • Make sure that no inlined assembly-language instruction affects the C or assembly environment, or results are unpredictable. The compiler passes an inlined assemblylanguage instruction to the assembly output file in text form, without knowledge of the instruction contents or side effects. For example, do not use an inlined assembly language instruction to change the contents of registers, because the compiler has no knowledge of such changes. Similarly, do not include any jumps or labels that access the C code — they could affect the correctness of the tracking algorithms. • Remember that the optimizer ignores inlined assembly-code instructions. • Check the syntax and text of the instruction before compilation. The compiler treats the assembly-language instruction as a text string, so cannot perform any error checking. Only at the assembly stage can the compiler identify errors in assemblylanguage code. • Never let a single inlined assembly-language instruction reference a C object. The only way to reference a C object in assembly-language code is to inline a sequence of assembly instructions. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 101 Freescale Semiconductor, Inc. MWEntComp.book Page 102 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Inlining an Assembly Sequence To inline a single assembly instruction, use the asm statement, which has syntax similar to that of a C-language function call. You pass the mnemonic of an assembly language instruction as a string, surrounded by double quotation marks. NOTE The quoted string for the asm function must appear exactly as it would in the C file, obeying the rules for assembly-language lines. The mnemonic must not begin in column 1, so asm(“nop”) would be wrong. The correct format is asm(“ nop”). Listing 4.1 is an example of a single inlined assembly-language instruction. Listing 4.1 Example of a Single Inline Assembly Language Instruction asm("wait"); /*incorrect - no leading space */ asm(" wait");/*correct - leading space as required */ Inlining an Assembly Sequence To use assembly-language code that references C objects, you must: 1. Define a separate function that consists of a sequence of assembly-language instructions. 2. Inline this entire function in your C code. Such a function cannot include C statements, but it can accept parameters that the assembly-language code references. Guidelines The following guidelines for inlined sequences are similar to those for inlining individual assembly-language instructions: • Make sure that no inlined assembly-language instructions affect the C or assembly environment. The compiler passes the sequence of inlined assembly-language instructions to the assembly output file as a string of text, without knowledge of contents or side effects. For example, do not use inlined assembly instructions to change the contents of registers. Do not use jump instructions that change the sequence of C code instructions, as the compiler has no knowledge of such changes. 102 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 103 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Inlining an Assembly Sequence • For the most effective optimization, use C alternatives instead of assembly-based instructions — the optimizer ignores functions based on inlined sequences of assembly code. • Check instruction syntax and text before compilation. The compiler cannot identify assembly-code errors until the assembly stage of compilation. These additional guidelines pertain to inlined sequences of assembly-language code: • You must specify the register from which each parameter enters the function, and the register to which each parameter leaves the function. There is no automatic allocation of registers for passing parameters. However, there is no need to save or restore the registers before or after the function. • You must tell the compiler if the function modifies global variables or has any other such possible side effects. The compiler cannot determine whether an inlined function might affect the application. • Avoid such statements as RTS. Even if you define a function as standalone, it is possible that the compiler will include this function in a sequence of instructions. In such a case, the compiler automatically adds the necessary return statements. • If the function requires local variables, you must allocate them specifically on the stack, or define them as static variables. The compiler does not automatically allocate local variables for use by assembly-language functions. • Assembly-language functions you define as a sequence of instructions can access global variables in the C source code. This is because such variables are static by definition. Defining an Inlined Sequence To define a sequence of inlined assembly instructions, you define the header for the function, the body of the instructions, then the registers each parameter is to use. You can define a list of read parameters, a list of write parameters, or a list of modified registers, as appropriate. Listing 4.2 shows the syntax for inlining a sequence of assembly instructions. Listing 4.2 Syntax for Inlining a Sequence of Assembly Instructions asm <func prototype> { asm_header optional arg binding optional return value optional read list optional write list optional modified reg list Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 103 Freescale Semiconductor, Inc. MWEntComp.book Page 104 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Inlining an Assembly Sequence asm_body <asm code> asm_end } optional arg binding .arg <ident> in <reg>; <ident> in <reg>; ... optional return value return in <reg> optional read list: .read <ident>,<ident>,...; optional write list: .write <ident>,<ident>,...; optional modified reg list: .reg <reg>, <reg>, ...; These syntax rules apply: • Identifiers must have the prefix _ (underscore). • Registers must have the prefix $ (dollar sign). • Labels must have the suffix . (period). Listing 4.3 shows the syntax for an inlined assembly function that takes two input parameters from registers d0 and r1, then returns the result in d0. Listing 4.3 Inlining Syntax asm int t6( int param1, int *param2) { asm_header .arg _param1 in $d0; _param2 in $r1; return in $d0; .reg $d0,$d1,$r1; asm_body move.l (r1),d1 add d0,d1,d0 asm_end } 104 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 105 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Inlining an Assembly Sequence In Listing 4.4, the function t6 accepts two parameters: integer p1 (passed in register d14) and pointer p2 (passed in r7). The function returns the result in d14. Listing 4.4 Simple Inlined Assembly Function #include <stdio.h> int A[10] = {1,2,3,4,5,6,7,8,9,0}; asm int t6(int p1, int *p2) { asm_header .arg _p1 in $d14; _p2 in $r7; return in $d14; .reg $d14,$d1,$r7; asm_body move.l (r7),d1 add d14,d1,d14 asm_end } int main() { int k = 8; int s; s = t6(k,&A[3]); printf("S= %d\n",s); return s; } Listing 4.5 shows labels and hardware loops within inlined assembly functions. You should use hardware loops within assembly functions only if you know that the loop nesting is valid. In this example, the function is called from outside a loop, so hardware loops are allowed. Listing 4.5 Inlined Assembly Function with Labels and Hardware Loops #include <stdio.h> char sample[10] = {9,6,7,1,0,5,1,8,2,6}; int status; asm char t7(int p) { Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 105 Freescale Semiconductor, Inc. MWEntComp.book Page 106 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Inlining an Assembly Sequence asm_header .arg _p in $d7; return in $d8; .reg $d7,$d8,$r1; asm_body clr d8 move.l #_sample,r1 doen3 d7 dosetup3 _L10 loopstart3 _L10: move.b (r1),d1 add d8,d1,d8 inc d1 move.b d1,(r1)+ loopend3 asm_end } int main() { int m = 8; int s,i; for(i=0;i < 10;i++) { sample[i] *= 2; printf("%d ",sample[i]); } printf("\n"); s = (int)t7(m); printf("S= %d\n",s); for(i=0;i < 10;i++) printf("%d ",sample[i]); printf("\n"); return 1; } Listing 4.6 includes referencing global variables within an inlined assembly function. To access global variables, you use their linkage name — the default linkage name is the variable name with an underscore (_) prefix. For example, to access variables vector1 and vector2 within the function, use linkage names _vector1 and _vector2. Listing 4.6 Referencing Global Variables in an Inlined Assembly Function #include <stdio.h> 106 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 107 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Calling a Function in a Different File short vector1[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; int vector2[] = {11,12,13,14,15,16,17,18,19,1,2,3,4,5,6}; short result_1=0; int result_2=0; asm void test(int n, short *r1,int *r2) { asm_header .arg _n in $r1; _r1 in $r3; _r2 in $r7; .reg $d0,$r1,$r6,$r11,$r3,$r7; asm_body move.l #_vector1,r6 move.l #_vector2,r11 addl1a r1,r6 addl2a r1,r11 move.w (r6),d0 asrr #<2,d0 move.w d0,(r3) move.l (r11),d1 asl d1,d2 move.l d2,(r7) asm_end } int main(void) { test(12,&result_1,&result_2); printf("Status = %d %d\n",(int)result_1, result_2); return (int)result_2; } Calling a Function in a Different File The compiler supports calls to assembly functions in separate files. This lets you integrate these files with your C application. To include a call to an assembly function in your program, follow these steps: 1. Write the assembly function in a separate file from your C source files. Use the standard calling conventions. 2. If required, assemble the file. (This step is optional.) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 107 Freescale Semiconductor, Inc. MWEntComp.book Page 108 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Calling a Function in a Different File 3. In your C source file, define the assembly function as an external function. 4. In the shell command line, specify both the C source file and the assembly file as input files. This tells the compiler to integrate the files during compilation. The following examples show how a segment of C code calls a function — implemented in assembly — that performs an FFT algorithm. Writing the Assembly Code Listing 4.7 shows the assembly code for the FFT algorithm, in the file fft.sl. Listing 4.7 Assembly Function in a Separate File ; ; extern void fft(short *, short*); ; ; Parameters: pointer to input buffer in r0 ; pointer to output buffer in r1 ; _fft: ;Save and restore d6, d7, r6, r7, according to ;calling conventions. push d6 push d7 push r6 push r7 < implementation of FFT algorithm > pop pop pop pop r6 r7 d6 d7 rts Calling the Assembly Function Listing 4.8 shows the C language code that calls the FFT function. This source code is saved in the file test_fft.c. Listing 4.8 C Language Code That Calls an Assembly Language Function #include <stdio.h> extern void fft(short *, short*); 108 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 109 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Calling a Function in a Different File #pragma external fft short in_block[512]; short out_block[512]; int in_block_length, out_block_length; void main() { int i; FILE *fp; int status; in_block_length=512; out_block_length=512; fp=fopen("in.dat","rb"); if( fp== 0 ) { printf("Can’t open parameter file: input_file.dat\n"); exit(-1); } printf("Processing function fft \n"); while ((status=fread(in_block, sizeof(short), in_block_length, fp)) == in_block_length) { fft(in_block,out_block); } } Integrating C, Assembly Files Listing 4.9 shows how the shell command line specifies the two input files: Listing 4.9 Integrating C and Assembly Files scc -o test_fft.eld test_fft.c fft.sl Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 109 Freescale Semiconductor, Inc. MWEntComp.book Page 110 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Including Offset Labels in Output File Including Offset Labels in Output File In some cases, data structures must be shared between the C source code and the called assembly code. In Listing 4.10, for example, the assembly code must use the layout of structure complex: Listing 4.10 Data Structure Shared Between C and Assembly struct complex { short r; short i; }; struct complex CVEC1, CVEC2; volatile struct complex res; void main() { cmpy (&CVEC1, &CVEC2, &res); The -do option in the shell command line instructs the compiler to include the details of C data structures in the output assembly file. Listing 4.11 shows this additional option: Listing 4.11 Specifying the Output of Offset Information scc -o test.eld test.c cmpy.sl -do If the command line include the -do option, the output file shows the offsets for all field definitions in each data structure that the C source code defines. The symbolic label consists of: <module name>_<structure name>_<field name>, as Listing 4.12 shows: Listing 4.12 Data Structure Offsets in the Assembly Output File test_complex_r test_complex_i equ equ 0 2 The assembly code can use the symbolic labels of the output file, as Listing 4.13 shows. Using these symbolic labels makes the code more readable, and makes assembly-code maintenance easier if you changes the C code. 110 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 111 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Including Offset Labels in Output File Listing 4.13 Using Symbolic Offsets in Assembly Code ;========================================================= ; Function cmpy ; ; Parameter x passed in r0 ; Parameter y passed in r1 ; Parameter result passed in (sp-12) ;========================================================= global align _cmpy 2 _cmpy [ move.2f move.2f (r0),d0d1 (r1),d2d3 mpy mpy macr macr move.l d0,d2,d5 d0,d3,d7 -d1,d3,d5 d1,d2,d7 sp-12),r2 rtsd moves.f moves.f d5,(r2+test_complex_r) d7,(r2+test_complex_i) ] [ ] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 111 Freescale Semiconductor, Inc. MWEntComp.book Page 112 Monday, September 27, 2004 2:17 PM Mixing C, Assembly Code Including Offset Labels in Output File 112 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 113 Monday, September 27, 2004 2:17 PM 5 Runtime Environment This chapter explains the startup code that the Metrowerks Enterprise C compiler uses, the layout and configuration of memory, and the calling conventions that the compiler supports. This chapter contains these sections: • Startup Code • Memory Models • Memory Layout and Configuration • Controlling Configuration • Calling Conventions Startup Code The compiler runtime startup code consists of these components: • Initialization code, which is executed when the program is initiated and before its main function is called • Finalization code, which controls the closedown of the application after the program’s main function terminates • Entry points for low-level I/O services • The interrupt vector table • Support for debugging tools Table 5.1 shows the patterns for directory and subdirectory names. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 113 Freescale Semiconductor, Inc. MWEntComp.book Page 114 Monday, September 27, 2004 2:17 PM Runtime Environment Startup Code Table 5.1 Startup Code Directory Patterns File Type Operating System Directory/Subdirectory Compiler Startup Code Windows $SCTOOLS_HOME/src/rtlib/startup/core/platform/ reentrant $SCTOOLS_HOME/src/rtlib/startup/core/platform $SCTOOLS_HOME/src/rtlib/startup/core $SCTOOLS_HOME/src/rtlib/startup Generated Object Module Solaris StarCore/starcore_support/src/rtlib Windows $SCTOOLS_HOME/lib/[core or platform] Solaris Starcore/starcore_support/lib For example, for reentrant 8102 startup code, the Windows makefile looks for the source in these directories: rtlib/startup/sc140/msc8102/reentrant rtlib/startup/sc140/msc8102 rtlib/startup/sc140/ rtlib/startup The destination for a generated object module file is a Windows directory such as: • $SCTOOLS_HOME/lib/sc140 — for the generic SC140 • $SCTOOLS_HOME/lib/msc8102 — for the MSC8102 • startup_be-r.eln, in $SCTOOLS_HOME/lib/msc8102 — for MSC8102 reentrant The compiler startup code consists of two phases: • Bare board startup code — for programs that execute without the support of any runtime executive or operating system. This phase resets the interrupt vector and initializes all necessary hardware registers. • C environment startup code — a mandatory phase for all configurations. This phase initializes the runtime structure of the application for the C environment, and includes the finalization code the system uses after program termination. 114 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 115 Monday, September 27, 2004 2:17 PM Runtime Environment Startup Code Bare Board Startup Code The bare board startup code performs actions that an operating system or runtime executive usually does, as if there were no operating system or runtime executive. These actions include: 1. Setting the reset interrupt vector to point to the system entry point __crt0_start, as if there just had been a system reset. The interrupt vector table holds the addresses of all interrupt handlers. The first entry in this table is the system entry point. The default arrangement is that all other entries in the interrupt vector table point to the abort function. 2. Initializing hardware registers: a. Initializing the four modulo (M) registers (m0-m3) to linear addressing. b. Setting the status register to an initial value from the linker command file used at link time. This file includes a label SR_setting, which specifies the initial status-register value following a system reset. Table 5.2 shows the default status register settings. Table 5.2 Status Register Default Settings Setting Type Value Mode: Exception mode Interrupt level: 7 Saturation: On Rounding mode: NEAREST_EVEN 3. Activating the timer, if the system includes one. 4. Terminating the bare board startup phase by jumping to the C environment startup code entry point, ___start. C Environment Startup Code The C environment startup phase applies to all programs. The entry point for this phase is ___start. This phase includes initialization code used prior to program start, and finalization code used after the application terminates. C Environment initialization Code The system performs these initialization actions before the application starts: Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 115 Freescale Semiconductor, Inc. MWEntComp.book Page 116 Monday, September 27, 2004 2:17 PM Runtime Environment Startup Code 1. Setting up and initializing the memory map. The stack start address, located at StackStart, loads the stack pointer (SP) value into memory, The linker command file defines this label; the linker uses this label at link time. 2. If the shell command line includes the -mrom option, copying initialized variables from ROM to RAM. This option is required for applications that do not use a loader. 3. Setting up the argv and argc arguments. 4. Enabling interrupts — which have remained disabled until this point. 5. Using the function main to call the application main procedure entry point. Initialization of Variables If your system uses a loader, the loader is the default initializer for all variables. If your system does not include a loader, you must specify the -mrom option when you compile the final version of your application. This makes sure that the system copies initialized variables from ROM to RAM at startup. NOTE If you use custom startup code, variables in the .bss section may not be initialized. C Environment Finalization Code On return from the application main function, the system calls the runtime function exit. This terminates any I/O services not yet ended. This function also issues the stop instruction to stop the processor. NOTE Certain embedded real time applications never terminate. Such termination activities do not usually pertain to embedded applications, but may be of use during early development and debugging stages. Low-Level I/O Services The C environment startup code includes the input and output of low-level, buffered I/O services. The code uses calls to __send and __receive in order to interface with debugging tools and/or runtime systems. Configuring Your Startup Code If the default runtime setup does not match your configuration, you must modify your startup code accordingly. To create your own runtime configuration code, follow these steps: 116 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 117 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Models 1. Copy the default startup file; name the copy anything you want. NOTE The architecture you use determines which default startup file to copy. Each startup file is in a directory named: $SC100_HOME/lib/arch_name where arch_name is a placeholder for the name of one of the StarCore architectures (for example, sc110, sc140, or sc1400). Listing 5.1 shows an example command to copy a startup file. Listing 5.1 Making a Copy of a Startup File cp install-dir/src/rtlib/startup/arch_name/startup.asm mysc100.asm 2. Make the required changes to the new file. 3. Assemble the modified file, as Listing 5.2 shows. Listing 5.2 Assembling the Modified Startup File asmsc100 -b -l mysc100.asm The generated object file is mysc100_be.eln or mysc100_le.eln, depending on whether you use big endian or little endian mode. 4. Specify the -crt option in the shell command line (as Listing 5.3 shows), to make sure that the system uses the modified startup file at link time. Listing 5.3 Using the Modified Startup File scc -crt mysc100_le.eln my-object-files.eln Memory Models The compiler architecture supports both 16-bit and 32-bit addresses. If your application is small enough that all static data fits into the lower 64K of the address space, the compiler can generate more efficient code. This small memory model is the default mode; all addresses must be 16-bit for this mode. The big memory model does not restrict the amount of space allocated to addresses. The shell command-line option -mb selects this model. When the compiler uses the big memory model to access a data object, whether static or global, it must use a longer instruction that includes a 32-bit address. This operation Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 117 Freescale Semiconductor, Inc. MWEntComp.book Page 118 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Models requires an additional word. Consequently, the big memory model leads to code that is larger, and in some cases, slower, than the small memory model does for a similar operation. Listing 5.4 shows the use of the move.l instruction in the big and small memory models. In this example, the assembler interprets the address in the first instruction as a 32-bit address, and allocates the maximum space for it. In the second instruction, the < symbol indicates to the assembler that this address fits into a 16-bit space, thus preventing the allocation of unnecessary program memory. Listing 5.4 Big and Small Memory Models ; Big memory model (3 16-bit words): move.l address,d0 ; Small memory model (2 16-bit words): move.l <address,d0 Certain instructions can be used only in small memory mode. If < is omitted in conjunction with these instructions, an error results. Listing 5.5 shows the instruction bmset.w, which sets bit #zero in the specified address, and is valid only in small memory mode. Listing 5.5 Small Memory Mode Instruction bmset.w #0001,<address For maximum efficiency, it is recommended that you place data in the lower 64KB of the memory map, so the compiler can use the small memory mode. A variation of the big memory model is enabled by the -mb1 option. Use this model for program’s whose code and static data require more than 64 KB but less than 1 MB of memory for all but the runtime code. In this model, the runtime code can be more than 1 MB away from the rest of the program. If your program’s code and static data requires more than 1 MB of memory, use the huge memory model. To select the huge memory model, use the -mh command line option. The SC100 Linker refers to a linker command file at link time, for various runtime values, addresses, and labels. Two linker command files are provided, one for each memory mode. These files are crtscsmm.cmd, used in small memory mode, and crtscbmm.cmd, used when big memory mode is selected. Both files are located in the install-dir/etc directory. 118 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 119 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Layout and Configuration Memory Layout and Configuration The SC100 default memory layout is a single linear block which is divided into data and code areas. C programs generate code and data in sections. The compiler places each of these sections in its own continuous space in memory. The default layout of the SC100 memory is illustrated in Figure 5.1. Figure 5.1 SC100 Default Memory Layout TopOfMemory High addresses ROM ROMStart Heap TopOfStack Stack StackStart Code CodeStart Global/static data DataSize DataStart Interrupt vector table Low addresses 0 Both memory models use the same default layout, but with different default values that define the distribution of the memory areas. You can change these default values. You also can configure the memory map to meet your specific requirements. The layout and functionality of the stack and heap are common to both the small and big memory models. The default memory map values for the small memory model are listed in Table 5.3. These values are held in the file crtscsmm.cmd. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 119 Freescale Semiconductor, Inc. MWEntComp.book Page 120 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Layout and Configuration Table 5.3 Small Memory Model: Default Values From Default To Default Contents Interrupt vector table 0 0x1ff 0x200 DataSize-1 0xfffd Global and static variables CodeStart 0x10000 StackStart-1 0x27fff Program code StackStart 0x28000 TopOfStack 0x7fff0 Stack and heap ROMStart 0x80000 TopOfMemory 0xfffff ROM Table 5.4 lists the default memory map values for the big memory model. These values are held in the file crtscbmm.cmd. Table 5.4 Big Memory Model: Default Values From Default To Default value Contents Interrupt vector table 0 0x1ff 0x200 DataSize-1 0x17fff Global and static variables CodeStart 0x18000 StackStart-1 0x3ffff Program code StackStart 0x40000 TopOfStack 0x7fff0 Stack and heap ROMStart 0x80000 TopOfMemory 0xfffff ROM Stack and Heap Configuration The heap and stack are allocated from the same area of memory and must be contiguous. The compiler always treats the stack and heap as a continuous area of memory. The other sections of memory can be distributed, and there are no restrictions relating to their location. Runtime Stack The compiler allocates an area of memory to the runtime stack, which is used for the following purposes: • Allocation of local variables • Passing arguments to functions 120 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 121 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Layout and Configuration • Saving function return addresses • Saving temporary results The stack is allocated in the area above the space used for code, and grows in an upward direction toward the top of memory. The compiler uses the SP register to manage this stack. The SC100 architecture includes two stack pointers: • NSP, used when the processor is running in Normal mode • ESP, used when the processor is running in Exception mode As shown in Table 5.2 on page 115, the default mode at initialization is Exception mode. The compiler makes no assumptions about which stack pointer to use, and uses the pointer for the current processor mode to point to the address at the top of the stack. When the system is initialized, the stack pointer for the current mode is set by default to the address of the location directly after the code area, as defined in StackStart in the linker command file. The actual address of the stack is determined at link time. The stack pointer for the current processor mode is automatically incremented by the C environment at the entry to a function. This ensures that sufficient space is reserved for the execution of the function. At the function exit, the stack pointer is decremented, and the stack is restored to its previous size prior to function entry. If your application includes assembly language routines and C code, you must ensure at the end of each assembly routine that the current stack pointer is restored to its pre-routine entry state. NOTE If you change the default memory configuration, remember to allow sufficient space for the stack to grow. If a stack overflow occurs at runtime, this will cause your program to fail. The compiler does not check for stack overflow during compilation or at runtime. Dynamic Memory Allocation (Heap) The runtime libraries supported by the compiler include a number of functions which enable you to allocate memory dynamically for variables. See Chapter 7 for details of the runtime libraries supported. Since C does not support the dynamic allocation of memory, the compiler assigns an area of memory as a heap for this purpose. The compiler allocates memory from a global pool for the stack and the heap together. The lower address of the area assigned to the stack and heap is defined in StackStart, in the linker command file. The heap starts at the top of memory, and is allocated in a downward direction toward the stack. Objects that are dynamically allocated are addressed only with pointers, and not directly. The amount of space that can be allocated to the heap is limited by the amount of available memory in your system. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 121 Freescale Semiconductor, Inc. MWEntComp.book Page 122 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Layout and Configuration To make more efficient use of the space allocated to data, you can use the heap to allocate large arrays, instead of defining them as static or global. For example, a definition such as struct large array1[80]; can be defined using a pointer and the malloc function, as illustrated in Listing 5.6. Listing 5.6 Allocating Large Arrays from the Heap struct large *array1; array1 = (struct large *)malloc(80*sizeof(struct large)); Static Data Allocation When you compile your application without cross-file optimization, the allocations for each file are assigned to different sections of data memory. At link time these are dispatched to different addresses. When compiling with cross-file optimization, the compiler uses the same data section for all allocations. If you want to override this and to instruct the compiler to use non-contiguous data blocks, you can edit the machine configuration file to define the exact memory map of the system that you want to use. Configuring the Memory Map The default values in the SC100 memory map are easily configurable, by modifying the linker command file. When making such changes, it is important that you ensure that the code size and data size values that you specify do not overlap. The stack and the heap must be always be located together in one contiguous area of memory. The compiler makes no assumptions about the layout of the other sections of memory, which can be split and distributed over non-contiguous parts of memory, as required. NOTE If you choose not to modify the default linker command file, but rather save the changes in a new linker command file instead, use the -mem option to pass the new command file to the linker. If you use the -Xlnk option to do this, both the new linker command file and the default linker command file will be passed to the linker, resulting in errors. The example below assumes that you have a system with non-contiguous memory, and would like to configure the memory as follows: • All code placed in external memory (addresses 0x10000000 through 0x10100000) • All data placed in internal memory 122 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 123 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Layout and Configuration • Some local memory reserved for the most frequently used functions and overlays (addresses 0x10000 through 0x20000) • All data placed in the lower 64K addresses, in order to be able to use the small memory model compilation mode Table 5.5 shows the memory map that meets the preceding list of requirements: Table 5.5 Modified Memory Map Configuration From To Contents 0 0x1ff Interrupt vectors 0x200 0xfffd Global and static variables 0x10000 0x1ffff Local code 0x20000 0x7fff0 Stack and heap 0x80000 0xfffff ROM 0x10000000 0x100fffff External code Listing 5.7 shows the definitions in the crtscsmm.cmd file that specify this memory map configuration: Listing 5.7 Modified Memory Configuration in the Linker Command File .provide _DataSize, .provide _CodeStart, 0x10000 0x10000000 .provide _StackStart, 0x20000 .provide _TopOfStack, 0x7fff0 .provide _ROMStart, 0x80000 ; ; ; ; ; ; ; ; ; Sets the data size. Sets the loader code start address. Sets the stack start address. The stac grows upward. The heap start address; the heap grows downward. Sets the ROM start address. Machine Configuration File The machine configuration file contains: • Information about data types and alignment requirements, used by the compiler for reference. This data must not be changed. • Memory structure information, used by the compiler to allocate variables in the data sections of memory. This information can be modified if required. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 123 Freescale Semiconductor, Inc. MWEntComp.book Page 124 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Layout and Configuration By default, the compiler uses the file proc.config, located in the install-dir/ etc directory. A different machine configuration file can be specified using the -mc option in the shell command line. The SC100 memory structure consists of physical and logical memory maps, as follows: • Physical memory is divided into several memory spaces. Each memory space is a physical entity consisting of a data bus and an address bus. A physical memory space is defined in terms of its size in words and the width of its address bus, and comprises blocks of words with contiguous addresses, described as physical memory areas. • Logical memory areas are defined as blocks of memory words with contiguous addresses. These words are used by the compiler as if they were in physical memory areas. The addresses of the logical areas are mapped as offsets to physical memory addresses at link time. This dual memory map structure provides a high degree of flexibility during the loading of application code. You define each memory space individually in the machine configuration file, by specifying a space identifier and a description: • Memory space type: program or data. • Word size, in bytes. • Area list, defining one or more logical areas. • The addresses in the logical areas, as positive integers, used as offsets to physical memory areas. • Physical area type: single-port RAM (ramsp), dual-port RAM (ramdp) or ROM (rom). • Attached spaces (optional). This is used for dual-port RAM only, when ramdp is the defined area type, to specify the two memory spaces. It is important that the code ensures address consistency between the corresponding spaces. Listing 5.8 shows the syntax for defining a memory space. Listing 5.8 Memory Space Definition Syntax space definition: define space <space identifier>: space_type; word_size; area_list; end define ; space_type: program | data ; 124 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 125 Monday, September 27, 2004 2:17 PM Runtime Environment Memory Layout and Configuration word_size: word : byte_number ; area_list: area | area_list area ; area: address_value .. address_value : area_type opt_attached_spaces ; ; area_type: ramsp | ramdp | rom ; opt_attached_spaces: [ space_number , space_number ] | ; The code of Listing 5.9 defines a one-word data space, providing one logical area that can be used for the allocation of variables. Listing 5.9 Defining a Data Memory Space define space data_0 : data; word : 2; 0x0000 .. 0xfffff : ramsp; end define Listing 5.10 shows the definition of a two-word program space in ROM. Listing 5.10 Defining a Program Memory Space define space pgm : program; word : 4; 0x0000 .. 0x3fff : rom; end define At link time, these areas are mapped to the relevant physical memory space, and the actual addresses are calculated as offsets to the physical space starting address. A data space can be divided into multiple logical areas, as shown in Listing 5.11. When the compiler executes with cross-file optimization, it divides memory into these logical areas, and allocates variables accordingly. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 125 Freescale Semiconductor, Inc. MWEntComp.book Page 126 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration Listing 5.11 Defining Multiple Memory Spaces define space data_1 : data; word : 2; 0x0000 .. 0x3fff : 0x0800 .. 0xffff : 0x10000 .. 0x13fff 0x40000 .. 0x47fff end define NOTE ramsp; ramdp [data_0,data_1]; : ramsp; : ramsp; If you define new memory spaces in the machine configuration file, it is important that you also add these space definitions in the linker command file, to enable the linker to locate them at link time. Controlling Configuration Application configuration files give you extensive control of compiler options and settings, without the need for pragmas in source files. Traditionally, application configuration files let you define bindings, overlays, and calling conventions. Now, in addition, an application configuration file lets you define views and components. To tell the compiler to use an application configuration file, include the -ma option in the command line. The syntax is: scc ... -ma filename.appli where: -ma The application configuration file command-line option. filename The name of the application configuration file: any name you care to assign. .appli The mandatory extension for the name of all application configuration files. Views A view is a set of configuration definitions and settings appropriate for compilation. An application configuration file can contain multiple views for the same application. At compile time, you specify the view that the compiler should use. This means that you can 126 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 127 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration switch between option and configuration settings without making any changes to your source files. To specify the view, you either: • Add the line use <view_name> to the application configuration file, or • Pass the view name to the compiler as a command-line argument: scc ... -ma filename.appli ... -view <view_name> Listing 5.12 shows the syntax for defining a view: Listing 5.12 View Definition Syntax view <view_name>: <view_body>: <section_definitions> <section_settings> <variable_settings> <control_option_settings> <calling_convention_setting> <module_list>: module <module_name> [ <variable settings> <control_option_settings> <calling_convention_setting> <function_list>: function <function_name> [ <control_option_settings> <calling_convention_setting> ] ] end view Note these points: • A view name is any name you care to assign. • A view body consists of section definitions, section settings, variable settings, control options settings, a calling convention setting, and a module list. These subsections explain several of these items: – Section Definition – Section Settings – Variable Settings – Control Option Settings Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 127 Freescale Semiconductor, Inc. MWEntComp.book Page 128 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration – Calling Convention Setting • A module consists of a specified file and a function list. It can contain its own, local variable settings, control option settings, and calling convention setting. If it does not, it inherits the corresponding settings from the parent view body. • A module name is the name of the module file, without its extension. For example, to specify file alpha.c, use the expression module alpha. • A function is a specified C function. It can contain its own, local control options settings or calling convention setting. If it does not, it inherits the corresponding settings from the parent module. • A function name is the name of a C function, with an underscore (_) prefix. View definition must follow the syntax hierarchy, although partial definition is possible. Section Definition A section definition binds logical names to the physical segments that the linker uses. This makes it easier to redefine mapping. A section definition applies to the whole view. Listing 5.13 shows the definition syntax, Listing 5.14 shows an example: Listing 5.13 Section Definition Syntax <section_definitions>: section <section_list> end section <section>: <section_type> = [ <binding_list> ] <section_type>: data program bss rom init <binding>: <logical_name> : <physical_name> <optional_qualifier> <qualifier>:[ overlay Listing 5.14 Example Section Definition ... section 128 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 129 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration data = [data1: “My_Data_Seg1”, data2: “My_Data_Seg2” overlay, data3: “My_Data_Seg3” overlay] program = [Pgm1: My_Pgm_Seg1”] end section ... Section Settings Once you define a section, you can specify a setting for each context. If you do not specify any settings, the section inherits settings of its parent. Listing 5.15 shows the syntax, Listing 5.16 shows an example: Listing 5.15 Section Setting Syntax <section_settings>: <section_type> = <logical_name> <section_type>: data program bss rom init Listing 5.16 Section Settings Example ... module “My_Module” [ ... data = data2 /*Use data2 as data space for whole module*/ program = Pgm1 /*Use Pgm1 as program space for whole module*/ ... function _alpha [ ... data = data3 /*Use data3 as data space for function _alpha,*/ /*overriding data = data2 */ ... ] ] ... Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 129 Freescale Semiconductor, Inc. MWEntComp.book Page 130 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration Variable Settings The variable settings position of a view-body definition lets you: • Force the alignment for a user variable, • Inform the compiler about point alignment, or • Override the data segment for the scope of a variable. Variable settings can be at either the view or the module level. You can use the same variable-alignment syntax to specify function alignment. Listing 5.17 shows the syntax, Listing 5.18 shows an example: Listing 5.17 Variable Settings Syntax <variable_settings>: <alignment_list> <placement_list> <alignment>: align <variable_name> <value> | align * <variable_name> <value> <placement>: place ( <variable_name_list> ) in <logical_name> Listing 5.18 Variable Settings Example ... view My_View” section data = [data1: “My_Data_Seg1”, data2: “My_Data_Seg2” overlay, data3: “My_Data_Seg3” overlay] program = [Pgm1: My_Pgm_Seg1”] end section place ( _A, _B, _C) in data2 /*Allocate globals _A, _B, and*/ /*_C to segment data2*/ place ( _X, _Y) in data3 /*Allocate globals _X and _Y*/ /*to segment data3*/ module “file1” [ align _alpha 1024 data = data2 opt_level = speed program = Pgm1 place (_AB, _CD) in data1 /*Allocate global/static _AB,*/ /*_CD to segment data1*/ function _alpha [ 130 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 131 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration align _X 2 /*Force local _X to 2-byte*/ /*boundary*/ /*Tell compiler that _Y points*/ /*to a 4-byte-aligned location*/ align *_Y 4 } ] end view ... Control Option Settings The control options settings position of a view-body definition lets you redefine all the compiler flags, whether boolean or integral values. The effect is the scope: exiting the scope restores the previous values. There are option-setting counterparts to most pragmas. Additionally, control options settings make it possible to set or reset many compiler internal variables. This can be helpful for a context-selective problem workaround. Listing 5.19 shows the syntax, Listing 5.20 shows an example: Listing 5.19 Control Option Setting Syntax <control_option_settings>: <option_list> <option>: <name> = <value> | <name> = true | <name> = false | <name> = <string> | <name>: opt_level inline unrolling_factor ... Listing 5.20 Control Option Settings Example ... module “file1” [ opt_level = speed /*Optimize for speed*/ Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 131 Freescale Semiconductor, Inc. MWEntComp.book Page 132 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration function _alpha [ inline = true safe_mod = true unrolling_factor = 2 Max_HW_Lev = 1 scalarizatioon = false self_test = true ] function _beta [ opt_level = O0 ] /*Inline this function*/ /*For this function, assume modulus*/ /*is equivalent to conditional*/ /*subtract*/ /*Set unrolling factor to 2*/ /*Allow only 1 hardware loop*/ /*Disable scalarization*/ /*Enable auto test mode*/ /*Disable optimizations*/ ] ... Table 5.6 lists public Icode options, which you can use in your application configuration files. (You also can set these options in Icode option files.) Table 5.6 Public Icode Internal Options Option If True/ False Effect CC_40Bit_In_Reg TRUE Uses registers to pass 40-bit data during calls. Const_To_Rom FALSE Does not place constants in ROM. Def_CC_Max_Struct_Size — Specifies maximum structure size that the default calling convention can pass in a register. Takes an integer value (instead of TRUE or FALSE). This value should be 4 to comply with the StarCore ABI, but this configuration is not efficient. Def_CC_Min_Align — Specifies minimum alignment that the default calling convention can use to pass arguments on the stack. Takes an integer value (instead of TRUE or FALSE). This value should be 4 to comply with the StarCore ABI, but this configuration is not efficient. limit_pushpop_O0 TRUE Limits push/pop and spill sequences for optimization level 0. If that level is not appropriate, could lead to debugger problems. loop_on_unsigned_int TRUE Hardware loops can result from an unsigned integer that controls a loop. String_To_Rom TRUE Places string constants in ROM. 132 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 133 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration Table 5.6 Public Icode Internal Options (continued) Option If True/ False Effect Switch_To_Rom TRUE Places switch tables in ROM. Uninit_And_Zeroed_Globals _In_Bss TRUE Places uninitialized and zeroed globals in BSS. Uninit_Globals_In_Bss TRUE Places uninitialized globals in BSS. Use_Const FALSE Does not handle const qualifiers in data dependency analysis. Use_Restrict FALSE Does not handle restrict qualifiers in data dependency analysis. Calling Convention Setting Calling convention setting is specifying a calling convention. the syntax is: <Calling_convention_setting>: call_convention = <Call_Convention_Name> Listing 5.21 shows an example: Listing 5.21 Calling Convention Setting Example ... view My_View call_convention = “Call_Conv_1” /*Use Call_Conv_1 everywhere*/ module “file1” [ function _alpha [ call_convention = “Call_Conv_2” /*In function alpha,*/ ] ] end view ... NOTE For information about creating a new calling convention in your application configuration file, see the section Creating a Calling Convention. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 133 Freescale Semiconductor, Inc. MWEntComp.book Page 134 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration Components For global optimization, an application configuration file can contain a list of component descriptions. Each component includes a list of entry points and a list of variables that must be visible outside the component. Listing 5.22 shows the syntax. Listing 5.22 Component Specification Syntax component <component_name> entries = [ <function_list> ] symbols = [ <variable_list> ] end component The example of Listing 5.23 indicates that C functions my_main, alpha, and beta are entry points for component Comp. The example also specifies that the definition of variable one_extern is visible outside the component. Listing 5.23 Component Specification Example component “Comp” entries = [_my_main , _alpha , _beta] symbols = [_one_extern] end component If you declare multiple components in an application configuration file, you can include a use component clause to tell the compiler which to use. For example, Listing 5.24 defines three components, then tells the compiler to use Comp2. Listing 5.24 Three Component Example configuration component “Comp” entries = [_my_main, _alpha, _beta] symbols = [_one_extern] end component component “Comp1” entries = [_alpha, my_main , _beta] symbols = [_one_extern] end component component “Comp2” entries = [_my_main1, _gamma, _beta] symbols = [_one_extern2] end component use component “Comp2”| 134 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 135 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration end configuration NOTE A use component clause in an application configuration file overrides any command-line option to use a particular component. Command-Line Specification Instead of including a use component clause in an application configuration file, you can have the scc command line tell the compiler which component to use. The syntax is: scc ... -complib <component_name> Note these constraints: • The declaration of the specified component must be in the application configuration file. Otherwise, the compiler issues an error message. • If you are not in global optimization mode, the compiler ignores this option. • A use component clause in the application configuration file overrides this option. An example command line is: scc -Og -o my_lib.elb -complib Comp2 -ma conf.appli <options> file_list This command line tells the compiler to use component Comp2 as it creates the selfcontained library my_lib.elf. This library will contain the result of global optimization applied to file_list. Vocorder Application Example Suppose that you want an application for vocorders voc1, voc2, and voc3, and that: • Each vocorder has entry-point functions for encoding, decoding, initializing encoding, and initializing decoding. • The control module, my_application.c, includes a protocol that dynamically selects the appropriate vocorder. • Global optimization is appropriate for each vocorder. , which will contain the Listing 5.25 Vocorder Component Declaration configuration component “Voc1” Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 135 Freescale Semiconductor, Inc. MWEntComp.book Page 136 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration entries = [_Voc1_Encode, _Voc1_Decode, Voc1_Encode_Init, _Voc1 _Decode_Init] end component component “Voc2” entries = [_Voc2_Encode, _Voc2_Decode, Voc2_Encode_Init, _Voc2 _Decode_Init] end component component “Voc3” entries = [_Voc3_Encode, _Voc3_Decode, Voc3_Encode_Init, _Voc3 _Decode_Init] end component end conofiguration Listing 5.26, Listing 5.27, and Listing 5.28 show the commands to create each library, using global optimization. Listing 5.26 Voc1 Library Creation Commands scc -ma my_appli.appli -complib Voc1 -o voc1.elb -Og -Og all C files for voc1 other options /*Use application file my_appli.appli*/ /*Select component Voc1*/ /*Generated library is voc1.elb*/ /*Specify global optimization*/ /*Pass list of C files that define voc1*/ Listing 5.27 Voc2 Library Creation Commands scc -ma my_appli.appli -complib Voc2 -o voc2.elb -Og -Og all C files for voc2 other options /*Use application file my_appli.appli*/ /*Select component Voc2*/ /*Generated library is voc2.elb*/ /*Specify global optimization*/ /*Pass list of C files that define voc2*/ Listing 5.28 Voc3 Library Creation Commands scc -ma my_appli.appli -complib Voc3 -o voc3.elb -Og -Og all C files for voc3 other options /*Use application file my_appli.appli*/ /*Select component Voc3*/ /*Generated library is voc3.elb*/ /*Specify global optimization*/ /*Pass list of C files that define voc3*/ shows the commands for separate compilation of the three libraries with the main file: 136 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 137 Monday, September 27, 2004 2:17 PM Runtime Environment Controlling Configuration Listing 5.29 Separate Compilation Commands scc -o my_appli.eld my_application.c voc1.elb voc2.elb voc3.elb other options /*Executable file is my_appli.eld*/ /*Name of main file*/ /*voc1 library*/ /*voc2 library*/ /*voc3 library*/ Affect on S1 Files Icode can process global and static variables placed in different memory segments. For each segment, the address allocation starting from zero means that different global/static variables can have the same address as soon as they are in segments. NOTE Icode does not process local variables. The segment list specifies the segment names available for use in an S1-format file. This segment list must be in the file, immediately after the calling-convention section. The syntax is: <segment_list> :== <one_segment>* <one_segment> :== .segment <segment_index> “ <segment_name> “ | .segment <segment_index> “ <segment_name> “ , “overlay” Another way to specify a segment is to include it at the end of the declaration of a global or static variable. A segment you specify in this way overrides any default segment specification. The syntax is: <var_def_syntax> :== ... <memory_space> : <memory_address> | ... <memory_space> : <memory_address> : <segment_index> The segment_index value is a reference from the segment list. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 137 Freescale Semiconductor, Inc. MWEntComp.book Page 138 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions Calling Conventions The compiler supports a stack-based calling convention. Additional calling conventions are also supported. Calling conventions can be mixed within the same application. Specific calling conventions can be enforced using pragmas. When compiling in separate compilation mode, non-static functions use the stack-based calling convention. Stack Pointer The SP register serves as the stack pointer, which points to the first available location. The stack direction is toward higher addresses, meaning that a push is implemented as (sp)+. The stack pointer must always be 8-byte aligned. Stack-Based Calling Convention The following calling conventions are supported: • The first (left-most) function parameter is passed in d0 if it is a numeric scalar or in r0 if it is an address parameter, regardless of its size. The second function parameter is passed in d1 if it is a numeric scalar, or in r1 if it is an address parameter, regardless of its size. The remaining parameters are pushed on the stack. Long parameters are pushed on the stack using little-endian mode, with the least significant bits in the lower addresses. • Structures and union objects that can fit in a register are treated as numeric parameters, and are therefore candidates to be passed in a register. • Numeric return values are returned in d0. Numeric address return values are returned in r0. Functions returning large structures, meaning structures that do not fit in a single register, receive and return the returned structure address in r2. The space for the returned object is allocated by the caller. • Functions with a variable number of parameters allocate all parameters on the stack. • Parameters are aligned in memory according to the base parameter type, with the exception of characters and unsigned characters that have a 32-bit alignment. The following registers are saved by the caller: d0-d5, r0-r5, n0-n3. The following registers are saved by the callee, if actually used: d6-d7, r6-r7. The compiler assumes that the current settings of the following operating control bits are correct: • Saturation mode • Round mode 138 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 139 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions • Scale bits The application is responsible for setting these mode bits correctly. Listing 5.30 shows two function calls and the parameters that are allocated for each call. Listing 5.30 Function Call and Allocation of Parameters # Function call: alpha(int a1, struct fourbytes a2, struct eightbytes a3, int *a4) # # # # # Parameters for the preceding function call: a1 - in d0 a2 - in d1 a3 - in stack a4 - in stack # Function call: beta(long *b1, int b2, int b3[]) # # # # Parameters for the preceding function call: b1 - in r0 b2 - in d1 b3 - in stack The stack-based calling convention must be used when calling functions that are required to maintain a calling stack. The compiler is able to use optimized calling sequences for functions that are not exposed to external calls. Local and formal variables are allocated on the stack and in registers. Table 5.7 summarizes register usage in the stack-based calling convention. Table 5.7 Register usage in the stack-based calling convention Register Used as Caller Saved d0 First numeric parameter + Callee Saved Return numeric value d1 Second numeric parameter d2-d5 + + d6-d7 + d8-d15 + Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 139 Freescale Semiconductor, Inc. MWEntComp.book Page 140 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions Table 5.7 Register usage in the stack-based calling convention (continued) Register Used as Caller Saved r0 First address parameter + Callee Saved Return address value r1 Second address parameter + r2 Big object return address + r3-r5 + r6 Optional argument pointer + r7 Optional frame pointer + n0-n3, m0-m3 + Stack Frame Layout The stack pointer points to the top (high address) of the stack frame. Space at higher addresses than the stack pointer is considered invalid and may actually be unaddressable. The stack pointer value must always be a multiple of eight. Figure 5.2 shows typical stack frames for a function, indicating the relative position of local variables, parameters and return addresses. 140 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 141 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions Figure 5.2 Stack Frame Layout High addresses Stack Pointer Outgoing parameters overflow Local variables Saved registers Return address Incoming parameters Low addresses The caller must reserve stack space for return variables that do not fit in registers. This return buffer area is typically located with the local variables. This space is typically allocated only for functions that make calls that return structures. Beyond these requirements, a function is free to manage its stack frame as necessary. The outgoing parameter overflow block is located at the top (higher addresses) of the frame. Any incoming argument spill generated for varargs and stdargs processing must be at the bottom (low addresses) of the frame. The caller puts argument variables that do not fit in registers into the outgoing parameter overflow area. If all arguments fit in registers, this area is not required. A caller has the option to allocate argument overflow space sufficient for the worst case call, use portions of this space as necessary, and/or leave the stack pointer unchanged between calls. Local variables that do not fit into the local registers are allocated space in the local variables area of the stack. If there are no such variables, this area is not required. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 141 Freescale Semiconductor, Inc. MWEntComp.book Page 142 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions Creating a Calling Convention The compiler’s default calling convention is the one that the ABI document defines, but this is not the best choice for all situations. Sometimes, for example, the compiler must call an assembly function. If only one module calls this assembly function, it is possible to use the asm prefix on a function in combination with the asm arg descriptor mechanism. The body of this function contains the assembly program. However, the asm prefix is exclusive with extern, so you cannot export this function. To eliminate this limitation, you can: 1. Define a specific calling convention in the application configuration file. 2. Use a pragma to tell the compiler to use this specific calling convention for a given function. You must describe user-defined calling conventions in the application configuration file. (You pass this file to the compiler using the -ma file_name option.) Listing 5.31 shows the calling convention syntax. You can create several calling conventions as long as they have different names. Listing 5.31 Calling Convention Syntax <A call convention> ::= call_convention <Name> ( arg [ <Arg descriptor> ] ; return <One Reg> ; saved_reg [ <Register list> ] ; <save_protocol> ) <Arg descriptor> ::= <One Arg> | <Arg descriptor> , <One Arg> <One Arg> ::= <arg number> : <One Reg> <arg number> ::= <A positive integer> <One Reg> :== <One Phi Reg> | <One Phi Reg> fract /* This register is treated as a fractional that is, left aligned. */ | 142 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 143 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions ( * <One Phi Reg> , <One Phi Reg> ) /* * This means that argument type is pointer */ <Register list> ::= <One Reg> | <Register list> , <One Reg> <One Phi Reg> ::= $d0 | $d1 | $d2 | $d3 | $d4 | $d5 | $d6 | $d7 | $d8 | $d9 | $d10 | $d11 | $d12 | $d13 | $d14 | $d15 | $r0 | $r1 | $r2 | $r3 | $r4 | $r5 | $r6 | $r7 | $r8 | $r9 | $r10 | $r11 | $r12 | $r13 | $r14 | $r15 | $m0 | $m1 | $m2 | $m3 | $b0 | $n1 | $n2 | $n3 <save_protocol> :== save = [ ] ; /* protocol is push and pop */ | save = [ <save_rt_name> , <restore_rt_name> , <frame_effect> ] ; /* Protocol is save and restore through user defined runtime. The restore run time is not expected to do the return of the called function. frame_effect is the number of bytes consumed on the stack */ | save = [ return , <save_rt_name> , <restore_rt_name> , <frame_effect> ] ; /* Protocol is save and restore through user defined runtime. The restore run time also takes care of the return of the called function. In this case, the compiler removes the return in the caller function. frame_effect is the number of bytes consumed on the stack */ | /* Default is push and pop */ ; Syntax Sections The next subsections correspond to the sections of the calling convention syntax: argument descriptor, return, saved register, and deleted register. Argument Descriptor Section The general format for passing arguments is: <One Arg> ::= <arg number> : <One Reg> ; where Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 143 Freescale Semiconductor, Inc. MWEntComp.book Page 144 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions <arg_number> The position in the argument list of the C function to which the calling convention applies. Argument numbers run from first to last, not necessarily by increments of one. If the function has more arguments than the calling convention defines, the system passes unspecified arguments on the stack. The system also uses the stack to pass any function arguments not defined in the calling convention. <One Reg> Name of a register to be used to pass the parameter. The compiler automatically translates the code structure of Listing 5.32 to the code of Listing 5.33. For this special case, the <arg number> value is 0. Listing 5.32 Function Returning a Structure typedef struct { int a; int b; } My_Type; My_Type A_Function() { } Listing 5.33 Translated Code for Function Returning a Structure void A_Function(My_Type *Compiler_Internal_Name) Return Section The return descriptor specifies the register in which the system returns the return value. The format is return <One Reg> ; A function always must pass the return value in a register, so this section of the calling convention is mandatory. (Remember the special case of functions returning structures.) Saved Register Section This section lists the registers used inside the function, registers that the function must save. The format is: saved_reg [ <Register list> ] ; 144 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 145 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions Saving these registers means that the calling function safely can keep a value in one of these registers during a call to the function that obeys this calling convention. Deleted Register Section This section lists the registers that the function deletes or may delete. The format is: deleted_reg [ <RegisterList> ] ; The calling function cannot keep a value in any of these registers during a call to the function that obeys this calling convention. General Remarks The calling convention syntax does not include loop-related registers, as saves and restores of such registers are expensive for StarCore processors. Accordingly, the compiler automatically disables hardware loop and modulo transformation in loops that contain function calls. A guiding assumption is that the system always leaves functions in a consistent state: no active hardware loops, and all pointers set to linear mode. The compiler enforces this behavior for C routines, but you must enforce this behavior for any called assembly routines. Specifying the Calling Convention The two general patterns for specifying a calling convention are for a function and for an entire file. Function Calling Convention To specify a calling convention for a function, use pragma call_conv. Its syntax is: #pragma call_conv <calling convention> <function> where calling convention Name of a calling convention in the application file. function Name of a function already declared. is an example: Listing 5.34 Pragma call_conv Example extern int alpha(int a, int b; ... Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 145 Freescale Semiconductor, Inc. MWEntComp.book Page 146 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions #pragma call_conv My_Call_Conv alpha int alpha_beta(int a); { #pragma call_conv My_Call_Conv alpha_beta ... } File Calling Convention To specify a calling convention for an entire file, use pragma default_call_conv. Its syntax is: #pragma default_call_conv <calling convention> where calling convention Name of a calling convention in the application file. The system applies the specified calling convention to all functions defined in the current module. If another module uses a function defined in the current module, you must attach pragma call_conv to the extern declaration of the other module. All extern calls in the current module use either the ABI default calling convention or the convention that a pragma call_conv specifies. Application File Specification To modify the default calling convention globally, include this syntax in your application file: default_call_convention = “my_default_call” This specifies that all functions without attached calling conventions use my_default_call. To use libraries compiled with the standard calling convention, use the call_convention directive and the keyword STD_CALL, as in this example: call_convention (_puts, _alpha2, _alpha3) = STD_CALL This specifies that functions _puts, _alpha2, and _alpha3 follow the standard calling convention. is a full example of specifying a calling convention. Listing 5.35 Specifying a Calling Convention configuration 146 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 147 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions call_convention my_default_call ( arg [ 1 : $d1 ]; return (.p: $r2, (.c,.uc,.si,.usi,.i,.ui,.li,.uli,.f,.fr,.lfr, .m): $d2 ) saved_reg [ ]; deleted_reg [ ]; save = [ ]; ) view my_view default_call_convention = “my_default_call” call_convention ( _puts, _alpha2, _alpha3) = STD_CALL end view use view my_view end configuration Note these limitations: • default_call_convention makes sense at the application level. Setting it at the module or function level has the same effect as setting it at the application level. • To restrict a function calling convention, use call_convention (_printf = STD_CALL at the function or module level. This makes sense for static functions. However, it probably is not a good idea for inlined functions, which may have restrictions enabled or disabled. User-Defined Calling Convention Examples This section shows some user-defined calling convention examples. Example 1: File call.appli Listing 5.36 shows an example application configuration file named call.appli that contains two user-defined calling conventions. According to Call_Conv_1, • The system passes any argument-1 value in register $d0 • The system passes any argument-2 value in register $d7 • The system passes any argument -3 value in register $r2 • The system passes values of any other arguments on the stack • The system puts any return value in register $d10 • The called function pushes/pops the saved_reg list, or leaves it unmodified • The deleted_reg list identifies registers whose contents are not valid after the function call Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 147 Freescale Semiconductor, Inc. MWEntComp.book Page 148 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions Listing 5.36 Example 1: File call.appli configuration call_convention Call_Conv_1 ( arg [1 : $d0, 2 : $d7, 3 : $r2]; return $d10; saved_reg [$d1, $d2, $r6, $r7]; deleted_reg [$d0, $d3, $d4, $d5, $d6, $d7, $d8, $d9, $d10, $d11, $d12, $d13, $d14, $d15, $r0, $r1, $r2, $r3, $r4, $r5, $r8, $r9, $r10, $r11, $r12, $r13, $r14, $r15]; save = [ ]; ) call_convention Call_Conv_2 ( arg [1 : $d0, 2 : $d1, 3 : $d3, 4: $d4, 5 : $d5, 6 : $d6, 7 : $d7, 8 : $d8]; return $d0; saved_reg [$d2, $d3, $d4, $d5, $d6, $d7, $d8, $d9, $d10, $d11]; deleted_reg [$d0, $d1, $d12, $d13, $d14, $d15, $r0, $r1, $r2, $r3, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11, $r12, $r13, $r14, $r15]; save = [ ]; ) end configuration Listing 5.37 shows call.c, which shows the following setup for calling conventions: • The compiler calls the fct function using Call_Conv_1. • The compiler calls the fct1 function using Call_Conv_2. • The compiler calls the main function using the ABI default calling convention. Listing 5.37 Example 1: Code that Uses User-Defined Calling Conventions #include <stdio.h> volatile int val = 10; int fct(int a, int b, int c, int d, int e, int f, int g, int h) { #pragma noinline #pragma call_conv fct Call_Conv_1 return (a + b + c + d + e + f + g + h); } int fct1(int a, int b, int c, int d,int e,int f,int g,int h) { #pragma noinline #pragma call_conv fct1 Call_Conv_2 int i; 148 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 149 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions int acc = 0; for (i =0; i<val; i++) { acc += fct(a, b, c, d,e,f,g,h); a++;b++;c++;d++;e++;f++;g++;h++; } return (acc + a + b + c + d + e + f + g + h); } void main() { int i; int a, b, c, d,e,f,g,h; int Z = 0; a=b=c=d=e=f=g=h=0; for (i =0; i<val; i++) { Z += fct1(a, b, c, d,e,f,g,h); a++;b++;c++;d++;e++;f++;g++;h++; } Z = Z + a + b + c + d + e + f + g + h; printf("Z = %d\n", Z); } To compile the preceding test case, type the command: scc -ma call.appli call.c Example 2 Listing 5.38 is another calling convention example. Note the line save = [ my_save, my_restore, 48], which specifies that: • Run-time my_save does the ctxt save • Run-time my-restore does the ctxt restore, and also takes care of the return of the calling function through stack demangling • 48 bytes are allocated on the stack, to make space for six pairs of registers Listing 5.38 Example 2 File Contents configuration call_convention Gcc_plus ( arg [1 : (* $r0, $d0), 2 : (* $r1, $d10, 3 : (* $r3, $d3), 4 : (* $r4, $d4), 5 : ((* $r5, $d5), 6: (* $r6, $d6), 7 : (* $r7, $d7)]; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 149 Freescale Semiconductor, Inc. MWEntComp.book Page 150 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions return (* $r0, $d0); saved_reg [$d3, $d3, $d4, $d5, $d6, $d7, $r2, $r3, $r4, $r5, $r6, $r7]; deleted_reg [$d0, $d1, $d8, $d9, $d10, $d11, $d12, $d13, $d14, $d15, $r0, $r1, $r8, $r9, $r10, $r11, $r12, $r13, $r14, $r15]; save = [ my_save, my_restore, 48]; ) end configuration Example3: asm Functions You also can use user-defined calling conventions with assembly language functions. Instead of the usual approach of defining everything has to be defined after the asm_header keyword, you can use a single directive: .call_conv = <call_conv_name> This single-directive approach: • Leads to a more compact description. • Opens the possibility of calling a C asm function from outside the current module without having to use the ABI rules for calling conventions. You place a pragma call_conv on the C assembly function when declaring it as an extern in the module that uses it. Listing 5.39 shows the corresponding code for file call.appli. Listing 5.39 Example 3: User-Defined Calling Conventions for Assembly Functions (Call.appli) configuration call_convention Call_Conv_1 ( arg [1 : (* $d14, $d14), 2 : (* $r9, $r9)]; return (* $d0, $d0); deleted_reg [$d0, $r9, $d14]; save = [ ]; ) end configuration Listing 5.40 shows the use of the .call_conv directive with user-defined calling conventions and assembly functions. 150 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 151 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions Listing 5.40 Example 2: Using .Call_conv Directive with Assembly Functions (File1.c) asm int My_Asm_Function(int a, int *b) { asm_header .call_conv = "Call_Conv_1"; /* call_conv replaces the commented section; in this case we do not follow the ABI rules for register passing .arg _a in $d14; _b in $r9; return in $d0; .reg $d0, $r9, $d14; */ asm_body move.l d14,d0 move.l (r9),d14 add d14,d0,d0 asm_end } Listing 5.41 shows the use of the call_conv pragma with user-defined calling conventions and assembly functions. Listing 5.41 Example 2: Using Call_conv Pragma with Assembly Functions (File2.c) #include <stdio.h> extern int My_Asm_Function(int a, int *b); #pragma call_conv My_Asm_Function Call_Conv_1 int Buff[10] = {25}; int Ret; void main() { Ret = My_Asm_Function(10, Buff); /* 10 to be passed in d14, Buff in r9, and Ret in d0 */ printf("Ret = %d\n", Ret); } To compile and run the preceding example, type these commands: scc -ma call.appli File1.c File2.c runsc100 a.eld Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 151 Freescale Semiconductor, Inc. MWEntComp.book Page 152 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions The correct result of the example is 35. Calling Convention Syntax Extensions Syntax extensions are necessary for the compiler’s support of long long and double data types. As StarCore processors are 32-bit devices, they must use register pairs to support 64-bit data types. The extensions let user-defined calling conventions: • Define ways to pass arguments and return values according to the type of data • Handle long long and double data types, by specifying register pairs in the syntax • Defining the maximum size of structures that registers can pass The syntax extensions impact only the argument descriptor and return sections. The extensions are backwards compatible, so that you can use old application files with the most recent version of the tools. Expanded Syntax For early compiler versions, the description of an argument was merely: <One Arg> ::= <arg number> : <One Reg>; But now that the compiler supports long long and double data types, an argument description must include an argument index, a set of types, and a register or register pair. Listing 5.42 shows this expanded description. Listing 5.42 Argument Definition Expanded Syntax <One Arg> ::= <arg number> : ( <Spec_List> ) ; <arg number> ::= <A positive integer> <Spec_List> ::= <One Spec> | <Spec List> , <One Spec> <One Spec> ::= ( <Type List> ) : <Reg Spec> <One Type> ::= .c | .uc | .si | .usi | .i | .ui | .li | .uli | .f | .fr | .lfr | .p | .d | .lli | .ulli | .m <Tpe List> ::= 152 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 153 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions <Type List> , <One Type> <Reg Spec> ::= <One Phi Reg> | <One Phi Reg> fract | <One Phi Reg> <Max Struct Spec> | <One Phi Reg> fract <Max Struct Sec> <One Phi Reg> ::= $d0 | $d1 | $d2 | $d3 | $d4 | $d5 | $d6 | $d7 | $d8 | $d9 | $d10 | $d11 | $d12 | $d13 | $d14 | $d15 | $r0 | $r1 | $r2 | $r3 | $r4 | $r5 | $r6 | $r7 | $r8 | $r9 | $r10 | $r11 | $r12 | $r13 | $r14 | $r15 | $dd0 | $dd2 | $dd4 | $dd6 | $dd8 | $dd10 | $dd12 | $dd14 | $m0 | $m1 | $m2 | $m3 | $b0 | $n1 | $n2 | $n3 <Max Struct Spec> :== max_struct = <max size> <max size> ::= <A positive integer> Notice the expansion of <One Phi Reg> to include register pairs. Similar changes apply to the return value. Its former description was: return <One Reg> ; Its new description includes the same <Spec List> of Listing 5.42: return : ( <Spec List> ) : Double Data Example shows the calling convention for long long and double data types. Listing 5.43 Long Long, Double Example configuration call_convention Double_RT ( arg [ 1 : ( .p : $r0, (.c,.uc,.si,.usi,.i,.ui,.li,.uli,.f,.fr,.lfr,.m): $d0, (.lli, .ulli, .d): $dd0 max_struct = 4), 2 : ( .p : $r1, Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 153 Freescale Semiconductor, Inc. MWEntComp.book Page 154 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions (.c,.uc,.si,.usi,.i,.ui,.li,.uli,.f,.fr,.lfr,.m): $d1, (.lli, .ulli, .d): $dd2 max_struct = 4), ]; return ( .p: $r0, (.c,.uc,.si,.usi,.i,.ui,.li,.uli,.f,.fr,.lfr,.m): $d0, (.lli, .ulli, .d): $dd0 max_struct = 4), saved_reg [ $d6, $d7, $r6, $r7]; deleted_reg [ $d0, $d1, $d2, $d3, $d4, $d5, $d8, $d9, $d10, $d11, $d12, $d13, $d14, $d15, $r0, $r1, $r2, $r3, $r4, $r5, $r8, $r9, $r10, $r11, $r12, $r13, $r14, $r15, save = []; ) view Double_RT_View call_convention (__d_add, __d_sub, __d_mul, __d_div, __d_feq, __d_ fle, __d_flt, __d_fne, __d_fge, __d_fgt) = “Double_RT” end view use view Double_RT_View end configuration Notice the arrangements for passing argument 1: • In $r0 if argument 1 is a pointer • In $d0-$d1 if argument 1 is a long long or double • In $d0 if argument 1 is any other type, such as an integral, fraction, of float of four or fewer bytes. The arrangements for passing argument 2 are the same, but involve registers $r1, $d2$d3, and $d1. The system uses the stack to pass any other arguments; this is the default arrangement for arguments not in the calling-convention descriptor list. If you use register pairs to pass long longs and doubles, endianness matters. For example, to pass such an argument in $d0 and $d1, the ABI specifies the equivalent of: 1. Storing in an 8-byte aligned memory area, 2. Loading the low-addressed word into $d1, 3. Loading the high-addressed word into $d1. This means that in big-endian mode, $d0 contains the most significant long word. In little-endian mode, $d0 contains the least significant long word. Calling Convention Rules Remember that the term type has two meanings: 154 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 155 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions • Calling function perspective — the effective type of the parameter, once it has been through promotion or conversion, according to ANSI-C rules. • Called function perspective — the type of the formal parameter as it appears in the declaration. These numbered rules apply to all calling conventions: 1. If the first function parameter is of type integral or float, with 4 or fewer bytes, passing takes place in $d0. If the first parameter is a pointer, passing takes place in $r0. 2. If the second parameter is of type integral or float, with 4 or fewer bytes, passing takes place in $d1. If the second parameter is a pointer, passing takes place in $r1. 3. If the first parameter is of type long long (where implemented), double, or long double, passing takes place in $d0 and $d1. The procedure is equivalent to storing the value in an 8-byte aligned memory area, then loading the low-addressed word into $d1, and finally loading the high-addressed word into $d1. This means that $d0 contains the most significant long word in big-endian mode, and the least significant long word in little-endian mode. 4. For all pass-by-value struct or union parameters, passing takes place on the stack (that is, by value). Any pass-by-address struct or union parameters become pointers, conforming to Rules 1 and 2. 5. Any function that has a variable number of arguments passes the last fixed argument, and all subsequent variable arguments, on the stack. Rules 1 and 2 apply until the nextto-last fixed argument. 6. For all other arguments, passing takes place on the stack. 7. As ISO C requires, unless there is a function prototype (old style call), all argument parameters of integral and floating types undergo integral and float promotion. 8. If a function prototype exists, the compiler casts parameters to the types of the formal arguments. When the system passes these arguments on the stack, they conform to the size and alignment of the formal arguments. 9. Parameter passing on the stack proceeds from higher addresses to lower addresses, in the byte order appropriate for the endian mode. Alignment conforms to the rules for fundamental data types, aggregates, and unions. 10. The system returns values according to their type: a. Integral (other than a long long) — the system sign- or zero-extends the value to 40 bits, then returns it in $r0. b. Float — the system returns it in $d0. c. Long long, double, or long double — the system returns it in $d0 and $d1, following the Rule 3 procedure. d. Address — the system returns it in $r0. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 155 Freescale Semiconductor, Inc. MWEntComp.book Page 156 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions e. Struct or union — the system returns the struct/union address in $r2; the calling function allocates space for the returned object. Interrupt Handlers Functions which require no parameters and return no result can be designated as interrupt handler functions. The process of creating an interrupt handler function includes: • Defining the function as an interrupt handler • Linking the function to the appropriate interrupt vector entry An interrupt handler can be defined in one of two ways: • Using #pragma interrupt in the source code • Defining an interrupt entry point in the application, by editing the schedule section of the application configuration file To create the link between the function and the interrupt vector entry, you can use any one of the following options: • In the code that calls the function, place a call to the handler function in the interrupt vector entry. • Use the signal.h library function to insert a call to the interrupt handler function into the required interrupt vector entry. • If the function is very small, you can embed it in the interrupt vector entry, by modifying the startup code file, crtsc100.asm. The size of each interrupt vector entry is 64 bytes. With this option, there is no need for an explicit call from the vector to the function. Interrupt handler functions always follow the stack-based calling convention. When an interrupt function is called, the interrupt handler saves all registers and all other resources that are modified by the function. Upon returning from the function all registers and hardware loop state saved at entry are restored to their original state. Local variables are saved on the stack. Interrupt handlers that are known to be non-interruptible may also allocate data statically. Return from interrupt is implemented using an RTE instruction. Frame and Argument Pointers The compiler does not use a frame pointer or an argument pointer. If, however, the use of a frame pointer or an argument pointer is required by external code, r7 may be allocated as a frame pointer and r6 as an argument pointer. When these registers are allocated as frame pointer and/or argument pointer, they should be saved and restored as part of the function prolog/epilog code. 156 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 157 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions Also, the compiler may use R6 as frame pointer if the stack frame is too large. Hardware Loops All hardware loop resources are available for use by the compiler. It is assumed that no nesting occurs when entering a function. As a result, a function may use all 4 nesting levels for its own use. An additional side effect of this assumption is that loops that include a function call as part of the loop code cannot be implemented using hardware loops, unless the compiler can infer the nesting level of the called function from static variables known at compilation time. Loops are nested beginning with loop counter 3 at the innermost nesting level. Operating Modes The compiler makes the following assumptions regarding runtime operating modes and the machine state: • All modulo (M) registers (m0-m3) are assumed to contain the value -1 (linear addressing). If the use of an M register is required, the calling function must restore the M register to the value -1 before returning or before calling another function. • The default settings in the startup code, including saturation modes, rounding mode, and scale bits are set by the user. You can control and change these operating modes during execution of the application. Refer to the SC100 architecture documentation for further details. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 157 Freescale Semiconductor, Inc. MWEntComp.book Page 158 Monday, September 27, 2004 2:17 PM Runtime Environment Calling Conventions 158 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 159 Monday, September 27, 2004 2:17 PM 6 Runtime Libraries This chapter explains the C and I/O libraries that the Metrowerks Enterprise C compiler supports. Table 6.1 summarizes the C libraries. The non-ISO C libraries contain the compiler’s built-in intrinsic functions. The header file you use to include such a library depends on whether your code has any conflicts between certain assembly-language operations and intrinsic functions. Table 6.1 Supported Libraries Library Type Header File Description ISO ctype.h Character typing and conversion float.h Floating-point characteristics limits.h Integer characteristics locale.h Locales math.h Floating-point math setjmp.h Nonlocal jumps signal.h Signal handling stdarg.h Variable arguments stddef.h Standard definitions stdio.h I/O library stdlib.h General utilities string.h String functions time.h Time functions Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 159 Freescale Semiconductor, Inc. MWEntComp.book Page 160 Monday, September 27, 2004 2:17 PM Runtime Libraries Character Typing and Conversion (ctype.h) Table 6.1 Supported Libraries (continued) Library Type Header File Description Non-ISO prototype.h Built-in intrinsic functions. prototype_a sm.h Alternative header file that defines built-in intrinsic functions so that they do not conflict with these assembler operations: add, debug, debugv, di, ei, max, mark, min, mpyuu, mpysu, mpyus, stop, sub, trap, wait. If needed, include this file in your code instead of prototype.h. Character Typing and Conversion (ctype.h) Table 6.2 lists the testing and conversion functions that the compiler supports. These functions are in the ctype.h library. Table 6.2 Testing, Conversion Functions 160 Category Function Purpose Testing functions int isalnum(int) Tests for isalpha or isdigit int isalpha(int) Tests for isupper or islower int iscntrl(int) Tests for any control character int isdigit(int) Tests for decimal digit character int isgraph(int) Tests for any printing character except space int islower(int) Tests for lowercase alphabetic character int isprint(int) Tests for any printing character including space int ispunct(int) Tests for any printing character not space and not isalnum int isspace(int) Tests for white-space characters int isupper(int) Tests for uppercase alphabetic character Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 161 Monday, September 27, 2004 2:17 PM Runtime Libraries Floating-Point Characteristics (float.h) Table 6.2 Testing, Conversion Functions (continued) Category Conversion functions Function Purpose int isxdigit(int) Tests for hexadecimal digit character int tolower(int) Converts uppercase alphabetic character to the equivalent lower case character int toupper(int) Converts lowercase alphabetic character to the equivalent uppercase character Floating-Point Characteristics (float.h) The compiler uses IEEE format (ANSI/IEEE Std 754-1985) to represent floating-point numbers. Unless you specify otherwise, the compiler supports just single precision floating-point format. To enable the double precision floating-point format, use the slld option . Table 6.3 lists the name and default value of each floating-point manifest constant; Table 6.4 lists the values of these constants if you use the -slld switch. NOTE The floating-point constant definitions are in float.h. Table 6.3 Default Values of Floating-Point Constants Constant Value Purpose FLT_DIG DBL_DIG LDBL_DIG 6 6 6 Number of decimal digits of precision FLT_EPSILON DBL_EPSILON LDBL_EPSILON 1.1920929E-07 1.1920929E-07 1.1920929E-07 Minimum positive number χ such that 1.0 + χ does not equal 1.0 FLT_MANT_DIG DBL_MANT_DIG LDBL_MANT_DIG 24 24 24 Number of base-2 digits in the mantissa FLT_MAX_10_EXP DBL_MAX_10_EXP LDBL_MAX_10_EXP 38 38 38 Maximum positive integers n such that 10n is representable Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 161 Freescale Semiconductor, Inc. MWEntComp.book Page 162 Monday, September 27, 2004 2:17 PM Runtime Libraries Floating-Point Characteristics (float.h) Table 6.3 Default Values of Floating-Point Constants (continued) Constant Value Purpose FLT_MAX_EXP DBL_MAX_EXP LDBL_MAX_EXP 128 128 128 1 FLT_MAX DBL_MAX LDBL_MAX 3.4028235E+38 3.4028235E+38 3.4028235E+38 FLT_MIN_10_EXP DBL_MIN_10_EXP LDBL_MIN_10_EXP -39 -39 -39 10n is representable FLT_MIN_EXP DBL_MIN_EXP LDBL_MIN_EXP -126 -126 -126 1 FLT_MIN DBL_MIN LDBL_MIN 5.8774817E-39 5.8774817E-39 5.8774817E-39 Minimum positive number FLT_RADIX FLT_ROUNDS 2 1 Floating-point exponent is expressed n radix 2. Floating-point rounding is to nearest even number. Maximum positive integer n such that 2nis representable Maximum positive floating-point number Minimum negative integer n such that Minimum negative integer n such that 2nis representable Table 6.4 Values of Floating-Point Constants with -slld Option 162 Constant Value Purpose FLT_DIG DBL_DIG LDBL_DIG 6 10 10 Number of decimal digits of precision FLT_EPSILON DBL_EPSILON LDBL_EPSILON 1.1920929E-07 2.2204460492503131E-16 2.2204460492503131e-16 Minimum positive number χ such that 1.0 + χ does not equal 1.0 FLT_MANT_DIG DBL_MANT_DIG LDBL_MANT_DIG 24 53 53 Number of base-2 digits in the mantissa FLT_MAX_10_EXP DBL_MAX_10_EXP LDBL_MAX_10_EXP 38 308 308 Maximum positive integers n such that 10n is representable Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 163 Monday, September 27, 2004 2:17 PM Runtime Libraries Floating-Point Library Interface (fltmath.h) Table 6.4 Values of Floating-Point Constants with -slld Option (continued) Constant Value Purpose FLT_MAX_EXP DBL_MAX_EXP LDBL_MAX_EXP 128 1024 1024 such that 2n-1 is representable FLT_MAX DBL_MAX LDBL_MAX 3.4028235E+38 1.79769313e+308 1.79769313e+308 FLT_MIN_10_EXP DBL_MIN_10_EXP LDBL_MIN_10_EXP -39 -308 -308 such that 10n is representable FLT_MIN_EXP DBL_MIN_EXP LDBL_MIN_EXP -126 -1022 -1022 such that 2n-1 is representable FLT_MIN DBL_MIN LDBL_MIN 5.8774817E-39 4.94065645e-308 4.94065645e-308 Minimum positive number FLT_RADIX FLT_ROUNDS 2 1 Floating-point exponent is expressed n radix 2. Floating-point rounding is to nearest even number. Maximum positive integer n Maximum positive floatingpoint number Minimum negative integer n Minimum negative integer n Floating-Point Library Interface (fltmath.h) Header file fltmath.h defines the software floating-point library interface. The code generator (of the compiler for floating-point expression evaluation) calls most of these functions. User code also may call these functions directly. The floating-point library supports the full IEEE-754 single-precision floating-point standard. Three configuration parameters and one status word are available for your use: • Round_Mode • FLUSH_TO_ZERO • IEEE_Exceptions • EnableFPExceptions Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 163 Freescale Semiconductor, Inc. MWEntComp.book Page 164 Monday, September 27, 2004 2:17 PM Runtime Libraries Floating-Point Library Interface (fltmath.h) Round_Mode The compiler supports four rounding modes: • ROUND_TO NEAREST_EVEN — (Default) The representable value nearest to the infinitely precise intermediate value is the result. If the two nearest representable values are equally near (tie), then the one with the least significant bit equal to zero (even) is the result. • ROUND_TOWARDS_ZERO — The result is the value closest to, and no greater in magnitude than, the infinitely precise intermediate result. • ROUND_TOWARDS_MINUS_INF — The result is the value closest to and no greater than the infinitely precise intermediate result (possibly minus infinity). • ROUND_TOWARDS_PLUS_INF — The result is the value closest to and no less than the infinitely precise intermediate result (possibly plus infinity). Listing 6.1 shows an example of changing the round mode to ROUND_TOWARDS_MINUS_INF. Listing 6.1 Changing the Round Mode #include <fltmath.h> . . . Round_Mode = ROUND_TOWARDS_MINUS_INF. FLUSH_TO_ZERO This is a boolean configuration item that sets the behavior of un-normalized numbers. When set to true (the default) all un-normalized values are flushed to zero. This leads to better performance, but a smaller dynamic range. For example, Listing 6.2 shows how to disable the FLUSH_TO_ZERO option. Listing 6.2 Disabling Flushing to Zero #include <fltmath.h> . . . FLUSH_TO_ZERO = 0; IEEE_Exceptions This status word represents the IEEE exceptions that were raised during the last floatingpoint operation. The default arrangement is that the floating-point library sets these values, but does not handle any of these exceptions. 164 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 165 Monday, September 27, 2004 2:17 PM Runtime Libraries Floating-Point Library Interface (fltmath.h) The compiler supports these exceptions, which the IEEE standard describes: • IEEE_Inexact • IEEE_Divide_By_Zero • IEEE_Underflow • IEEE_Overflow • IEEE_Signaling_Nan Listing 6.3 is an example of how to use the exception status word. Listing 6.3 Using the Exception Status Word #include <fltmath.h> float x,y; . . . x = x*y; if (IEEE_Exceptions & IEEE_Overflow) { <handle overflow> } EnableFPExceptions This is a bit field mask. Setting a flag enables raising an SIGFPE signal if the last FP operation raised this exception. For example, Listing 6.4 is an example that installs a signal for handling overflow and divide-by-zero exceptions. Listing 6.4 Setting a Signal for Exceptions #include <fltmath.h> #include <signal.h> void SigFPHandler(int x) { switch (IEEE_Exceptions) { case IEEE_Overflow: . . . case IEEE_Divide_by_zero: . . . } } float x,y; . . . Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 165 Freescale Semiconductor, Inc. MWEntComp.book Page 166 Monday, September 27, 2004 2:17 PM Runtime Libraries Integer Characteristics (limits.h) EnableFPExceptions = IEEE_Overflow | IEEE_Divide_by_zero; signal(SIGFPE, SigFPHandler) x = x*y /*This raises SIGFPE if overflow or */ divide by zero occur */ NOTE As signal handling installs the handler address in the interrupt table, this example works only if the interrupt vector table is in RAM. If the call to SIGNAL cannot install the new handler, the call returns SIG_ERR. Integer Characteristics (limits.h) Table 6.5 lists the contents of limits.h. Table 6.5 Contents of file limits.h Constant Value Purpose CHAR_BIT 8 Width of char type, in bits CHAR_MAX CHAR_MIN 127 -128 Maximum value for char Minimum value for char INT_MAX INT_MIN UINT_MAX 2147483647 (-2147483647-1) 429496729u Maximum value for int Minimum value for int Maximum value for unsigned int LONG_MAX LONG_MIN ULONG_MAX 2147483647 (-2147483647-1) 429496729uL Maximum value for long int Minimum value for long int Maximum value for unsigned long int MB_LEN_MAX 2 Maximum number of bytes in a multibyte character SCHAR_MAX SCHAR_MIN UCHAR_MAX 127 -128 255 Maximum value for signed char Minimum value for signed char Maximum value for unsigned char SHRT_MAX SHRT_MIN USHRT_MAX 32767 -32768 65536u Maximum value for short int Minimum value for short int Maximum value for unsigned short int Locales (locale.h) Table 6.6 lists the locale functions that the compiler supports. 166 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 167 Monday, September 27, 2004 2:17 PM Runtime Libraries Floating-Point Math (math.h) NOTE These locale functions have no effect; the compiler supports them only for compatibility. Table 6.6 Locale Functions Function Purpose localeconv(void) Not applicable setlocale(int category, const char* locale) Not applicable Floating-Point Math (math.h) The compiler runtime environment uses floating-point emulation to implement the math.h library. This library provides support for these function types: • Trigonometric • Hyperbolic • Exponential and logarithmic • Power • Other functions Table 6.7 lists these functions. Table 6.7 Mathematical Functions Type Function Purpose Trigonometric double acos(double) arc cosine double asin(double) arc sine double atan(double) arc tangent double atan2(double, double) arc tangent2 double cos(double) cosine double sin(double) sine double tan(double) tangent Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 167 Freescale Semiconductor, Inc. MWEntComp.book Page 168 Monday, September 27, 2004 2:17 PM Runtime Libraries Program Administrative Functions Table 6.7 Mathematical Functions (continued) Type Function Purpose Hyperbolic double cosh(double) Hyperbolic cosine double sinh(double) Hyperbolic sine double tanh(double) Hyperbolic tangent double exp(double) Exponential double frexp(double, int*) Splits floating-point into fraction and exponent double ldexp(double, int) Computes value raised to a power double log(double) Natural logarithm double log10(double) Base ten (10) logarithm double modf(double, double*) Splits floating-point into fraction and integer double pow(double, double) Raises value to a power double sqrt(double) Square root double ceil(double) Ceiling double fabs(double) Floating-point absolute number double floor(double) Floor double fmod(double, double) Floating-point remainder Exponential, Logarithmic Power Other Program Administrative Functions Programs routinely must control jumps, handle signals, define variable arguments, and define standard types and constants. Table 6.8 lists the corresponding functions that the compiler supports, indicating their library files. 168 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 169 Monday, September 27, 2004 2:17 PM Runtime Libraries Program Administrative Functions Table 6.8 Administrative Functions Type Function Purpose Non-local jumps (setjmp.h) typedef unsigned int jmp_buf[32] Buffer used to save the execution context void longjmp(jmp_buf, int) Nonlocal jump int setjmp(jmp_buf) Nonlocal return int raise(int) Raises a signal void(*signal(int, void (*)( int ))) (int) Installs a signal handler va_arg(_ap, _type) (*(_type*)((_ap) -= sizeof(_type))) Returns next parameter in argument list va_end(_ap) (void)0 Performs cleanup of argument list va_list Type declaration of variable argument list va_start(_ap, _parmN) (void)(_ap = (char*)&_parmN) Performs initialization of argument list NULL((void*)0) Null pointer constant offsetof(type, member) Field offset in bytes from start of structure typedef int ptrdiff_t Signed integer type resulting from the subtraction of two pointers typedef int size_t Unsigned integer type that is the data type of the sizeof operator typedef short wchar_t Wide character type, as defined in ISO C Signal handling (signal.h) Variable argument (stdarg.h) Standard definitions (stddef.h) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 169 Freescale Semiconductor, Inc. MWEntComp.book Page 170 Monday, September 27, 2004 2:17 PM Runtime Libraries I/O Library (stdio.h) I/O Library (stdio.h) The stdio.h library contains the input, stream, output, and miscellaneous I/O functions. Table 6.9 lists these functions. Table 6.9 I/O Functions Type Function Purpose Input int fgetc(FILE*) Inputs a single character if available from specified stream size_t fread(void*, size_t, size_t, FILE*) Inputs a size number of characters from stdin int fscanf(FILE*, const char*, ...) Inputs text from the specified stream int getc(FILE*) Inputs a single character if available from specified stream int getchar(void) Inputs a single character if available from stdin int scanf(const char*, ...) Inputs text from stdin int sscanf(const char*, const char*, ...) Inputs text from specified string void clearerr(FILE*) Clears the EOF and error indicators for the specified stream Stream 170 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 171 Monday, September 27, 2004 2:17 PM Runtime Libraries I/O Library (stdio.h) Table 6.9 I/O Functions (continued) Type Function Purpose int fclose(FILE*) Flushes the specified stream and closes the file associated with it int feof(FILE*) Tests the EOF indicator for the specified stream int ferror(FILE*) Tests the error indicator for the specified stream int fgetpos(FILE*, fpos_t*) Stores the current value of the file position indicator for the specified stream FILE* freopen(const char*,const char*,FILE*) Opens the specified file in the specified mode, using the specified stream int fseek(FILE*, long int, int) Sets the file position indicator for the specified stream int fsetpos(FILE*, const fpos_t*) Sets the file position indicator for the specified stream to the specified value long int ftell(FILE*) Retrieves the current value of the file position indicator for the current stream int remove(const char*) Makes the specified file unavailable by its defined name int rename(const char*, const char*) Assigns to the specified file a new filename void rewind(FILE*) Sets the file position indicator for the specified stream to the beginning of the file Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 171 Freescale Semiconductor, Inc. MWEntComp.book Page 172 Monday, September 27, 2004 2:17 PM Runtime Libraries I/O Library (stdio.h) Table 6.9 I/O Functions (continued) Type Output 172 Function Purpose void setbuf(FILE*, char*) Defines a buffer and associates it with the specified stream. A restricted version of setvbuf() int setvbuf(FILE*, char*, int, size_t) Defines a buffer and associates it with the specified stream stderr Standard error stream (Value = 3) stdin Standard input stream (Value = 1) stdout Standard output stream (Value = 2) FILE* tmpfile(void) Creates a temporary file char* tmpnam(char*) Generates a valid filename, meaning a filename that is not in use, as a string char* fgets(char*, int, FILE*) Outputs characters to the specified stream int fprintf(FILE*, const char*, ...) Outputs the specified text to the specified stream int fputc(int, FILE*) Outputs a single character to the specified stream int fputs(const char*, FILE*) Outputs a string to the specified stream size_t fwrite(const void*, size_t, size_t, FILE*) Outputs a size number of characters to stdout char* gets(char*) Outputs characters into the user's buffer Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 173 Monday, September 27, 2004 2:17 PM Runtime Libraries I/O Library (stdio.h) Table 6.9 I/O Functions (continued) Type Miscellaneous Function Purpose void perror(const char*) Outputs an error message int printf(const char*, ...) Outputs the specified text to stdout int putc(int, FILE*) Outputs a single character to the specified stream int putchar(int) Outputs a single character int puts (const char*) Outputs the string to stdout, followed by a new line int sprintf(char*, const char*, ...) Outputs the specified text to the specified buffer int vfprintf(FILE*, const char*, va_list) Outputs the variable arguments to the specified stream int vprintf(const char*, va_list) Outputs the variable arguments to stdout int vsprintf(char*, const char*, va_list) Outputs the variable arguments to the specified buffer int fflush(FILE*) Causes the output buffers to be emptied to their destinations FILE* fopen(const char*, const char*) Associates a stream with a file int ungetc(int, FILE*) Moves the character back to the head of the input stream Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 173 Freescale Semiconductor, Inc. MWEntComp.book Page 174 Monday, September 27, 2004 2:17 PM Runtime Libraries General Utilities (stdlib.h) General Utilities (stdlib.h) The stdlib.h library contains these function types: • Memory allocation • Integer arithmetic • String conversion • Searching and sorting • Pseudo random number generation • Environment • Multibyte Table 6.10 lists these functions. Table 6.10 General Utility Functions Type Function Purpose Memory allocation void free(void*) Returns allocated space to heap void* calloc(size_t, size_t) Allocates heap space initialized to zero void* malloc(size_t) Allocates heap space void* realloc(void*, size_t) Allocates a larger heap space and returns previous space to heap int abs(int) Absolute value div_t div(int, int) Quotient and remainder long int labs(long int) Computes absolute value and returns as long int ldiv_t ldiv(long int, long int) Quotient and remainder of long int double atof(const char*) String to float int atoi(const char*) String to int Integer arithmetic String conversion 174 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 175 Monday, September 27, 2004 2:17 PM Runtime Libraries General Utilities (stdlib.h) Table 6.10 General Utility Functions (continued) Type Searching, sorting Pseudo random number generation Environment Function Purpose long int atol(const char*) Long double strtod(const char*, char**) Double long int strtol(const char*, char**, int) Long unsigned long int strtoul(const char*, char**, int) Unsigned long void *bsearch(const void*, const void*, size_t, size_t, int(*)(const void*, const void*)) Binary search void *qsort(void*, size_t, size_t, int(*)(const void*, const void*)) Quick sort int rand(void) Random number generator void srand(unsigned int) Initializes the random number generator void abort(void) Causes an abnormal termination. int atexit(void (*)(void)) Registers a function to be called at normal termination. void exit(int) Causes a normal termination char *getenv(const char *name) Gets environment variable. (This function is supported for compatibility purposes and has no effect.) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 175 Freescale Semiconductor, Inc. MWEntComp.book Page 176 Monday, September 27, 2004 2:17 PM Runtime Libraries String Functions (string.h) Table 6.10 General Utility Functions (continued) Type Multibyte character Function Purpose int system(const char *string) Passes command to host environment. (This function is supported for compatibility purposes and has no effect.) int mblen(const char*, size_t) Multibyte string length size_t mbstowcs(wchar_t*, const char*, size_t) Converts multibyte string to wide character string int mbtowc(wchar_t*, const char*, size_t) Converts multibyte to wide character int wctomb(char*, wchar_t) Converts wide character to multibyte size_t wcstombs (char*, const wchar_t*, size_t) Converts wide character string to multibyte string String Functions (string.h) The string.h library contains these function types: • Copying • Concatenation • Comparison • Search • Other Table 6.11 lists these functions. Table 6.11 String Functions 176 Type Function Purpose Copying void* memcpy(void*, const void*, size_t) Copies data void* memmove(void*, const void*, size_t) Swaps data Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 177 Monday, September 27, 2004 2:17 PM Runtime Libraries String Functions (string.h) Table 6.11 String Functions (continued) Type Concatenation Comparison Search Function Purpose char* strcpy(char*, const char*) Copies a string char* strncpy(char*, const char*, size_t) Copies a string of a maximum length char* strcat(char*, const char*) Concatenates a string to the end of another string char* strncat(char*, const char*, size_t) Concatenates a string of specified maximum length to the end of another string int memcmp(const void*, const void*, size_t) Compares data int strcmp(const char*, const char*) Compares strings int strcoll(const char*, const char*) Compares strings based on locale int strncmp(const char*, const char*, size_t) Compares strings of maximum length size_t strxfrm(char*, const char*, size_t) Transforms a string into a second string of the specified size void* memchr(const void*, int, size_t) Searches for a value in the first number of characters char* strchr(const char*, int) Searches a string for the first occurrence of char size_t strcspn(const char*, const char*) Searches a string for the first occurrence of char in string set and returns the number of characters skipped Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 177 Freescale Semiconductor, Inc. MWEntComp.book Page 178 Monday, September 27, 2004 2:17 PM Runtime Libraries Time Functions (time.h) Table 6.11 String Functions (continued) Type Other Function Purpose char strpbrk(const char*, const char*) Searches a string for the first occurrences of char in string set and returns a pointer to that location char* strrchr(const char*, int) Searches a string for the last occurrence of char size_t strspn(const char*, const char*) Searches a string for the first occurrence of char not in string set char* strstr(const char*, const char*) Searches a string for the first occurrence of string char* strtok(char*, const char*) Separates a string into tokens void* memset(void*, int, size_t) Copies a value into each number of characters char* strerror(int) Returns string for associated error condition size_t strlen(const char*) Returns size of string Time Functions (time.h) Table 6.12 lists the time functions, and the time constant, that the compiler supports. Table 6.12 Time Functions 178 Type Function Purpose Time functions (time.h) char *asctime(const struct tm *timeptr) Converts time to ASCII representation clock_t clock() Returns processor time typedef unsigned long clock_t Type used for measuring time char *ctime (const time_t *timer) Converts time to ASCII representation Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 179 Monday, September 27, 2004 2:17 PM Runtime Libraries Time Functions (time.h) Table 6.12 Time Functions (continued) Type Time constant Function Purpose double difftime(time_t time1, time_t time0) Returns difference in seconds time_t mktime(struct tm *timeptr) Converts struct tm to time_t size_t strftime (char *s, size_t maxsize, const char *format, const struct tm *timeptr) Converts an ASCII string to time_t time_t time(time_t *timer) Returns processor time (same as clock) typedef unsigned long time_t Type used for measuring time struct tm *gmtime(const time_t *timer) Returns time in GMT time zone struct tm *localtime(const time_t *timer) Returns time in local time zone CLOCKS_PER_SEC Value is different for each target board. See the board’s time.h file. The clock function returns the current value of the system timer. This function must be configured to match the actual system timer configuration. The timer is started and set for a maximum period during the initialization of any C program that references the clock function, and is used only by this function. The return value of clock has type clock_t, which is unsigned long. Listing 6.5 shows how to use the clock function to time your application. Listing 6.5 Timing an Application #include <time.h> clock_t start, end, elapsed; /* . . . application setup . . . */ start = clock( ); Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 179 Freescale Semiconductor, Inc. MWEntComp.book Page 180 Monday, September 27, 2004 2:17 PM Runtime Libraries Time Functions (time.h) /* . . . application processing . . . */ end = clock( ); elapsed = end - start; /* Assumes no wrap-around */ printf("Elapsed time: %Lu * 2 cycles. \n", elapsed) 180 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 181 Monday, September 27, 2004 2:17 PM 7 Optimization Techniques and Hints This chapter explains the SC100 optimizer. This explanation covers optimization levels and individual optimizations. This chapter contains these sections: • Optimizer Overview • Using the Optimizer • Optimization Types and Functions • Optimizer Assumptions Optimizer Overview The SC100 optimizer converts preprocessed source files into assembly output code, applying a range of code transformations that can significantly improve program efficiency. The goal is producing output code that is functionally equivalent to the original source code, but which is smaller or executes faster. Subsections are: • Code Transformations • Basic Blocks • Linear and Parallelized Code • Optimization Levels and Options Code Transformations The optimizer is extremely versatile, so can transform the code in a number of ways, including • Substituting instructions with more efficient code • Removing redundant instructions • Inserting instructions to simplify operations • Hoisting or lowering instructions to reduce unnecessary operations Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 181 Freescale Semiconductor, Inc. MWEntComp.book Page 182 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimizer Overview Table 7.1 illustrates each of these transformations. Table 7.1 Instruction Transformation Transformation Type Before Optimization After Optimization Substitution move.w #0,d0 clr d0 Removal move.w #0,d0 move.w (r1),d0 move.w (r1),d0 Insertion and removal for(i=0; i<3; i++) alpha(); alpha(); alpha(); alpha(); Hoisting if(a<3) Tbit = TRUE; else Tbit = FALSE; Tbit = FALSE; if(a<3) Tbit = TRUE; Basic Blocks The optimizer applies most of these transformations to basic blocks of code. A basic block is a linear sequence of instructions for which there is only one entry point and one exit point. There are no branches in a basic block. In general, bigger basic blocks enable better optimization, as they increase the scope for further optimization. Linear and Parallelized Code The optimizer can produce code that takes full advantage of the multiple execution units in the SC100 architecture. Executable programs process instructions in the form of execution sets, with one execution set per cycle. The optimizer can increase the number of instructions in an execution set, so that two or more execution units process instructions in parallel, in the same cycle. In this sense, the optimizer transforms linear code into parallelized code: • Linear code occupies just one execution unit, no matter how many execution units may be available. Each execution set consists of just one instruction. • Parallelized code execution sets can contain multiple instructions. If multiple execution units are available, they can execute the execution sets in parallel. Parallelized code executes faster and more efficiently than does linear code. Figure 7.1 illustrates the transformation of linear code: 182 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 183 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimizer Overview Figure 7.1 Linear and Parallelized Code LINEAR CODE PARALLELIZED CODE Instruction Execution set 1 A Execution set 2 B Execution set 3 C Execution set 4 D Execution set 5 E Instructions A B C D F E I G H L M P K J ... J K P Remember, however, that dependencies between instructions can restrict the possible level of parallelization. Optimization Levels and Options For each compilation, you may specify only one optimization level. Each level is a balance between code density and speed. At each higher level compilation takes longer, but code execution is faster. • Level 0 — unoptimized code. • Level 1 — target-independent optimizations. This yields optimized linear code. • Level 2 (the default) — target-independent optimizations, plus target-specific optimizations. This yields parallelized code. • Level 3 — target-independent optimizations and target-specific optimizations, plus global-algorithm register allocation by the low-level optimizer. The generated code usually is faster than Level-2 code. With Level 1, Level 2, or Level 3, you may add two supplemental optimizations: Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 183 Freescale Semiconductor, Inc. MWEntComp.book Page 184 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimizer Overview • Space optimization — the optimizer favors program size over the level you specify. Programs or modules that have been optimized for space require less memory but may sacrifice program execution speed. • Cross-file optimization — the optimizer applies the specified level across all application files at the same time. This yields the most efficient program code. Combining space optimization at Level 3 (-O3 -Os) generates programs with smaller code size than those obtained with specifiers -O2 -Os. Cross-file optimization is complex process, so significantly increases compilation time, Developers usually apply cross-file optimization at the end of the cycle, after compiling and optimizing source files individually or in groups. The optimizer’s default setting is no cross-file optimization. Table 7.2 summarizes the optimization options. Table 7.2 Optimization Options Summary Option Description Benefits -O0 (Level 0) Disables all optimizations. Outputs non-optimized, linear assembly code. Compiles fastest. -O1 (Level 1) Performs all target-independent (nonparallelized) optimizations, such as function inlining and loop unrolling. Omits all target-specific optimization steps. Outputs optimized, linear code. Compiles faster than option -O2 (the default). Produces faster programs than option -O0. Generates assembly code which correlates clearly with the C source code, and can assist debugging. -O or -O2 (Level 2) (Default) Performs all optimizations. Outputs optimized, non-linear assembly code. Takes advantage of parallel execution units, producing the highest performance code possible without cross-file optimization. -O3 (Level 3) Activates the same optimizations as the -O2 option but uses the low-level optimizer to perform global register allocation. Fewer number of cycles. 184 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 185 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Using the Optimizer Table 7.2 Optimization Options Summary (continued) Option Description Benefits -Os Performs the indicated level of optimization, with emphasis on reducing code size. Can be specified together with any of the other optimization options except -O0. Produces optimized assembly code which is small. -Og Performs cross-file optimization. Can be specified together with any of the other optimization options except -O0. Produces the most efficient results when used with -O3. Compiles significantly slower than the other options. Using the Optimizer The default optimization is Level 2, without cross-file optimization. However, at each stage of program development, you can optimize your source code at the level you need. Furthermore, you can optimize individual program sections according to their purpose in the application. For example: • During initial development stages, you may wish to use the default Level 2 optimization to compile your source code files, individually or in groups. As appropriate, you could optimize certain sections of the application for maximum speed, but optimize other sections for size, reducing the memory space they occupy. • During final development stages, you could specify Level 3 and cross-file optimization. This compilation would take more time, but would produces the most effective results. You select the optimization level and mode by specifying one or more options in the shell command line. • Invoking the Optimizer • Optimizing for Space • Cross-File Optimizing Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 185 Freescale Semiconductor, Inc. MWEntComp.book Page 186 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Using the Optimizer Invoking the Optimizer To invoke the optimizer, include the appropriate options in the shell command line or command file, as Listing 7.1, Listing 7.2, and Listing 7.3 show. The command line of Listing 7.1 invokes the optimizer with one input source file, and the default optimization settings. The optimizer applies Level 2 optimizations without cross-file optimization. Listing 7.1 Invoking the Optimizer with Default Settings scc -o file.eld file.c The command line of Listing 7.2 invokes the optimizer with the Level 1 option. The optimizer applies only target-independent optimizations. Listing 7.2 Invoking the optimizer for target-independent optimizations only scc -O1 -o file.eld file.c The command line of Listing 7.3 invokes the optimizer with cross-file optimization mode. The optimizer processes all the specified source files together, applying the default Level 2 optimizations to all application modules. Listing 7.3 Invoking the optimizer with cross-file optimization scc -Og -o file.eld file1.c file2.c file3.c Optimizing for Space Your application, or specific parts of it, may require code that occupies the least possible memory space. If so, you can optimize the files for space, at the expense of program speed. To do so, include the -Os option in the shell command line. In response, the optimizer generates the smallest code size for the given optimization level. If you do not specify a level, the optimizer uses the default Level 2. The optimizer applies all optimizations that are part of the specified level are applied, except those that increase code size. (In fact, the optimizer emphasizes optimizations that reduce code size.) However, depending on your application, you might achieve the best code density through other combinations, such as -O2 and -Og. 186 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 187 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Cross-File Optimizing Once you have optimized your individual source files and groups of files, you can invoke cross-file optimization. This mode is the most effective across the entire application, yielding the most efficient code. With cross-file optimization, the compiler processes all the application code at the same time. The optimizer does not have to accommodate theoretical worst cases, as all the necessary information is available. Cross-file optimization also includes: • Function inlining across all program files. As with inlining for individual files, this increases code size, but considerably increases execution speed. • Optimization of accesses to global and static variables. The main disadvantages of cross-file optimization are the high consumption of resources and the slow compilation time. In addition, due to the interdependence that cross-file optimization creates among all application segments, you must recompile the entire application if you change any one source file. This is why cross-file optimization is most appropriate at the final stage of development. To activate cross-file optimization, include the -Og option in the shell command line. Although you can specify this option with any optimization level, it is most appropriate with Level 3. NOTE If you compile with global optimization, you can use an application reference file to compile parts of your application for speed and other parts for size. Optimization Types and Functions The optimizer implements two main types of optimization: • Target-independent — these optimizations improve output code without considering the properties of the target machine. • Target-specific — these optimizations improve code by exploiting the architecture features of the target machine. You can apply both sets of optimizations to individual files or to groups of files, with or without cross-file optimization. Note that optimization can be cumulative: one optimization’s changes to the code may make it possible to apply another optimization, and so forth. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 187 Freescale Semiconductor, Inc. MWEntComp.book Page 188 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Dependencies and Parallelization Dependency among instructions directly limits optimizations. An instruction is dependent on another if a change in their order of execution influences the result of the operation. The optimizer can group instructions into parallelized execution sets only if these instructions do not contain dependencies. Parallelization of different parts of the program, or of iterations of the same loop, can significantly increase the speed of the executable application. But dependencies prevent such improvements. Listing 7.4 illustrates a simple dependency between two instructions. The value of d0 is different if you reverse the order of these instructions. This prevents parallel execution of these instructions. Listing 7.4 Simple Instruction Dependency move.w add #5,d0 d0,d1,d2 ; Sets register d0 to 5 ; Adds the values in d0 and d1 into register d2 Listing 7.5 shows dependency from an algorithm: the processor must calculate the value of sum before can use that variable in the L_mac instruction. Listing 7.5 Algorithm Instruction Dependency sum = mpy(a,b); result = L_mac(sum,c,d); The optimizer is most effective with code that contains the fewest dependencies possible. Target-Independent Optimizations NOTE This manual’s appendixes provide detailed explanations of target-independent optimizations, with guidelines for making the most efficient use of them. In the high-level optimization phase, the optimizer implements a number of general, target-independent optimizations. These optimizations are part of Level 1, Level 2, or Level 3. Table 7.3 summarizes these optimizations; text sections after the table include examples. (For a detailed discussion of principles, refer to Compilers Principles, Techniques, and Tools, by Aho, Sethi, and Ullman.) 188 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 189 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Table 7.3 Summary of Target-Independent Optimizations Optimization Description Strength Reduction (Loop Transformations) Transforms array access patterns and induction variables in loops, and replaces them with pointer accesses Function Inlining Substitutes a function call with the code of the function Common Subexpression Elimination Replaces an expression with its value if it occurs more than once Loop Invariant Code Moves code outside a loop if its value is unchanged by the loop Constant Folding and Propagation Calculates the value of an expression at compilation time if it contains known static constants Jump-to-Jump Elimination Combines jump instructions Dead Code Elimination Removes code that is never executed Dead Storage/Assignment Elimination Removes redundant variables and value assignments The output from target-independent optimizations has the form of linear assembly code. Strength Reduction (Loop Transformations) Strength reduction is transforming resource-expensive operations into less expensive, linear operations. For example, addition and subtraction are linear functions that need fewer operation cycles than multiplication and division. If an address calculation that contains addition can replace one that contains multiplication, this significantly reduces resources the code needs. This is because the complex addressing mode of the Address Generation Unit (AGU) can implement the addition. The benefit of the addition replacement is even greater if the original multiplication appears within a loop. As part of strength reduction, the optimizer identifies and transforms induction variables (IVs) — variables whose successive values form an arithmetic progression, usually within a loop. An IV example is a subscript that points to the addresses of array elements, increasing with each iteration of the loop. The optimizer tries to move the computation of such a variable to a position outside the loop, avoiding repeated operations. Another possibility is transforming the calculation for use with linear operations. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 189 Freescale Semiconductor, Inc. MWEntComp.book Page 190 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Strength reduction also includes transforming simple and complex loops, and array access patterns, into simpler, linear forms. The subsections below give examples. Simple Loops Listing 7.6, Listing 7.7, Listing 7.8, and Listing 7.9 show the generated pseudocode and output assembly code for a simple loop that initializes an array. The loop structure is static. This means that the loop’s induction variables, the loop counter i and the array offset t1, both increase by increments of known constant values. Listing 7.6 Simple Loop C Source Code int table[100]; step = 1; for(i=0; i<100; i+=step) table[i] = 0; Listing 7.7 Simple Loop C Pseudocode: Before Optimization L1 i = 0; t1 = i * 4; table[t1] = 0; i++; if(i<100) goto L1 Listing 7.8 Simple Loop C Pseudocode: After Optimization L1 i = 0; t1 = i * 4; table[t1] = 0; t1 = t1 + 4; i++; if(i<100) goto L1 Listing 7.9 Simple Loop Assembly Language Output move.l #_table,r0 clr d2 loopstart3 move.l d2,(r0)+ loopend3 190 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 191 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Before optimization, calculating the value of t1 took place within the loop, and was incremented by multiplication. After optimization, t1’s initial value assignment is outside the loop, and its value incrementation inside the loop is by addition. The optimized code yields identical values, but has a much lower resource overhead. The same principles also apply to these more complex loop structures and array access patterns: • Dynamic Loops • Multi-Step Loops • Composed Variable Loops • Square Loops • Triangular Loops Dynamic Loops In a dynamic loop, one or more increments are based on variables whose values are not known at compilation time. Listing 7.10, Listing 7.11, Listing 7.12, and Listing 7.13 show a dynamic loop in which the value of the loop increment and its upper limit are not known at the time of compilation. The optimizer removes the initial multiplication instruction from the body of the loop, replacing the multiplication increment instruction inside the loop with an addition instruction. Listing 7.10 Dynamic Loop C Source Code step = step_table[1]; for(i=0; i<MAX; i+=step) table[i] = 0; Listing 7.11 Dynamic Loop C Source Pseudocode: Before Optimization L1 step = step_table[1]; i = 0; t1 = i * 2; table[t1] = 0; i = i + step; if(i<MAX) goto L1 Listing 7.12 Dynamic Loop C Pseudocode: After Optimization i = 0; step = step_table[1]; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 191 Freescale Semiconductor, Inc. MWEntComp.book Page 192 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions L1 t1 = i * 2; t2 = step * 2; table[t1] = 0; t1 = t1 + t2; i = i + step; if(i<MAX) goto L1 Listing 7.13 Dynamic Loop Assembly Language Output L2 clr move.l adda jf d3 d3,(r1) r2,r1 L2 add cmpge.w d1,d0,d1 #100,d1 Multi-Step Loops In multi-step loops, the loop iterator increments more than once during each loop iteration. Listing 7.14, Listing 7.15, Listing 7.16, and Listing 7.17 show such a loop: iterator i increments twice within the loop. For this case, the optimizer transforms i into an induction variable that increments in linear progression, in three stages. Listing 7.14 Multi-Step Loop Transformation C Source Code int table[10]; for(i=0; i<10; i++) table[i] = i; i++; table[i] = 0; Listing 7.15 Multi-Step Loop Transformation Pseudocode: Before Optimization L1 192 i = 0; t1 = i * 2; table[t1] = i; i = i + 1; t2 = i * 2; table[t2] = i; i= i + 1; if(i<10) goto L1 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 193 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Listing 7.16 Multi-Step Loop Transformation Pseudocode: After Optimization i = 0; t1 = i * 2; t2 = i * 2 + 2; t3 = i; Repeat 10 times: table[t1] = t3; table[t2] = 0; t1 = t1 + 4; t2 = t2 + 4; t3 = t3 + 2; Listing 7.17 Multi-Step Loop Transformation Assembly Language Output loopstart3 L93 move.l d0,(r0)+n3 move.l loopend3 d2,(r1)+n3 add #<2,d0 Composed Variable Loops A composed variable loop incorporates one or more variables or iterators, which have a linear relationship. The optimizer moves the multiplication instruction outside the loop, and substitutes a constant for one variable. This optimization is possible only if linear arithmetic functions link the variables — functions that involve addition or subtraction of the variables, or multiplication of a variable by a constant. This optimization is not possible for functions that include nonlinear operations, such as multiplication of two induction variables. Listing 7.18, Listing 7.19, Listing 7.20, and Listing 7.21 show the generated code for a composed variables loop. In this example the increment is the result of a linear calculation using the two induction variables i and j. Listing 7.18 Composed Variables Loop Transformation C Source Code int table[100]; for(i=0, j=0; i<10; i++) table[10 * i + j] = i; j++; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 193 Freescale Semiconductor, Inc. MWEntComp.book Page 194 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Listing 7.19 Composed Variables Loop Transformation Pseudocode: Before Optimization L1 i = 0; j = 0; t1 = i * 10; t2 = t1 + j; t3 = t2 * 2; /* address */ table[t3] = i; i = i + 1; t1 = t1 + 10; j = j + 1; if(j < 10) goto L1 Listing 7.20 Composed Variables Loop Transformation Pseudocode: After Optimization i = 0; j = 0; t1 = 1 * 10; t2 = t1 + j; t3 = t2 * 2; Repeat 10 times: table[t3] = i; i = i + 1 t3 = t3 + 22; Listing 7.21 Composed Variables Loop Transformation Assembly Language Output loopstart3 L93 move.l loopend3 d0,(r0)+n3 inc d0 Square Loops A square loop is a multi-dimensional array access pattern. It is similar to a matrix in which cell access happens horizontally in rows. This access can start at the first cell in each row. But the optimizer also can process block accesses — in which the access may not begin at the first cell and may not end at the last cell. The compiler’s initial code for a square loop uses a doubly-nested loop with two induction variables. Incrementation of these variables is by multiplication, as the loop progresses through the array elements in each row, and at the start of each new row. Figure 7.2 shows this access pattern. 194 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 195 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Figure 7.2 Square Loop The optimizer changes such a two-dimensional array into one row that contains all the elements in one straight string. The optimizer replaces multiplication instructions with additions, as linear progression is now possible. Listing 7.22, Listing 7.23, Listing 7.24, and Listing 7.25 show an example of square loop transformation. Listing 7.22 Square Loop Transformation C Source Code int table[70][70]; int i, j; for(i=0; i<35; i++) for(j=0; j<70; j++) c += table[i][j]; Listing 7.23 Square Loop Transformation Pseudocode: Before Optimization L1 L2 i = 0; j = 0; tmp1 = i * 140; tmp2 = j * 2; tmp3 = tmp1 + tmp2; tmp4 = table[tmp3]; c = c + tmp4; j++; if(j < 70) goto L2 i++; if(i<35) goto L1 Listing 7.24 Square Loop Transformation Pseudocode: After Optimization ... Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 195 Freescale Semiconductor, Inc. MWEntComp.book Page 196 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions tmp2 = table Repeat 2450 times tmp4 = *tmp2; c = c + tmp4; tmp2 = tmp2 + 2; ... Listing 7.25 Square Loop Transformation Assembly Language Output ... suba r0,r0 move.l move.w nop doen3 doestup3 loopstart3 L9 move.w nop adda adda loopend3 #_tab,r1 #2450,d2 d2 L9 (r1),r2 r2,r0 #<2,r1 ... Triangular Loops A triangular loop array access pattern resembles a square loop pattern, but the pointer moves to an incremented starting position in each row. The starting position pointer increments by linear progression, as Figure 7.3 shows. 196 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 197 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Figure 7.3 Triangular Loop The optimizer transforms a triangular loop into a loop that is mainly linear based, and which incorporates the offset increment as an addition operation. Listing 7.26, Listing 7.27, Listing 7.28, and Listing 7.29 show the transformation of a triangular loop. Listing 7.26 Triangular Loop Transformation C Source Code int table[70][70]; int i, j; for(i=0; i<70; i++) for(j=i+3; j<70; j++) table[i][j] = 0; Listing 7.27 Triangular Loop Transformation Pseudocode: Before Optimization L1 L2 L3 i = 0; j = i if(j>=70) goto L3 tmp1 = i * 140; tmp2 = j * 2; tmp3 = tmp1 + tmp2; table[tmp3] = 0; j++; if(j < 70) goto L2 i++; if(i<70) goto L1 Listing 7.28 Triangular Loop Transformation Pseudocode: After Optimization ... tmp7 = 3 /* equal j+3, that is, inner-loop low bound */ Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 197 Freescale Semiconductor, Inc. MWEntComp.book Page 198 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions tmp4 = table + 6 /* pointer */ tmp6 = 8 /* reset to reach diagonal after inner loop */ Repeat 70 times tmp5 = 70-tmp7 if(tmp5<=0) goto L3 Repeat tmp5 times *tmp4 = 0 tmp4 = tmp4 + 2 /* pointer prepared set to diagonal, */ /* next row */ L3 tmp4 = tmp4 + tmp6 /* next step prepared */ tmp6 = tmp6 + 2 /* next number of iterations */ /* for inner loop */ tmp7 = tmp7 + 1 ... Listing 7.29 Triangular Loop Transformation Assembly Language Output ... move.w #<3,d0 move.l #_tab+6,r0 move.w #<8,r1 move.w #70,d5 nop doen2 d5 dosetup2 L10 move.w #70,d2 loopstart2 L10 sub d0,d2,d3 tstgt d3 jf L4 doensh3 d3 clr d6 nop loopstart3 L9 move.w adda loopend3 d6,(r0) #<2,r0 adda inc adda loopend2 r1,r0 d0 #<2,r1 L6 L4 ... 198 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 199 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Function Inlining Inlining is replacing a function call with a copy of that function’s code. If the procedure call and return consume more time than the function does itself, function inlining can significantly increase the speed of the program. However, function inlining generates larger executable code. The function inlining optimization can be particularly effective with cross-file optimization, as it can be applied across all available files, operating in conjunction with other cross-file optimizations. Listing 7.30 and Listing 7.31 show how the optimizer incorporated function Check’s operation into the code itself, removing the call to the function. Listing 7.30 Function Inlining: Before Optimization int Check(int x); { return (x>10); } void main() { if (Check(y)) a = 5; } Listing 7.31 Function Inlining: After Optimization void main() { if (y>10) a = 5; } To force or suppress function inlining at specific points in the code, use the pragmas #pragma inline and #pragma noinline. Common Subexpression Elimination Common subexpression elimination is substituting an expression’s value for the expression. This optimization pertains to an expression that appears in more than one place in the code, but has the same computed value in each place. The optimizer can include values loaded from memory, as well as values based on arithmetic computations. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 199 Freescale Semiconductor, Inc. MWEntComp.book Page 200 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions In Listing 7.32 and Listing 7.33, the variable x replaces the repeated subexpression e + f. Listing 7.32 Common Subexpression: Before Optimization d = e + f + g; y = e + f + z; Listing 7.33 Common Subexpression: After Optimization x = e + f; d = x + g; y = x + z; Loop Invariant Code Loop invariant code is an instruction that appears inside a loop, without being affected directly by the execution of the loop. The optimizer moves such an instruction to a position outside the loop, so that each loop iteration does not repeat the instruction. In Listing 7.34 and Listing 7.35, for example, the variable z received the computed value of 2 * b + 1 during each loop iteration. The optimizer moved this assignment before the loop start, so that it takes place just once. Listing 7.34 Loop Invariant Code Motion: Before Optimization b = c; for(i=0; i<3; i++) d[i] = 2 * b + 1; Listing 7.35 Loop Invariant Code Motion: After Optimization b = c; z = 2 * b + 1; for(i=0; i<3;i++) d[i] = z; Constant Folding and Propagation In constant folding and propagation, the optimizer identifies expressions that contain int values known to be constants, then calculates their values at compilation time. Then the 200 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 201 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions optimizer replaces each such expression with its value. Listing 7.36 and Listing 7.37 show an example. Listing 7.36 Constant Folding and Propagation: Before Optimization X = 2; Y = X + 10; Z = 2 * Y; Listing 7.37 Constant Folding and Propagation: After Optimization X = 2; Y = 12; Z = 24; Jump-to-Jump Elimination Jump-to-jump elimination is combining two jump operations into one. This optimization pertains to a jump to an destination address, only to jump immediately to a different address. Listing 7.38 and Listing 7.39 show the result of this optimization: a direct jump to J2 replaces the two jump instructions goto J1; and goto J2;. Listing 7.38 Jump-to-Jump Elimination: Before Optimization if(x) ... else goto J1; J1: goto J2; Listing 7.39 Jump-to-Jump Elimination: After Optimization if(x) ... else goto J2; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 201 Freescale Semiconductor, Inc. MWEntComp.book Page 202 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Dead Code Elimination Dead code elimination is removing segments of code that cannot possibly be executed. Such code may be dead from the start, or may become dead as a result of other optimizations. For example, the code may specify a condition that can never be true. In Listing 7.40 and Listing 7.41, the variable c is type char, which can never have a value greater than 255, so the if condition can never be met. Listing 7.40 Dead Code Elimination: Before Optimization char c; if c > 300 a = 1; else a = 2; Listing 7.41 Dead Code Elimination: After Optimization a = 2; Dead Storage/Assignment Elimination Dead storage or dead assignment occurs if a variable receives a value (directly or as a result of an expression), but: • The code never uses the variable again, or • The variable receives another value before being used. For such cases, the optimizer removes the unnecessary instructions and their resulting unused memory locations. This redundancy may arise as a result of other optimizations. In Listing 7.42 and Listing 7.43, before optimization the variable a receives the value 5; code does not use this variable before it receives the new value 7. The optimizer removes the redundant instruction a = 5. If variable a were not used at all after receiving the value 7, the optimizer would have removed it completely. Listing 7.42 Dead Storage/Assignment Elimination: Before Optimization a = 5; .. a = 7; 202 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 203 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Listing 7.43 Dead Storage/Assignment Elimination: After Optimization a = 7; Target-Specific Optimizations The low-level transformations (LLT) phase is a separate modular stage of optimization. During this LLT, the optimizer implements several target-specific optimizations. For example, it transforms the linear code from target-independent optimization into parallel assembly language code. This parallel code can exploit the parallel execution units of the SC100 architecture. However, the number and type of dependencies in the source code limit the degree of possible parallelization. If you specify Level 2 or 3 optimization (option -O2 or -O3), the optimizer applies all target-specific optimizations. It does not apply target-specific optimizations at all if you specify option -O0 or -O1. Table 7.4 lists target-specific optimizations. Sections that follow this table include examples of the major optimizations. Table 7.4 Target-Specific Optimizations Optimization Description Control and Data Flow Analysis Evaluates hierarchical flow of control and data manipulation within procedures, so that optimizations are effective. Constant Propagation Analysis Determines for which constant-to-variable assignments the variable contents remain unchanged, Target-Specific Peephole Optimization Merges a sequence of instructions into a single instruction Register Renaming Removes unnecessary dependencies among instructions that use the same register, by naming other registers for some of the uses. Loop-Invariant Extraction Extracts from loops those instructions whose effect is identical across loop iterations See “Loop Invariant Code” on page 200 for example code. Modulo/Bit-Reverse Addressing Exploits the modulo and bit-reverse addressing modes the StarCore processor supports. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 203 Freescale Semiconductor, Inc. MWEntComp.book Page 204 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Table 7.4 Target-Specific Optimizations (continued) Optimization Description Post-Increment Detection Combines the functions of incrementing (or decrementing) a pointer and accessing the computed address into one instruction If Conversion and Branch Exploits conditional execution of instructions (ift/iff), which the StarCore processor supports. Target-Specific Software Pipelining Rearranges instructions in a loop to minimize dependencies Dead-Code Elimination Deletes instructions that are never executed or whose outputs are never used. Instruction Scheduling Executes multiple instructions in the same cycle, fills delay slots associated with a branch operation, and avoids pipeline restrictions Flow Restructures program flow to minimize the number of change-of-flow instructions. Global Register Allocation In option -O3, most target-independent optimizations and most target-dependent optimizations are performed an virtual registers. Register allocation is an optimization that allocates the virtual registers to physical registers or memory slots, attempting to minimize the transfers from memory to registers. LLT register allocation is global, that is, rather than optimizing small portions of the function (for example, basic blocks), it works on entire functions at once, thus getting better overall results. 204 Target-specific (tfrt/f, movet/f) Replaces conditional execution of transfer/move instructions (ift move) with target-specific conditional instructions (tfrt/movet). Branch Uses short encoding form of change-of-flow instructions where possible. Restriction Checking Verifies compliance with target-machine specific restrictions. As necessary, modifies or inserts code for this compliance. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 205 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Table 7.4 Target-Specific Optimizations (continued) Optimization Description Conditional Execution and Predication Transforms a branch into a sequence of conditional actions Speculative Execution As part of instruction the scheduling step, some instructions are speculatively moved from conditional to unconditional paths. The optimizer applies target-specific optimizations in this definite sequence, invoking some more than once. The result of each optimization affects the next optimization. 1. Control and data-flow analysis 2. Constant propagation analysis 3. Peephole 4. Register renaming 5. Loop invariant 6. Modulo/bit-reverse addressing 7. Post-increment 8. If conversion and branch 9. Peephole 10. Software pipelining 11. Dead code elimination 12. Loop invariant 13. Local instruction scheduling 14. If conversion and branch 15. Flow 16. Register allocation 17. Peephole 18. If conversion and branch 19. Target-specific (tfrt/f, movet/f) 20. Global instruction scheduling 21. Branch 22. Restriction checking Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 205 Freescale Semiconductor, Inc. MWEntComp.book Page 206 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Target-Specific Peephole Optimization Target-specific peephole optimization is merging sequences of instructions into a single instruction. Listing 7.44 and Listing 7.45 show an example. Listing 7.44 Peephole Optimization Generated Code: Before Optimization deca r0 move.w #33,d0 tstgea.l r0 Listing 7.45 Peephole Optimization Generated Code: After Optimization decgea move.w r0 #33,d0 Listing 7.46 and Listing 7.47 show the combination of pipelining and peephole optimizations. During pipelining, the optimizer moved the final mac instruction outside the loop, During peephole optimization, the optimizer merged the mac and rnd instructions into a macr instruction. Listing 7.46 Peephole, Pipelining Generated Code: Before Optimization doen dosetup0 #9 L1 loopstart0 L1 move.w move.w mac (r0)+,d3 (r1)+,d2 d2,d3,d7 loopend0 rnd d7 Listing 7.47 Peephole, Pipelining Generated Code: After Optimization doen #8 ;Pipelining loop once dosetup0 L1 move.w (r0)+,d3 move.w (r1)+,d2 loopstart0 206 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 207 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions L1 mac move.w move.w loopend0 d2,d3,d7 (r1)+,d2 (r0)+,d3 macr d2,d3,d7 ; * ; ** ; ** Post-Increment Detection Post-increment detection is replacing multiple instructions that modify pointers and access addresses with instructions that do both actions. This optimization exploits features of the SC100 architecture to reduce size and increase execution speed. The optimizer identifies instructions that: 1. Use arithmetic functions to modify pointers, and 2. Access the computed addresses. Then the optimizer replaces these instructions with special post-increment or postdecrement address mode instructions that combine both actions. The increment (or decrement) factor is not limited to the values 2 or 4, as any of the four index registers (n0 through n3) may be used. Listing 7.48 and Listing 7.49 show an example. Listing 7.48 Post-Increment Detection Generated Code: Before Optimization L150 move.l #_L_R,r4 move.l #_CGUpdates,r5 doen3 #<8 dosetup3 L183 loopstart3 L183 move.l (r4),d0 move.l (r5),d1 mac d0,d1,d2 adda #<4,r4 adda #<12,r5 loopend3 L152 Listing 7.49 Post-Increment Detection Generated Code: After Optimization L150 doensh3 #<7 ; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 207 Freescale Semiconductor, Inc. MWEntComp.book Page 208 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Pipelining loop once move.w #3,n3 move.l #_L_R,r4 move.l #_CGUpdates,r5 move.l (r4)+,d0 move.l (r5)+n3,d1 loopstart3 L183 [ mac move.l move.l d0,d1,d2 ; * (r5)+n3,d1 ; ** (r4)+,d0 ; ** ] loopend3 L152 mac d0,d1,d2 Target-Specific Software Pipelining Software pipelining is rearranging instruction sequences inside loops, to minimize dependencies between the instructions and increase parallelization. This target-specific optimization enhances target-independent loop optimizations. For example, a loop that iterates four times may contain instructions A, B and C. In some such cases, a different sequence would not affect the result, so the optimizer might be able to change the code segment to: 1. Instruction A 2. Instructions B, C, A, in a loop that iterates three times 3. Instruction B 4. Instruction C This different sequence has fewer dependencies than the original code. This optimization pertains only to innermost loops of small or moderate size, which do not contain branches or function calls. It is most effective for loops that iterate a large number of times. Each iteration of a software pipelined loop may contain instructions from a different iteration of the original loop. Software pipelining almost always increases code size, so specifying optimization for size suppresses software pipelining entirely. 208 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 209 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Listing 7.50, Listing 7.51, and Listing 7.52 show how software pipelining reduces the number of iterations and rearranges instructions both within and outside the loop. This enables parallel execution for the maximum number of non-dependent instructions. Listing 7.50 Software Pipelining: Complex FIR C Source Code for (i = 0; i < N; i++) { L_tmpr = L_mac (L_tmpr, sample[i].r, coeff[N - i - 1].r; L_tmpr = L_msu (L_tmpr, sample[i].i, coeff[N - i - 1].i; L_tmpi = L_mac (L_tmpi, sample[i].i, coeff[N - i - 1].r; L_tmpi = L_mac (L_tmpi, sample[i].r, coeff[N - i - 1].i; } Listing 7.51 Software Pipelining: Complex FIR Pseudocode Before Optimization loop n times: move.w (r0)+,d4 move.w (r1)-,d3 mac d3,d4,d5 move.w (r0)+,d1 move.w (r1)-,d2 mac -d1,d2,d5 mac d3,d1,d6 mac d2,d4,d6 Listing 7.52 Software Pipelining: Complex FIR Pseudocode After Optimization /* Prolog */ move.w (r0)+,d4 mac d3,d4,d5 move.w move.w loop n-1 times: /*start loop*/ [ mac d3,d1,d6 move.w (r0)+,d4 ] [ mac d3,d4,d5 move.w (r0)+,d1 ] /*endloop*/ /* epilog */ (r1)-,d3 (r0)+,d1 move.w(r1)-,d2 mac move.w -d1,d2,d5 (r1)-,d3 mac move.w d2,d4,d6 (r1)-,d2 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 209 Freescale Semiconductor, Inc. MWEntComp.book Page 210 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions mac mac d3,d1,d6 d2,d4,d6 mac -d1,d2,d5 In the example of Listing 7.53 and Listing 7.54, the loop iterates eight times, instead of the original 10, as the optimizer unrolled two iterations. The loop executes in a single cycle, during which the loop: • Loads a value from iteration i+2 • Multiplies the value from iteration i+1 • Stores the result value from iteration i Listing 7.53 Vector Multiplication by a Constant C Source Code for (i=0; i<10; i++) b[i] = mult(a[i], 0x4000); Listing 7.54 Vector Multiplication by a Constant Assembly Code After Optimization doensh3 #<8 ; Pipelining loop twice move.l #_a,r1 move.f #16384,d1 move.f (r1)+,d0 move.l #_b,r0 mpy d0,d1,d2 move.f (r1)+,d0 loopstart3 L93 [ moves.f d2,(r0)+ mpy d0,d1,d2 move.f (r1)+,d0 ] loopend3 ; * ; ** ; *** L92 moves.f moves.f d2,(r0)+ d2,(r0)+ mpy d0,d1,d2 Instruction Scheduling Instruction scheduling is executing as many instructions as possible from the same instruction stream, in the same cycle. Wherever possible, the optimizer organizes instructions into execution sets for parallel execution. This makes the best use of the SC100 architecture’s Data Arithmetic Units and Address Generation Units. 210 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 211 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions The amount of dependency among the instructions limits the extent of this optimization. Listing 7.55 and Listing 7.56 show code before and after this optimization: Listing 7.55 Instruction Scheduling: Before Optimization move.l inc tfra adda move d0,(r0) d0 r3,r0 #12,r3 (r1)+,d1 Listing 7.56 Instruction Scheduling: After Optimization move.l d0,(r0)inc d0 tfra r3,r0 move(r1)+,d1 adda #12,r3 Instruction scheduling includes two additional optimizations: • Filling branch-instruction delay slots • Rescheduling operations that do not depend on pipeline-restricted instructions Filling Delay Slots When program execution takes a branch, the branch instruction needs three clock cycles. Furthermore, execution loses the prefetch queue. This wastes the cycles for other instructions, as the processor cannot execute them until the branch instruction is complete. These wasted cycles are delay slots. As part of instruction scheduling, the optimizer coordinates execution of other operations at the same time as execution of the branch instruction. This rescheduling is possible only if there are no limiting factors, such as: • Instructions that immediately precede the branch instruction and directly affect the branch instruction. • Specific dependencies among the branch and the other instructions. If there are no limiting factors, the scheduler rearranges the code, to use the delay slots efficiently. Listing 7.57 and Listing 7.58 show this effect: the reorganized code lets the processor execute three instructions during the time the branch instruction needs. Listing 7.57 Filling Delay Slots: Before Optimization move.l inc d0,(r0) d0 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 211 Freescale Semiconductor, Inc. MWEntComp.book Page 212 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions tf r rts r3,r0 Listing 7.58 Filling Delay Slots: After Optimization rtsd move.l d0,(ro) inc d0 tfr d5.d2 Avoiding Pipeline Restrictions Instructions such as a move to an Rn register are subject to pipeline restrictions. This means that implementation of the instruction’s effect may not happen until two or more cycles after the processor executes the instruction. An operation that depends on the result of such an instruction, but which follows the instruction immediately, must wait until the result is available. As part of instruction scheduling, the optimizer rearranges the sequence of such instructions where possible. It uses the otherwise-wasted cycles to implement operations that do not depend on the restricted instruction. Listing 7.59 and Listing 7.60 show that the optimizer can reschedule the clr instruction, to execute before the effect of the move.l instruction. By contrast, the move.w instruction must wait for the results of the move.l operation. Listing 7.59 Avoiding Pipeline Restrictions: Before Optimization move.l nop move.w clr d0,(r0) (r0),dl d0 Listing 7.60 Avoiding Pipeline Restrictions: After Optimization move.l clr move.w d0,(r0) d0 (r0),dl Conditional Execution and Predication Conditional execution and predication is simplifying small conditional structures, transforming the branch into one sequence. 212 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 213 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Listing 7.61, Listing 7.62, and Listing 7.63 show an example: the optimizer removes two branches. Listing 7.61 Conditional Execution, Predication C Source Code If(a < 0){ lower_bound = 0; i = 0; }else lower_bound = a; Listing 7.62 Conditional Execution, Predication Generated Code: Before Optimization move.w tstgt bf clr clr bra L_False tfr L_AfterIf move.w a,d0 d0 L_False d2 d3 L_AfterIf d0,d2 d2,lower_bound Listing 7.63 Conditional Execution, Predication Generated Code: After Optimization move.w tstgt ift iff move.w a,d0 d0 clr d2 clr d3 tfr d0,d2 d2,lower_bound An additional advantage of this optimization is that it increases the basic block size in the optimized code segment. This makes other optimizations more effective. NOTE Conditional execution optimization adds one word for each branch that it replaces (ift and iff in the above example), so it can increase program size significantly. Accordingly, this optimization is appropriate only for small structures in which the number of additional instructions does not exceed the number of instructions saved. If size is an important consideration, optimization levels apply specific thresholds for this optimization. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 213 Freescale Semiconductor, Inc. MWEntComp.book Page 214 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions Speculative Execution Speculative execution is moving instructions from conditional to unconditional paths, filling execution slots that otherwise would not be used. If an empty execution slot is available when execution arrives at a condition statement, the optimizer rearranges instructions so that the conditional instructions execute unconditionally in cycles before the condition. This gains a clock cycle for either of two situations: • If the condition is true and the ift instruction has been executed • If the condition is false and the iff instruction has been executed. If the condition result does not match the moved instruction, normal execution of the appropriate instruction takes place, with no loss of cycles. Listing 7.64, Listing 7.65, and Listing 7.66 show an example of this transformation. The optimizer moves the first iff instruction so that it executes in the same cycle as the cmpgt instruction. If the result of the conditional operation is true, execution of the ift instruction takes place in the next cycle. If the result is false, execution of the previouslysecond iff instruction takes place, so that execution takes one cycle instead of two. Listing 7.64 Speculative Execution C Source Code If(var > 5) x[3] = a; else y = b; Listing 7.65 Speculative Execution Generated Code: Before Optimization cmpgt nop iff iff ift #5,d1 move.l x+6,r0 move.l d3,_y move.l d2,(r0) Listing 7.66 Speculative Execution Generated Code: After Optimization move.l nop iff ift x+6,r0 cmpgt #5,d1 move.l d3,_y move.l d2,(r0) This optimization succeeds for one or more instructions if: 214 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 215 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimization Types and Functions • Sufficient slots are available, • There are no dependencies between the instruction in the conditional path and other instructions, and • The conditional instruction does not have any specific side effects. NOTE The LLT option -no_load_spec prevents speculative execution of load instructions. You must use this option when compiling code for architectures that raise the illegal memory access exception. Target-Specific Space Optimization If you specify optimization for space (the -Os option), the optimizer produces the smallest code possible. For target-specific optimizations and optimization for space, the optimizer: • Disables software pipelining. • Uses only serial grouping to encode assembly instructions (adding prefixes would increase code size). • Applies conditional execution and predication to only small structures (this optimization adds to code size). • Uses only the low-registers bank for global register allocation, avoiding the codesize increase of instruction prefix encoding. • Saves and reloads called-saved registers at function entries and exits by means of calls to the library functions ___CW_SC100_callee_save and ___CW_SC100_callee_restore. • Performs some peephole optimizations only for code size, performs others for speed. You may use the -Os option with any option except -O0. If you do not specify a level, the optimizer uses the default — level 2. Using level 3 for space optimization can lead to even smaller code size. The command line of Listing 7.67 invokes the optimizer with the default level 2 optimizations. The optimizer applies all target-independent and target-specific optimizations, except those noted above, across all modules of the application. Listing 7.67 Invoking the Optimizer for Space Optimization scc -Os -Og -o file1.eld file1.c file2.c Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 215 Freescale Semiconductor, Inc. MWEntComp.book Page 216 Monday, September 27, 2004 2:17 PM Optimization Techniques and Hints Optimizer Assumptions Optimizer Assumptions The optimizer uses information from the compiler to keep optimizations from affecting the original accuracy of your program. The compiler information reflects the rule that inside a function it is possible to access only two types of variables: • Global — all variables within the file scope or application scope • Local — variables whose addresses are retrieved implicitly by the automatic conversion of array references to pointers, or explicitly by the & operator If your program conforms to standard ANSI/ISO C, this rule does not affect your code. But if you compile non-standard code that does not follow this rule, the optimization process could affect program behavior adversely. To avoid unexpected results, and to make sure that your program executes correctly after optimization, follow these coding guidelines: • Do not make assumptions based on memory layout when using pointers. For example, if x points to the first member of a structure, x+1 may not necessarily point to the second member of the same structure. Similarly, if you define y as a pointer to the first declared variable in a list, do not assume that y+1 points to the second variable in the list. • When referencing an array, keep the references inside the array bounds. • Be sure to pass all required arguments to functions. • When you subscribe one array, do not access another array indirectly. For example, if x and y are the same type of array, in the construct x[y-x], the construct is equivalent to *(x+(y-x)), which is equivalent to *y. Thus the construct actually references the array y. • When pointing to objects, do not reference outside the bounds of these objects. The optimizer deals with all references of the form *(p+i) as if they apply within the bounds of the variables to which p points. • If external processes must access variables, be sure to declare these variables as volatile. But use this keyword judiciously, as it could affect optimization adversely. 216 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 217 Monday, September 27, 2004 2:17 PM A Icode Options and Option Files Icode options let you enable or disable loop optimizations — you can disable part of the optimizations during your debugging or evaluation. You pass these options to Icode by using the -F option and an appropriate option file with name filename.opt (the .opt extension is mandatory). This appendix contains these sections: • Specifying Icode Options • Option File Syntax • ICode Options List Specifying Icode Options There are several ways to specify Icode options (all these examples include the option file opt.opt): • Icode command line: icode -F opt.opt ... • Scc/ccsc100 command line: scc -Xicode "-F opt.opt" ... • CodeWarrior IDE: Select Edit > C for CW Settings > StarCore Compiler > Passthrough, Hardware > To Icode. Then, in the corresponding panel, type -F opt.opt. Option File Syntax An option text file is a sequence of option keywords, names, and values. Options can have boolean or integral values. For example, these lines disable both multi-step induction and scalarization: ... achieve_multi_step = FALSE Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 217 Freescale Semiconductor, Inc. MWEntComp.book Page 218 Monday, September 27, 2004 2:17 PM Icode Options and Option Files ICode Options List scalarization = FALSE ... ICode Options List Table A.1 lists the Icode options that monitor high-level loop optimizations. NOTE The default value of all these options is TRUE. Table A.1 Icode options related to high-level optimizations 218 Option Effect, related optimization achieve_induction Root condition for most loop optimizations move_invariants_enable Invariant code motion, scalarization Scalarization , simplification of redundant memory accesses, achieve_multi_step Multi-step induction achieve_composition Composition of induction variables achieve_redundant_iv Simplification of redundant basic and non-basic IV achieve_wrap_iv Warp-around IV processed thanks to loop peeling sequential_access Transformation of sequences of memory accesses smart_seqpack_strategy Control of sequences based on assessed register pressure paired_access Multiple moves, vectorization extended_packing Multiple moves involving non-consecutive accesses deambiguation Sequences used to refine data-dependency analysis achieve_cont_mod_access Sequences of modulo accesses merged across loop nest achieve_cross_compo Cross-loop induction partial_summation Partial summation Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 219 Monday, September 27, 2004 2:17 PM Icode Options and Option Files ICode Options List Table A.1 Icode options related to high-level optimizations (continued) Option Effect, related optimization no_unroll_if_seq Loop not unrolled if looks like a loop unrolled in C source code collapse_nest Perfect loop nests collapsed Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 219 Freescale Semiconductor, Inc. MWEntComp.book Page 220 Monday, September 27, 2004 2:17 PM Icode Options and Option Files ICode Options List 220 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 221 Monday, September 27, 2004 2:17 PM B Induction-Related Loop Optimizations This appendix contains these sections: • Loop Detection and Normalization • Loop-Invariant Code Motion • Scalarization • Pointer Promotion • Single-loop Induction • Sequential Accesses, Related Optimizations • Cross-Loop Induction Loop Detection and Normalization • Detecting Hardware-Mappable Loops • Normalizing Hardware Loops Detecting Hardware-Mappable Loops One of the optimizer’s first actions is detecting hardware mappable loops — loops that could be candidates for future mapping as actual hardware loops. This occurs if it is possible to compute loop bounds and loop count, either as static or dynamic values, at compile time. Upon detecting such a loop, the optimizer stores the loop features in an appropriate data structure that contains the definitions of loop bounds, loop steps, loop counter, and so forth. However, the optimizer does not perform actual transformations at this time. For Loops and Do-While Loops The internal representation of a for loop is a do-while loop. This for loop: Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 221 Freescale Semiconductor, Inc. MWEntComp.book Page 222 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Loop Detection and Normalization for(i=3; i<10; i++) { ... } has an internal representation equivalent to this do-while loop: i=3; do { ... i++; } while (i<10); The subsections that follow present loops that the optimizer would detect as hardware mappable loops. These examples have for loops, but the optimizer also would detect equivalent do-while loops. Example 1: Static Loop, Unit Step This loop is the simplest case of hardware loop — a static loop with unit step: for(i=3; i<10; i++) { ... } The main features are: • iteration instruction is i++, • step is 1, • lower-bound expression is i=3, • upper-bound expression is i==10 , • related static loop count is 7. Example 2: Static Loop, Non-Unit Step This similar static loop has a step that is not a unit: for(i=3; i<10; i+=4) { ... } The main features are: • iteration instruction is i+=4, • step is 4, • lower-bound expression is i=3, • upper-bound expression is i==10, 222 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 223 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Loop Detection and Normalization • related static loop count is 2. Example 3: Static Loop, Decreasing Case This loop has a negative (decreasing) step: for(i=10; i>3; i-=4) { ... } The main features are: • iteration instruction is i-=4, • step is -4, • lower-bound expression is i=10, • upper-bound expression is i==3, • related static loop count is 2. Example 4: Simple Dynamic Loop, Unit Step In a dynamic loop, the loop count expression involves a dynamic variable. The variable is loop invariant, but its value is unknown at compile time. This example loop is: for(i=3; i<high_bound; i++) { ... } The main features are: • iteration instruction is i++, • step is 1, • lower-bound expression is i=3, • upper-bound expression is i==high_bound, • related dynamic loop count expression is (high_bound-3). Example 5: Simple Dynamic Loop, Non-Unit Step In this example, the instruction that controls the dynamic loop is an iteration instruction involving a non-unit step. The optimizer detects such a loop as hardware loop if the step is: • A power of two, or equal to 3, 5, or 7, and • The type of the loop index and bounds is a short integer or an unsigned short integer. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 223 Freescale Semiconductor, Inc. MWEntComp.book Page 224 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Loop Detection and Normalization This restriction is due to the complexity of the related dynamic loop count’s expression, as well as the possibility to transform division expressions to fractional multiplication expressions. For example, the optimizer would detect this loop is detected as a hardware loop: for(i=3; i<high_bound; i+=4) { ... } The main features are: • iteration instruction is i+=4, • step is 4, • lower-bound expression is i=3, • upper-bound expression is i==high_bound, • related dynamic loop count expression is (((high_bound-31)+4)>>2)=high_bound>>2. The optimizer also would detect this loop as a hardware loop: short int high_bound short int i; ... for(i=3; i<high_bound; i+=3) { ... } The main features are: • iteration instruction is i+=3, • step is 3, • lower-bound expression is i=3, • upper-bound expression is i==high_bound, • related dynamic loop count expression is (((high_bound-3-1)+3) /* 10923) — where the /* operation corresponds to a multiplication followed by a shift by 15. The StarCore optimizer would not detect this loop as a hardware loop: int high_bound; int i; ... for(i=3; i<high_bound; i+=7) { ... } 224 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 225 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Loop Detection and Normalization Normalizing Hardware Loops Consider these two loops: for(i=0 ; i<MAX ; i++) and: for(i=0 ; i<MAX*2 ; i+=2) The optimizer detects both loops as hardware mappable, but: • Neither loop corresponds to the hardware loop mechanism of the StarCore processor. This mechanism is based on: – a decreasing loop counter, – a step equal to -1, – an initial high bound equal to the number of loop iterations (static or dynamic), – a final low bound equal to 0. • Both loops have similar behavior. Accordingly, the optimizer perceives these loops to be different, as it the features it extracts (during detection of hardware mappable loops) are different. Transformations that require recognition or comparison of loop shapes are thus more complex than they could be. Normalization Principles To overcome these drawbacks, you should preprocess loops so as to normalize them — that is, make them correspond to the processor hardware loop mechanism. This dramatically reduces the possible combinations of patterns to be recognized and transformed. Normalization makes use of the information extracted for detection of hardware-mappable loops to retrieve useful features. Then, for each loop, the optimizer: • Sets a new temporary to be the loop counter, • Normalize the step, • Modifies the branching instructions, and • Memorizes all former (or C-like) features. Preprocessing applies normalization to any hardware mappable loops, whether static or dynamic. Example This initial C for loop: Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 225 Freescale Semiconductor, Inc. MWEntComp.book Page 226 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Loop-Invariant Code Motion for(i=3; i<10; i++) { ... } Has an initial internal representation equivalent to this do-while loop: i=3; do { ... i++; } while (i<10); If normalization is valid for this loop body, its subsequent internal representation is: lc=7; do { ... lc--; } while (lc>0); Loop-Invariant Code Motion Invariant code motion is moving loop invariant instructions to each loop’s prolog. The optimizer applies this optimization before transforming loops, especially before the induction process begins. Consider the C code of Listing B.1: Listing B.1 Loop-Invariant Source Code for(i=0; i<10; i++) { for(j=0; j<10; j++) { ... A = i*3; B = j*4; C = 10; array[j] = A+B+C; ... } } Listing B.2 shows the result of loop invariant motion. Listing B.2 Loop Invariant Motion Result C = 10; for(i=0; i<10; i++) { 226 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 227 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Scalarization A = i*3; for(j=0; j<10; j++) { ... B = j*4; array[j] = A+B+C; ... } } Note that this optimization moved the C=10 instruction twice: • From the inner loop to the inner loop prolog. • From the outer loop to the outer loop prolog. Even an indirect access can be a candidate for this optimization, once the loop body does not modify the pointer value or the contents of the related address. Scalarization Loop code is inefficient if it includes reads from and writes to a memory location, due to an invariant pointer or index. A common example of such a case is using a memory location as an accumulator inside a loop, as in an FIR application. Detecting such a case is merely identifying the pointer or index variable as invariant. Optimizing such code should include scalarizing the memory accesses — that is, moving them outside the loop, replacing them inside the loop with scalar operations. Overview In the Listing B.3 example, i is invariant in the inner loop. Listing B.3 Scalarization Source Code Example 1 for(...) { ... A[i] = 0; for(...) { A[i] = A[i] + f(j); j++; } i++; } Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 227 Freescale Semiconductor, Inc. MWEntComp.book Page 228 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Scalarization Scalarization is substituting an accumulation in a scalar for the read/write memory accumulation. Setting and reading this scalar variable takes place outside the loop. Listing B.4 shows the equivalent, scalarized C code. Listing B.4 Scalarized C Code for(...) { ... scalar = A[i]; for(...) { scalar = scalar + f(j); j++; } A[i] = scalar; i++; } Scalarization Result Listing B.5 shows initial C code that tracks with an accumulation, as you might find in a FIR filter. Listing B.5 Scalarization Source Code Example 2 #define MAX 10 ... short tab[MAX][MAX]; int accu[MAX]; int i, j; ... for(i=0; i<MAX; i++) { accu[i]=0; for(j=0; j<MAX; j++) { accu[i]=accu[i]+tab[i][j]; } } If you generate assembly code without scalarization, default settings lead to two accesses of array accu[i] inside the inner-loop body: a read, then a write. In the Listing B.6 code, this read/write access involves register r0. Listing B.6 Assembly Code without Scalarization DW_2 228 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 229 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Scalarization move.w #240,r6 nop adda r6,sp DW_5 adda #>-40,sp,r0 adda #>-240,sp,r1 doen2 #<10 dosetup2 L10 sub d0,d0,d0 loopstart2 L10 move.l d0,(r0) doen3 #<10 dosetup3 L9 falign loopstart3 L9 move.l (r0),d1 move.w (r1),d2 add d1,d2,d3 move.l d3,(r0) adda #<2,r1 loopend3 L6 adda #<4,r0 loopend2 ;[20] ;[0] AGU stall ;[20] ;[27] ;[0] ;[0] ;[0] ;[0];CLR instruction ;[27] ;[0] ;[0] ;[29] ;[29] ;[29] ;[29] ;[28] ;[26] When the optimizer simplifies this kind of pattern, it reduces the number of memory accesses and instructions in the inner loop body. This lets a data register (d0 in the code of Listing B.7) handle accumulation. Instructions in the outer loop body clear this register, read its contents, then store its contents in the appropriate memory slot: Listing B.7 Assembly Code with Scalarization DW_2 move.w #240,r6 nop adda r6,sp DW_5 adda #>-40,sp,r0 adda #>-240,sp,r1 doen2 #<10 dosetup2 L10 loopstart2 L10 move.w #<0,d0 move.l d0,(r0) ;[20] ;[0] AGU stall ;[20] ;[27] ;[0] ;[0] ;[0] ;[27] ;[27] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 229 Freescale Semiconductor, Inc. MWEntComp.book Page 230 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Pointer Promotion doen3 #<10 dosetup3 L9 nop falign loopstart3 ;[0] ;[0] ;[0] L_D_6 move.w (r1),d1 iadd d1,d0 adda #<2,r1 loopend3 ;[29] ;[29] ;[28] move.l d0,(r0) adda #<4,r0 loopend2 ;[0] ;[26] L9 L6 This optimization reduces the number of instructions in the inner loop body from five to three; it reduces the number of inner-loop memory accesses from three to one. Pointer Promotion Indexed memory accesses are less efficient than indirect accesses. Accordingly, the optimizer transforms indexed accesses to indirect ones, especially for accesses inside a loop. Listing B.8 shows initial C code, in which an indexed instruction accesses an array. Listing B.8 Pointer Promotion Source Code Example ... short tab[MAX]; ... for(i=0 ; i<MAX ; i+=step) { tab[i] = 0 ; }... Pointer promotion is making code efficiency independent of programmer style with regard to array accesses. In the Listing B.8 code, the address the processor actually uses for access is &tab + 2*i. After optimization, the intermediate code is equivalent to that of Listing B.9. Listing B.9 Pointer Promotion Optimized C Code ... short tab[MAX]; ... 230 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 231 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction for(i=0 ; i<MAX ; i+=step) { *(&tab + 2*i) = 0 ; } ... The actual assembly code the compiler generates (when you disable transformation of induction variables) corresponds with Listing B.10, an equivalent indirect form. Listing B.10 Pointer Promotion Assembly Code ... DW_2 adda #<24,sp DW_3 sub d0,d0,d0 doen3 #<10 dosetup3 L5 sub d0,d0,d1 adda #>-24,sp,r1 loopstart3 L5 move.l d0,r0 nop asla r0 adda r1,r0 move.w d1,(r0) inc d0 loopend3 ... ;[20] ;[27];CLR instruction ;[0] ;[0] ;[0];CLR instruction ;[0] ;[28] ;[0] AGU stall ;[28] ;[28] ;[28] ;[27] Single-loop Induction The goals of induction are: • Performing strength reduction by moving complex expressions related to induction variables outside the loop body, replacing these expressions inside the loop body with simple additions. • Allowing a wider, more relevant use of address registers, as soon as memory accesses involve induction variables. Only linear induction variables (IVs) are within the scope of your CodeWarrior for StarCore optimizer: • Basic linear IV — a variable decremented or incremented within the loop body by a constant value (a literal) or by a loop-invariant step. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 231 Freescale Semiconductor, Inc. MWEntComp.book Page 232 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction • Static IV — an IV whose step is a constant (literal). • Dynamic IV — an IV whose step is an invariant value. • Multi-step IV — an IV incremented more than once within the loop body. The key property is that any linear function, or linear combination of linear induction variables, also defines a linear induction variable: • Non-basic (or derived) IV — an IV derived from any other IV by means of a linear function, where the gain is a constant value and the offset is either a constant or a loop-invariant value. • Composed IV — an IV that is a linear combination of any other IVs, where gains are constant values and the offset is either a constant or a loop-invariant value. Extensions of these definitions include modulo IVs, wraparound variables, and monotonic variables (those with conditional incrementation in the loop), all within the scope of the CodeWarrior for StarCore optimizer. Other definition extensions cover polynomial and geometric induction variables, which are not within the scope of the CodeWarrior for StarCore optimizer. Text below shows the effect of single-loop induction. This text focuses on static steps — those known as literal values at compile time. However, the transformation’s principle also applies to dynamic steps — those known to be loop invariant variables, but whose value is unknown at compile time. Simple Induction Variables Consider the initial C code of Listing B.11. Listing B.11 IV Initial C Code ... short tab[MAX]; ... for(i=0 ; i<MAX ; i++) { tab[i] = 0 ; } ... Because of the pointer promotion, the code of Listing B.12 is strictly equivalent. Listing B.12 IV Equivalent C Code ... short tab[MAX]; ... for(i=0 ; i<MAX ; i++) { 232 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 233 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction *(&tab + 2*i) = 0 ; } ... Each access to array tab requires one extra multiplication and one extra addition. The induction variables are: • i — a basic IV; its step equals 1. • (2*i) — a derived IV; its step equals 2, its initial value is 0. • (&tab + 2*i) — a derived IV; its step equals 2, its initial value is &tab. (This expression is a derived IV because the address of array tab is a loop invariant variable.) Through induction the optimizer tries to create equivalent, but more efficient code. This optimized code sets the pointer before entering the loop, incrementing the pointer inside the loop body. This eliminated the need for the intermediate IV 2*i, so the optimizer removed it. Listing B.13 shows the optimized code. Listing B.13 IV Optimized C Code ... short tab[MAX]; short* pt = &tab; ... for(i=0 ; i<MAX ; i++) { *pt = 0 ; pt = pt + 2; } ... Simple Induction Result The original C code of Listing B.11 contains an indexed access using an inducted index. Listing B.14 shows the corresponding assembly code without any transformation of induction variables: • Each loop iteration includes recomputing the address for memory access. • The loop body contains five actual instructions and one nop. Listing B.14 Assembly Code without Induction ... DW_3 sub d0,d0,d0 ;[26];CLR instruction Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 233 Freescale Semiconductor, Inc. MWEntComp.book Page 234 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction doen3 #<10 dosetup3 L5 sub d0,d0,d1 adda #>-24,sp,r1 loopstart3 ;[0] ;[0] ;[0];CLR instruction ;[0] move.l nop asla adda move.w inc loopend3 ;[27] ;[0] AGU stall ;[27] ;[27] ;[27] ;[26] L5 d0,r0 r0 r1,r0 d1,(r0) d0 ... Listing B.15 shows the counterpart assembly code if the optimizer does implement induction. The pointer initialization now is in the loop prolog. A single addition replaces the arithmetic expressions inside the loop body. These improvements relate directly related to this induction: • Just one address register (r0) performs and monitors memory access. • Variable i was no longer useful, so the optimizer removed the related induction and initialization instructions. • Consequently, the loop body contains two instructions instead of the previous six. Listing B.15 Assembly Code with Induction ... DW_3 adda #>-24,sp,r0 doensh3 #<10 sub d0,d0,d0 loopstart3 L5 move.w d0,(r0) adda #<2,r0 loopend3 ... ;[27] ;[0] ;[0];CLR instruction ;[27] ;[26] Limitations The compiler’s induction process handles only restricted cases of division: • The candidate must be a non-basic IV derived form a static IV by means of a division by a power of two (that is, a right shift). 234 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 235 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction • If the compiler accepts such a candidate as a non-basic IV, then it does not detect derived IVs. Multi-Step Induction Variables Listing B.16 shows example initial C code. Listing B.16 Multi-Step Initial C Code ... short tab1[MAX]; short tab2[MAX]; ... for(i=0 ; i<MAX ; ) { tab1[i] = 0 ; i++; tab2[i] = 1; i++; } ... This code inducts variable i twice inside the loop body, so i is a multi-step induction variable. Pointer promotion makes the Listing B.17 code strictly equivalent. Listing B.17 Multi-Step Equivalent C Code ... short tab1[MAX]; short tab2[MAX]; ... for(i=0 ; i<MAX ; ) { *(&tab1 + 2*i) = 0 ; i++; *(&tab2 + 2*i) = 1 ; i++; } ... The optimizer detects derived IVs for each value of the multi-step basic IV: • The expression (&tab1 + 2*i) defines derived induction variables for the initial value of i, • The expression (&tab2 + 2*i) defines derived induction variables for the first step value of i (that is, i+1). Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 235 Freescale Semiconductor, Inc. MWEntComp.book Page 236 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction At this stage, any of several strategies could transform the multi-step IVs. The default strategy is to de-correlate all the derived IVs. On one hand, this tends to increase the need for registers. On the other hand, this reduces false data dependencies and increases finegrain parallelism of the code. The induction process changes the code to the form of Listing B.18, which is equivalent and more efficient. Listing B.18 Better Multi-Step Equivalent C Code ... short tab1[MAX]; short tab2[MAX]; short* pt1 = &tab1; short* pt2 = &tab2 + 2 ... for(i=0 ; i<MAX ; i+=2) { *pt1 = 0 ; *pt2 = 1; pt1 = pt1 + 4; pt2 = pt2 + 4; } ... The loop now contains two indexed accesses, so index induction happens twice. Listing B.19 shows the result. Listing B.19 Multi-Step C Code with Induction ... short tab1[MAX]; short tab2[MAX]; ... for(i=0 ; i<MAX ; ) { tab1[i] = 0 ; i++; tab2[i] = 1; i++; } ... If there is no transformation of multi-step IVs, the compiler generates the assembly code of Listing B.20. The loop body contains 13 instructions, including three nop instructions. Listing B.20 Assembly Code without Multi-Step Induction ... 236 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 237 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction DW_2 move.w #40,r6 nop adda r6,sp DW_5 sub d0,d0,d0 doen3 #<5 dosetup3 L5 move.w #<1,d1 adda #>-20,sp,r1 adda #>-40,sp,r3 loopstart3 L5 move.l d0,r0 nop asla r0 adda r1,r0 sub d0,d0,d2 move.w d2,(r0) inc d0 move.l d0,r2 nop asla r2 adda r3,r2 move.w d1,(r2) inc d0 loopend3 ... ;[7] ;[0] AGU stall ;[7] ;[15];CLR instruction ;[0] ;[0] ;[0] ;[0] ;[0] ;[16] ;[0] AGU stall ;[16] ;[16] ;[16];CLR instruction ;[16] ;[17] ;[18] ;[0] AGU stall ;[18] ;[18] ;[18] ;[19] Assembly Code with Multi-Step Induction However, transformation of the multi-step IVs leads to the assembly code of Listing B.21. The loop body contains four instructions, instead of 13. This code uses separate address registers to access arrays tab1 and tab2, each register gets inducted just once. Listing B.21 Assembly Code with Multi-Step Induction ... DW_2 move.w nop adda DW_5 adda adda doen3 #40,r6 r6,sp ;[7] ;[0] AGU stall ;[7] #>-38,sp,r0 #>-20,sp,r1 #<5 ;[18] ;[16] ;[0] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 237 Freescale Semiconductor, Inc. MWEntComp.book Page 238 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction dosetup3 L5 sub d0,d0,d0 move.w #<1,d1 loopstart3 ;[0] ;[0];CLR instruction ;[0] move.w move.w adda adda loopend3 ;[16] ;[18] ;[19] ;[19] L5 d0,(r1) d1,(r0) #<4,r1 #<4,r0 ... Composition of Induction Variables The C code of Listing B.22 corresponds to a diagonal access to a matrix. Listing B.22 Diagonal Access Initial C Code ... short tab[10][20]; ... for(i=0, j=0 ; i<10 ; ) { tab[i][j] = i ; i++ ; j+=2 ; } ... Pointer promotion makes the code of Listing B.23 strictly equivalent. Listing B.23 Diagonal Access Equivalent C Code ... short tab[10][20]; ... for(i=0, j=0 ; i<10 ; ) { *(&tab1 + 2*(20*i+j)) = i ; i++ ; j+=2 ; } ... Here, i and j are induction variables with different steps. The result of the linear combination (20*i+j) defines a third IV, and the same linear combination specifies the 238 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 239 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction step of this third IV: step = 20*1 + 2 = 22. Multiplying this expression by 2 yields a fourth IV, whose step is 2*22=44. The induction process changes the code to the equivalent, more efficient form of Listing B.24. Listing B.24 Diagonal Access Better C Code ... short tab[10][20]; short *pt = &tab[0][0]; ... for(i=0, j=0 ; i<10 ; ) { *pt = i ; i++ ; pt=pt+44; } ... The basis for index access is a linear combination of i and j, which are both loop induction variables, as Listing B.25 shows. Listing B.25 Diagonal Access Basis ... short tab[10][20]; ... for(i=0, j=0 ; i<10 ; ) { tab[i][j] = i ; i++ ; j+=2 ; } ... Without any transformation of composed IVs, the compiler generates the code of Listing B.26. The optimizer identified two components as loop-induction variables, storing (40*i) in register d2, and storing (4*i) in register d1. But the optimizer did not detect the sum of these IVs as yet another induction variable, so the loop body contains eight instructions: Listing B.26 Assembly Code without Composed Induction ... DW_2 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 239 Freescale Semiconductor, Inc. MWEntComp.book Page 240 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction move.w #400,r6 nop adda r6,sp DW_5 sub d0,d0,d0 sub d0,d0,d1 sub d0,d0,d2 doen3 #<10 dosetup3 L5 adda #>-400,sp,r1 loopstart3 L5 add d1,d2,d3 move.l d3,r0 nop adda r1,r0 move.w d0,(r0) add #<4,d1 inc d0 addnc.w #40,d2,d2 loopend3 L4 ... ;[7] ;[0] AGU stall ;[7] ;[14];CLR instruction ;[15];CLR instruction ;[15];CLR instruction ;[0] ;[0] ;[0] ;[15] ;[15] ;[0] AGU stall ;[15] ;[15] ;[17] ;[16] ;[16] However, transformation of composed IVs detects the linear combination of i, j, and the base offset tab as a new induction variable. This enhanced optimization leads to the code of Listing B.27. The loop body contains only three instructions, instead of eight. Listing B.27 Assembly Code with Composed Induction ... DW_2 move.w #400,r6 nop adda r6,sp DW_5 sub d0,d0,d0 adda #>-400,sp,r0 doen3 #<10 dosetup3 L5 nop loopstart3 L5 move.w d0,(r0) inc d0 adda #>44,r0,r0 loopend3 240 ;[7] ;[0] AGU stall ;[7] ;[14];CLR instruction ;[0] ;[0] ;[0] ;[0] L_D_6 ;[15] ;[16] ;[16] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 241 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction L4 ... Wraparound Variables A wraparound variable follows an induction law only after the first loop iteration. Listing B.28 is a dummy example. Listing B.28 Wraparound Variable Example ... wrap = f(...); ... i=0; for(...) { ...array[wrap]...; wrap = i; i++; } ... Variable wrap is a wraparound variable, because its value depends on that of the basic IV i, except for the first iteration of the loop. The standard induction scheme cannot transform such a variable. The solution consists of first peeling the loop once — moving one loop iteration outside the body. So transforming wraparound variables involves: 1. Detecting the wraparound pattern during the induction-process detection step. 2. Verifying that it is possible to peel the loop once, then memorizing the variable in the temporary data structure of the IV. 3. Peeling the loop once before the induction-process transformation step. Listing B.29 shows the result of loop peeling. The code no longer contains any wraparound variables, so a usual induction process is appropriate. Listing B.29 Wraparound Variable Peeled Away ... wrap = f(...); ... i=0; /*** first iteration peeled ***/ ...array[wrap]...; wrap = i; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 241 Freescale Semiconductor, Inc. MWEntComp.book Page 242 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction i++; /******************************/ for(...) { ...array[wrap]...; wrap = i; i++; } ... Listing B.30 shows equivalent code. Listing B.30 Wraparound Variable Equivalent Code ... wrap = f(...); ... i=0; ...array[wrap]...; i=1; for() { wrap = i-1; ...array[wrap]...; i++; } ... Monotonic Variables A monotonic variable is a special IV: its induction instruction is conditional, as the code of Listing B.31 shows. Listing B.31 Monotonic Variable Example ... for(...) { ... non_basic_iv = basic_iv * 3; if(...) { basic_iv=basic_iv+1; } } ... The CodeWarrior StarCore compiler handles such variables easily, as the related nonbasic IVs also can have conditional induction. Listing B.32 is an example. 242 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 243 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction Listing B.32 Conditional Induction Example ... for(...) { ... if(...) { basic_iv=basic_iv+1; non_basic_iv = non_basic_iv + 3; } } ... To the optimizer, there is no significant difference between non-conditional IVs and monotonic variables. Accordingly, the compiler produces very similar assembly code for the two variable types. Modulo-Induction Previous sections explained transformations of pure linear IVs. But many signal processing applications make use of modulo and bit-reverse operations. The induction process should include these non-linear IVs, to take advantage of the processor’s moduloaddressing capabilities. Listing B.33, for example, includes a modulo IV, and modulo-inducted behavior. Listing B.34 shows equivalent code, after pointer promotion. Listing B.33 Modulo Induction Example Source Code ... short tab[MAX]; ... for(i=0, j=0 ; j<MAX ; j++) { tab[i] = 0 ; i += 1; i = i % 8; } ... Listing B.34 Modulo Induction with Pointer Promotion ... short tab[MAX]; ... for(i=0, j=0 ; i<MAX ; j++) { *(&tab + 2*i) = 0 ; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 243 Freescale Semiconductor, Inc. MWEntComp.book Page 244 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction i=i+1; i=i%8; } ... In this code, the i variable is a basic modulo IV — an IV both incremented and modified by a modulo operation. These expressions also have modulo-inducted behavior: • (2*i) is a derived modulo IV, with step 2 and modulo operator 8*2=16. • (&tab + (2*i)) is more complex: – It behaves like an IV with step 2, – Its initial value is &tab, – Its value gets reset to &tab each time it reaches the threshold &tab + 16). This means that the code of Listing B.35 is equivalent. Listing B.35 Modulo Induction Equivalent Code ... short tab[MAX]; short* pt=&tab[0]; ... for(i=0, j=0 ; i<MAX ; j++) { *pt = 0 ; pt=pt+2; pt=pt-&tab; pt=pt%16; pt=pt+&tab; } ... This form corresponds with a modulo-addressing pattern applied to pointer pt, with base equal to &tab, and modulo operator equal to 16. Modulo-Induction Result In the code of Listing B.36, i is the index for modulo access. Listing B.36 Modulo Access Index ... short tab[MAX]; ... for(i=0, j=0 ; j<MAX ; j++) { 244 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 245 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction tab[i] = 0 ; i += 1; i = i % 8; } ... As soon as possible, the compiler substitutes conditional subtraction for the modulo operator, in order to generate the code of Listing B.37. (Otherwise, the compiler would have to call Qmod32 or Qmod16 runtime, resulting in less efficient code.) Listing B.37 Assembly Code without Modulo Induction ... DW_2 adda #<24,sp DW_3 adda #>-24,sp,r0 doen3 #<10 dosetup3 L5 sub d0,d0,d0 move.l r0,d1 adda #>-24,sp,r1 move.l r1,d2 loopstart3 L5 move.l d1,r0 nop move.w d0,(r0) adda #<2,r0 move.l r0,d1 sub d2,d1,d3 cmpgt.w #<15,d3 jf L7 sub #<16,d1 L7 nop nop nop loopend3 L4 ... ;[7] ;[15] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[0] ;[0] ;[15] ;[0] AGU stall ;[15] ;[16] ;[16] ;[16] ;[16] ;[16] ;[16] ;[0] L_L_1 ;[0] L_L_1 ;[0] L_C_1 But transformation of the modulo induction makes use of the StarCore modulo-addressing mode, as in the code of Listing B.38. Notice the instructions bmset and bmclr, which control modulo addressing mode. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 245 Freescale Semiconductor, Inc. MWEntComp.book Page 246 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction Listing B.38 Assembly Code with Modulo Induction ... DW_3 adda #>-24,sp,r0 move.w #<16,m0 bmset #8,mctl.l doen3 #<10 dosetup3 L5 sub d0,d0,d0 adda #>-24,sp,r8 loopstart3 L5 move.w d0,(r0) nop adda #<2,r0 loopend3 L4 bmclr #15,mctl.l ... ;[15] ;[0] ;[0] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[15] ;[16] ;[16] ;[0] Modulo IV Classes The classes of modulo IVs are: • Basic — a variable both incremented and modified by a modulo operator, as Listing B.33 shows. • Derived through multiplication — a non-basic IV derived from a basic modulo IV by means of a multiplication. • Non-basic — a variable derived from a basic (non-modulo) IV by means of a modulo operator, as Listing B.39 shows. • Multi-step — a variable in a sequence of modulo induction, in either of two patterns: – A basic IV that is both a modulo and a multi-step IV — a sequence of increment / modulo instruction pairs, as Listing B.40 shows. – A non-basic modulo IV derived from a standard multi-step IV, as Listing B.41 shows. Listing B.39 Non-Basic Modulo IV Example ... i = 0 ; j = 0 ; for(j=0 ; j<10 ; j++) { tab[i%8] = 0 ; 246 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 247 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction i += 1; } ... Listing B.40 Multi-Step Modulo IV, Pattern 1 ... i = 0 ; j = 0 ; for(j=0 ; j<60 tab[i] = 0 i += 1; i = i % 8; tab[i] = 0 i += 1; i = i % tab[i] = 0 i += 1; i = i % 8; } ... ; j++) { ; ; 8; ; Listing B.41 Multi-Step Modulo IV, Pattern 2 ... i = 0 ; j = 0 ; for(j=0 ; j<60 ; j++) { tab[i%8] = 0 ; i += 1; tab[i%8] = 0 ; i += 1; tab[i%8] = 0 ; i += 1; } ... Modulo IV Limitations These limitations apply to modulo IVs: • The compiler cannot transform non-basic IVs derived from modulo basic IVs through addition of a constant or invariant. (The exception is the addition of a base Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 247 Freescale Semiconductor, Inc. MWEntComp.book Page 248 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction address with an inducted offset). The only way the compiler can apply the modulo operation is to subtract the constant/invariant, perform the modulo operation, then immediately add back the constant/invariant. Any efficiency gain in code would not be significant. • The compiler does not recognize an IV derived from a modulo basic IV or modulo non-basic IV by means of a modulo instruction. • The compiler does not permit composition of a modulo IV with any other IV (whether basic or non-basic). Conditional Subtraction StarCore processors do not allow direct mapping of an actual modulo operation, and jumping to a corresponding subroutine is not efficient. However, conditional subtraction often is available as a micro-instruction. If so, depending on certain other conditions, it makes sense to replace the modulo instruction with conditional subtraction. For example, the conditional subtraction: var = var csub cst is equivalent to: if (var>=cst) var = var - cst If the input value var is within the appropriate range (0, 2*cst), this modulo instruction is equivalent: var = var % cst Replacing a modulo operation by an equivalent conditional subtraction is possible only if: 1. The induction step is positive, 2. The compiler can compute the initial value of the input variable at compile time, and 3. The value of the input variable is not out of range. If these three conditions are not satisfied, the compiler leaves the modulo operation unchanged. Modulo Pointer/Array Value after Loop An application may re-use the value of a modulo pointer or array after a loop. Listing B.42 shows the most natural way to write such an application. This is the case of a modulo array, in which a macro often replaces the sequence of increment/modulo operations. 248 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 249 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction Listing B.42 Inefficient C Code Example ... int* fct_2() { #pragma noinline int j int l int* pt = 0; = 0; = 0; l=0; for (j=0; j<5; j++) { tab[l]=j; l++; l=l%3; } return(&tab[l]); } ... As this code reuses the l modulo index and the modulo pointer outside the loop, the generated assembly code (Listing B.43) is not efficient. Listing B.43 Inefficient Assembly Code ... _fct_2 type func OPT_SPEED [ sub d0,d0,d0 sub d0,d0,d3 doen3 #<5 dosetup3 L25 ] [ move.l #_tab,r0 move.w #<3,d4 ] [ bmset #8,mctl.l move.w #<12,m0 ] nop move.l #_tab,r8 falign loopstart3 L25 ;[32];CLR instruction ;[33];CLR instruction ;[0] ;[0] ;[34] ;[0] ;[35] ;[35] ;[0]A_1 ;[0] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 249 Freescale Semiconductor, Inc. MWEntComp.book Page 250 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction [ inc inc move.l d0 d3 d3,(r0)+ ;[35] ;[36] ;[35] cmpgt d0,d4 iff sub d4,d0,d0 loopend3 ;[35] ;[35] bmclr move.l ;[0] ;[38] ] [ #15,mctl.l d0,r0 ] nop ;[0] AGU stall [ asl2a rtsd r0 ;[38] ;[38] adda r8,r0 ;[38] ] global F_fct_2_end ... F_fct_2_end A better solution is using the modulo operator, as Listing B.44 shows. This avoids actual modification of main induction variable l. The compiler simply derives the array-access index, and the address to be returned, from l. This simple modification yields the improved assembly code of Listing B.45, saving both code size and cycles: Listing B.44 Modulo Operator Solution ... int* fct_2() { #pragma noinline int j int l int* pt = 0; = 0; = 0; l=0; for (j=0; j<5; j++) { tab[l%3]=j; l++; } return(&tab[l%3]); 250 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 251 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction } ... Listing B.45 Improved Assembly Code ... global _fct_2 align 16 _fct_2 type func OPT_SPEED [ sub d0,d0,d4 doensh3 #<5 ] move.l #_tab,r0 [ bmset #8,mctl.l move.w #<12,m0 ] nop move.l #_tab,r8 loopstart3 [ inc d4 move.l d4,(r0)+ ] loopend3 [ bmclr #15,mctl.l rtsd ] move.l #_tab+8,r0 global F_fct_2_end ... ;[33];CLR instruction ;[0] ;[34] ;[35] ;[35] ;[0]A_1 ;[0] ;[36] ;[35] ;[0] ;[38] ;[38] F_fct_2_end Bit-Reverse Induction Another non-linear addressing mode common for DSPs is bit-reverse. This mode, especially useful for implementing efficient FFT algorithms, consists of computing sums in reversed bit order, the bits being mirrored. The optimizer performs bit reverse on a given number of bits (usually a power of 2), propagating carry from the MSB to the LSB. Table B.1 illustrates this operation for a bit reverse on 4 bits. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 251 Freescale Semiconductor, Inc. MWEntComp.book Page 252 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction Table B.1 Bit-Reverse Examples Standard Arithmetic Bit-Reverse Arithmetic Binary Value Decimal Value Binary Value Decimal Value 0000 0 0000 0 0001 1 1000 8 0010 2 0100 4 0011 3 1100 12 0100 4 0010 2 0101 5 1010 10 0110 6 0110 6 0111 7 1110 14 1000 8 0001 1 1001 9 1001 9 1010 10 0101 5 1011 11 1101 13 1100 12 0011 3 1101 13 1011 11 1110 14 0111 7 1111 15 1111 15 As bit-reverse mode does not correspond to any standard C operation, it requires its own approach, based on the dedicated prototype function: int br_inc(int x, int n) where: x The index to be subjected to bit-reverse modification. n The width of the operation: a power of 2. 252 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 253 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction This function returns the x value bitreverse-incremented. Using this function to update an index increments the bit-reversed pointer. (A brnset instruction indicates that the address register must be handled with bit-reverse mode.) If prototype.h is not part of the include files, the compiler instead uses the br_inc function. Bit-Reverse Result The code of Listing B.46 computes an inducted, bit-reversed index; computes a standard inducted index; then dumps both indexes. Listing B.46 Bit-Reverse Initial C Code ... int tab[32]; #pragma align tab 64 ... br_index=0; for(index=0; index<max_val; index++) { tab[br_index]=index; tab2[index]=br_index; br_index=br_inc(br_index, max_val); } ... If bit-reverse induction is disabled, you either must call the br_inc function from inside the loop body, or inline equivalent code. Listing B.47 shows the resulting code for one dump loop body. The function calls prevent any mapping of this loop onto a hardware loop resource, so the code is inefficient. Listing B.47 Bit-Reverse Disabled: Inefficient Assembly Code ... L1 [ move.l move.l d0,r1 #_tab,r2 ;[28,1] ;[28,1] move.l move.l d0,(r0) (sp-32),d1 ;[28,1] ;[29,1] asl2a r1 ;[28,1] adda jsrd r2,r1 _br_inc ;[28,1] ;[29,1] ] [ ] [ Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 253 Freescale Semiconductor, Inc. MWEntComp.book Page 254 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction ] move.l d2,(r1) ;[28,1] move.l move.l (sp-20),r0 (sp-24),d3 ;[28,1] ;[30,1] sub move.l #1,d3 (sp-28),d2 ;[30,1] ;[30,1] tstgt inc adda move.l d3 d2 #<4,r0 d3,(sp-24) ;[27,1] ;[30,1] ;[28,1] ;[30,1] btd <L1 ;[27,1] [ ] [ ] [ ] ... Listing B.48 shows the better assembly code possible if you enable bit-reverse mode. Access for the tab[] array uses a bit-reverse pointer (register r1), set before the loop and reset after the loop. A bit-reverse increment in register r0 handles the initial bitreverse index br_index, but the mode set and reset take place inside the loop body. Listing B.48 Bit-Reverse Enabled: Efficient Assembly Code ... bmset #16,mctl.l nop move.l #_tab2,r2 falign loopstart3 ;[29,1] ;[0,0]A_1 ;[28,1] L9 [ inc move.l bmset d1 d1,(r1)+n0 #1,mctl.l ;[28,1] ;[28,1] ;[29,1] nop nop move.l ro,(r2)+ ;[0,0]A_1 ;[0,0] MCTL stall ;[28,1] adda bmclr n0,r0 #15,mctl.l ;[29,1] ;[29,1] ] [ ] nop loopend3 254 ;[0,0] MCTL stall Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 255 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction bmclr (#240,mctl.l ;[0,1] ... Bit-Reverse Limitations Bit-reverse mode is safe only for global arrays. Using it on local or dynamically allocated arrays leads to invalid, unpredictable behavior. Furthermore, using bit-reverse addressing mode to access an array means that the array must be correctly aligned. The alignment value depends on: 1. The number of bits used to compute the bit-reverse increment: the maximum value for the bit-reverse index. 2. The type of data stored in the array: its size. For example, the maximum value for a bit-reverse of 4 bits is 16. If the array contains the short data type (2 bytes), the array must be aligned on 64. Bit-Reverse Prototype Listing B.49 is prototype code equivalent to the br_inc and br_swap functions. Listing B.49 Bit-Reverse Prototype Code ... /*swap of input reversing the n LSB, so that max_val=1<<n*/ int br_swap(int input, int max_val) { int nb_bits; /*number of bits affected by BR mode*/ int mask; int masked_val; int swap; int temp; /*mask to extract subpart of input*/ /*affected by BR mode*/ /*initial subpart of affected input*/ /*swapped subpart of affected input*/ /*temporary value for swa operation*/ int output; int bit_index; int bit_value; /*output value, swapped input*/ /*index of bits during computation*/ /*value represented by bit n (1<<n)*/ /*number of bits necessary: precomputed*/ nb_bits=0; while((max_val>>nb_bits)!=1) { nb_bits++; } /*mask set: nb_bits=1, others=0*/ Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 255 Freescale Semiconductor, Inc. MWEntComp.book Page 256 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction mask=max_val-1; /*subpart of input to be swapped*/ masked_val=input&mask; /*effective swap of this masked part*/ swap=0; for(bit_index=0; bit_index<nb_bits; bit_index++) { bit_value=(1<<bit_index); tmp=(bit_value&masked_val)/bit_value; swap+=(tmp*(1<<(nb_bits-bit_index-1))); } /*output computed*/ output=(input-masked_val+swap); return(output); } /*bit reverse increment of input, reversing the n LSB, so that*/ /*max_val=1<<n*/ int br_inc(int input, int max_val) { int output; int nb_bits; int mask; /*number of bits necessary: precomputed*/ nb_bits=0; while((max_val>>nb_bits)!=1) { nb_bits++; { /*mask set: nb_bits=1, others=0*/ mask=max_val-1; output=br_swap(input, max_val); output++; output=br_swap(output, max_val); /*As bit reverse operates on 2^nb_bits, we want all bits*/ /*outside the range [2^nb_bits..0] to be unmodified,*/ /*wrap around [2^nb_bits..0]*/ output= (input & -mask) | (output & mask); return(output); } ... 256 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 257 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction Min/Max Function Induction If the result of a min or max function is known to be linear inside a loop, that result is a non-basic IV. One possibility is that the min or max function combines two induction variables that follow the same linear law (that is, the same step value). In such a case, the result of the min or max function corresponds with one of the two IVs, so that result is linear inside the loop. In Figure B.1’s depiction, the value of function min(IV1, IV2) is a non-basic IV. This means that induction-related optimizations may be possible. Figure B.1 Min Function Result Is an IV Loop Domain IV1 min(IV1, IV2) IV2 But if the function’s behavior inside the loop is non-linear, as Figure B.2 depicts, the result is not an IV, so induction-related optimizations are not possible. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 257 Freescale Semiconductor, Inc. MWEntComp.book Page 258 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction Figure B.2 Min Function Result Not an IV Loop Domain IV1 min(IV1, IV2) IV2 Consider the loop nest of Listing B.50. In the nest, iNumSamples and iStatIndx are loop invariant. The only modification of i and j values takes place in the induction instructions of the loop-control statements. Listing B.50 Min/Max Initial C Code ... for (i=0; i<iNumSamples; i++) { ... for (j = 5; (j >= 0) && (iStatIndx - i + j >= 0); j--) ... } ... If you do not enable min/max induction, control of the inner loop comes from a boolean expression. This boolean expression combines variable j on one side, with a linear expression involving i and j on the other side. Consequently, there can be two assembly representations: • The basis of representation 1 is a hardware loop that j controls, with an early exit conditioned by the value of the linear expression (iStatIndx - i + j). Assembly code is not efficient, as the early loop exit impacts code size and speed. Furthermore, it is necessary to recompute the value of the linear expression for each loop iteration. • The basis of representation 2 is a loop that the boolean expression’s result controls, without any early exit. For this case, the code of Listing B.51 can replace the control of the inner loop. 258 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 259 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction Listing B.51 Loop Control Replacement without Min/Max Induction for(j=5; min(j, iStatIndx-i+j)>=0); j--) { ... } The representation 2 solution is more efficient, as it eliminates the need for an early exit from the inside loop. However, a non-linear expression controls this loop, so it may be difficult to map this loop on a hardware loop. Accordingly, the resulting assembly code shows that the inner loop is mapped on a software loop. But if you enable min/max induction, the optimizer recognizes that j and (iStandIndx - i + j) are two induction variables of the inner loop, based on the same step. This means that behavior inside the loop always is linear, so the optimizer can transform the code to that of Listing B.52. Listing B.52 Loop Control Replacement with Min/Max Induction ... temp= min(j, iStatIndx-i+j); for(j=5; temp>=0; j--) { ... temp--; } ... The result of the min() function is an IV of the inner loop, with step -1. Initialization of this result can be outside the loop. Consequently, the inner loop is a hardware loop that induction variable temp controls. Simplifying Redundant IVs Two induction variables are redundant if they obey the same induction law and can be substituted for each other. More precisely: • Basic IVs are redundant if: – Their initial values before entering the loop are the same or differ by a constant (literal) value). – They evolve in the same way at each iteration of the loop, that is, have similar steps and induction footprints. (The induction footprint is the relative location of induction and uses, especially for a multi-step IV). • Non-basic IV are redundant if: – They are derived from the same basic IV or from redundant basic IVs. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 259 Freescale Semiconductor, Inc. MWEntComp.book Page 260 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction – They make use of the same linear features (gain and offset). As redundant IVs may appear both in the initial object code, and after some steps of the induction process, it is important to detect and replace them. This leads to more efficient code, this reduces code size, and this reduces register pressure. Redundant Basic IVs The optimizer compares initialization instructions and steps to detect redundant basic IVs. When the optimizer finds two basic IVs to be redundant, it merges the two sets of related non-basic IVs and modifies related instructions. In the code below, i and j are redundant basic IVs: ... for (i=0, j=0; square(i+j) <= 25; i++, j++) { k *= k; } ... The code can be transformed so as to be equivalent to this code: ... for (i=0; square(2*i) <= 25; i++) { k *= k; } ... Redundant Non-Basic IVs The optimizer compares expressions as linear combinations of basic IVs to detect redundant non-basic IVs. If the optimizer finds non-basic IVs to be redundant, it replaces one with the other, removing the IV no longer used. In the dummy code of Listing B.53, for example, the two successive expressions derived from i are equivalent and redundant. Listing B.53 Redundant Non-Basic IV Dummy Code ... short tab[10][20]; ... for(i=0; i<10 ; i+=2) { ...use(2*(20*i)+4)...; ... ...use(4*((10*i)+1))...; ... 260 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 261 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction } ... Without any attempt to detect redundant non-basic IVs, the optimizer would consider these two expressions to be different. This would lead to computing two IVs. Another reason it is important to detect redundant non-basic IVs is that detecting equivalent linear expressions can be useful during the extraction of sequential memory accesses. The simplification of redundant non-basic IVs leads to the equivalent form of Listing B.54. Listing B.54 Equivalent Non-Basic IV Code ... short tab[10][20]; ... for(i=0, j=0 ; i<10 ; i+=2) { ...use(2*(20*i)+4)...; ... ...use(2*(20*i)+4)...; ... } ... Simplification Results Listing B.55 contains two redundant expressions derived form the i basic IV. Listing B.55 Redundant Expression Example Code ... short tab[10]; int i; for(i=0; i<10 ; i+=2) { tab[i]=(2*(20*i)+4); tab[i+1]=(4*((10*i)+1)); } ... Listing B.56 shows the generated assembly code without simplification of these redundant non-basic IVs. Setting and updating the corresponding values require the two registers Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 261 Freescale Semiconductor, Inc. MWEntComp.book Page 262 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Single-loop Induction $d1 and $d2. Furthermore, the compiler detected the opportunity for a double move, so the code needs yet a third register. Listing B.56 Assembly Code without Simplification ... DW3 move.w #<4,d1 move.w #<4,d2 adda #>-24,sp,r0 doen3 #<5 dosetup3 L5 loopstart3 ;[16] ;[15] ;[15] ;[0] ;[0] tfr move.2w adda addnc.w addnc.w loopend3 ;[15] ;[15] ;[14] ;[14] ;[14] L5 d1,d3 d2:d3,(r0) #<4,r0 #80,d2,d2 #80,d1,d1 L4 ... Simplifying the redundant IVs reduces the number of registers and reduces the number of instructions in the loop body. The optimizer also activated the double move. Listing B.57 shows the resulting assembly code. Listing B.57 Assembly Code with Simplification ... DW_3 move.w #<4,d0 adda #>-24,sp,r0 doen3 #<5 dosetup3 L5 loopstart3 L5 tfr d0,d1 move.2w d0:d1,(r0) adda #<4,r0 addnc.w #80,d0,d0 loopend3 ... 262 ;[16] ;[15] ;[0] ;[0] ;[15] ;[15] ;[14] ;[14] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 263 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations Sequential Accesses, Related Optimizations An important loop-optimizer step is detecting sequential accesses (so-called sequences of memory accesses), then making appropriate transformations. A sequence of memory accesses is a set of memory accesses arising in either a loop or a loop nest, such that: • They concern the same array or base pointer, • The distance (or stride) between two successive memory accesses must be computable as a literal value at compile time. In other words, the related IV must be derived linearly from the same basic IV (or from redundant ones), due to the same linear gain, but have a different literal linear offset. (Theoretically, this condition is not necessary, but it is a practical necessity for reducing code size and increasing code efficiency.) • The pointer must not be redefined between the two accesses, particularly by means of aliases. The optimizer structures sequences in order to reflect the control flow graph, as Figure B.3 depicts. The optimizer also detects sequences based on modulo IVs. Figure B.3 Sequence Structure ... for (...) { ...tab[i]..., i=i+3; if(...)...tab[i]...; else...tab[i+1]...; i=i+1; ...tab[i]...; } ... stride = 0 ...tab[i].. stride = 3 ...tab[i].. stride = 4 ...tab[i+1].. stride = 1 stride = 1 ...tab[i].. Sequence detection is a powerful tool for optimizing loops. It also is important for identifying candidates for several smart loop transformations, including: Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 263 Freescale Semiconductor, Inc. MWEntComp.book Page 264 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations • Monitoring multi-step IV transformations, to find a good tradeoff among register pressure, code mobility, and code size. • Identifying candidates for multiple moves (access packing). • Simplifying redundant memory accesses. • Refining data dependency analysis. • Software pipelining. Transformation Control Strategy The compiler transforms the sequences from the initial scheme with multiple pointers or address registers, according to the optimization criterion (speed or size). The sequence of Listing B.58, for example, is based on a multi-step IV. It includes accesses to different slots of the same array. The rewritten example is Listing B.59. Listing B.58 Initial Sequence Example ... short tab[MAX]; ... for(i=0 ; i<MAX ; ) { tab[i] = 0 ; i++; tab[i] = 1; i++; } ... Listing B.59 Rewritten Sequence Example ... short tab[MAX]; ... for(i=0 ; i<MAX ; ) { *(&tab + 2*i) = 0 ; i++; *(&tab + 2*i) = 1 ; i++; } ... 264 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 265 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations Two Possible Schemes Listing B.60 shows one scheme: using independent variables for each different value of the mother IV. This scheme increases register pressure, but improves code mobility (opportunities for parallelism). The optimizer chooses this scheme if you optimize for speed, provided that the register pressure will not cause spills; Listing B.60 Independent-Variable Scheme Code ... short tab[MAX]; short* pt1 = &tab; short* pt2 = &tab + 2; ... for(i=0 ; i<MAX ; i+=2) { *pt1 = 0 ; *pt2 = 1; pt1 = pt1 + 4; pt2 = pt2 + 4; } ... Listing B.61 shows the other scheme: using a single pointer. This scheme results in a poor code mobility, but reduces register pressure. The optimizer chooses this scheme if you optimize for size. Listing B.61 Single-Pointer Scheme Code ... short tab[MAX]; short* pt = &tab; ... for(i=0 ; i<MAX ; i+=2) { *pt = 0 ; pt = pt + 2; *pt = 1; pt = pt + 2; } ... Assembly Results The source code of Listing B.62 involves single sequence. (For the purpose of this example, slight modification of the strides avoids multiple moves.) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 265 Freescale Semiconductor, Inc. MWEntComp.book Page 266 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations Listing B.62 One-Sequence Source Code Example ... short tab[MAX]; ... for(i=0 ; i<MAX ; ) { tab[i] = 0 ; i++; tab[i] = 1; i+=2; } ... The default behavior for multi-step IVs, with optimization for speed, yields a first version of assembly code: Listing B.63. This code uses address registers $r0 and $r1 to perform the related accesses: Listing B.63 Speed-Optimized Assembly Code ... DW_3 adda #>-22,sp,r0 adda #>-24,sp,r1 doen3 #<4 dosetup3 L5 sub d0,d0,d0 move.w #<1,d1 loopstart3 L5 move.w d0,(r1) move.w d1,(r0) adda #<6,r1 adda #<6,r0 loopend3 ... ;[19] ;[17] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[17] ;[19] ;[20] ;[20] Specifying optimization level 3 yields the assembly code of Listing B.64. This code is better, as each loop iteration is performed in one cycle. Listing B.64 Speed-Optimized Assembly Code, Level 3 ... DW3 [ move.w adda 266 #3,n3 #>-22,sp,r1 ;[0] ;[17] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 267 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations ] DW4 [ adda move.w #>-24,sp,r4 #<1,d2 ;[15] ;[0] ] loopstart3 L5 DW5 [ move.w move.w d3,(r4)+n3 d2,(r1)+n3 ;[15] ;[18] ] loopend3 ... Listing B.65 shows assembly code optimized for size. This involves transformation of sequences, so access uses only register $r0. Listing B.65 Size-Optimized Assembly Code ... DW_3 adda #>-24,sp,r0 doen3 #<4 dosetup3 L5 move.w #<1,d0 loopstart3 L5 sub d0,d0,d1 move.w d1,(r0) adda #<2,r0 move.w d0,(r0) adda #<4,r0 loopend3 ... ;[17] ;[0] ;[0] ;[0] ;[17];CLR instruction ;[17] ;[18] ;[19] ;[20] Specifying optimization level 3 yields the code of Listing B.66. Although loop iteration requires two cycles, this code saves one address register, as well as the related initialization instruction: Listing B.66 Size-Optimized Assembly Code, Level 3 ... DW_3 adda #>-24,sp,r0 ;[17] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 267 Freescale Semiconductor, Inc. MWEntComp.book Page 268 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations move.w #2,n3 move.w #<1,d1 loopstart3 ;[0] ;[19] move.w d2,(r0)+ move.w d1,(r0)+n3 loopend3 ;[18] ;[20] L5 ... Sequential Access Examples This section shows several examples of indexed-access-mode (IAM) that the optimizer handles. (It handles equivalent programs based on indirect addressing mode, that is, with pointers, the same way.) The listings are: Listing B.67, Listing B.68, Listing B.69, Listing B.70, Listing B.71, Listing B.72, Listing B.73, Listing B.74, and Listing B.75. Listing B.67 IAM: Derived from Multi-Step IV ... for(...){ ...array[i]...; i++; ...array[i]...; i++; ...array[i]...; i++; } ... Listing B.68 IAM: Derived from Simple Step IV, Different Static Offsets ... for(...){ ...array[i] ...; ...array[i+1] ...; ...array[i+2] ...; i+=3; } ... Listing B.69 IAM: Row-Major Access, Derived from Multi-Step IV for(...){ 268 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 269 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations for(...){ ...array[i][j] ...; j++; ...array[i][j] ...; j++; ...array[i][j] ...; j++; } i++; } ... Listing B.70 IAM: Row-Major Access, Derived from Simple IV, Different Static Offsets for(...){ for(...){ ...array[i][j] ...; ...array[i][j+1] ...; ...array[i][j+2] ...; j+=3; } i++; } ... Listing B.71 IAM: Diagonal Access, Composed IV ... for(...){ ...array[i][j] ...; ...array[i+1][j+1] ...; ...array[i+2][j+2] ...; j+=3; i+=3; } ... Listing B.72 IAM: Partial Column-Major Access ... for(...){ for(...){ ...array[i][j] ...; ...array[i+1][j] ...; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 269 Freescale Semiconductor, Inc. MWEntComp.book Page 270 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations ...array[i+2][j] ...; j++; } i+=3; } ... In Listing B.73, note that the defined structure type Struct_tab contains an array of integer tab. Listing B.73 IAM: Sequential Accesses to Arrays in Data Structures ... typedef struct Type_struct_tab *Pt_struct_tab; typedef struct Type_struct_tab { char letter; int tab[MAX]; int number; } Struct_tab; ... This lets the optimizer detect successive accesses to the array contents as a sequential memory access, as Listing B.74 shows. Listing B.74 IAM: Sequential Memory Accesses for Arrays ... Struct_tab array_tab; ... for(ind1=0 ; ind1<MAX/2; ind1+=2) { array_tab.tab[ind1]=ind1; array_tab.tab[ind1+1]=ind1+1; } ... Given the same structured type of Listing B.73, the optimizer also can detect accesses to simple array fields as a sequential memory access. This produces code such as that of Listing B.75. Listing B.75 IAM: Sequential Memory Accesses for Fields ... Struct_tab array[10]; ... for(ind1=0 ; ind1<MAX/2; ind1+=2) { 270 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 271 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations array[ind1].letter='f'; array[ind1].number=ind1; } ... Simplifying Redundant Memory Accesses Many programs have redundant memory accesses, particularly regarding scalarization. Other redundant memory accesses occur, but can be difficult to detect: • The memory accesses must be made at the same address, and • No interleaved access can modify memory contents or the pointer. Within a restricted scope, however, the optimizer’s sequence detector can help prove that two memory accesses are redundant. The first case is Listing B.76: code writes to a memory slot, then reads from that slot. Instructions A[i]=X; and Z=A[i]; pertain to the same memory location, but no actual modification occurs between the write access and the related read access. This makes it possible to modify those instructions, reducing the number of memory accesses inside the loop body, as Listing B.77 shows. Listing B.76 Redundant Memory Access: Coupled Write, Read ... for() { ... A[i]=X; i++; A[i]=Y; i--; Z=A[i]; ... i++; } ... Listing B.77 Improved Coupled Write, Read ... for() { ... A[i]=X; i++; A[i]=Y; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 271 Freescale Semiconductor, Inc. MWEntComp.book Page 272 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations i--; Z=X; ... i++; } ... Listing B.78 shows the same kind of redundancy in a case of multiple memory reads. The same simplification leads to the code of Listing B.79. Listing B.78 Redundant Memory Access: Multiple Reads ... for() { ... X=A[i]; i++; A[i]=Y; i--; Z=A[i]; ... i++; } ... Listing B.79 Improved Multiple Reads ... for() { ... X=A[i]; i++; A[i]=Y; i--; Z=X; ... i++; } ... Listing B.80 shows initial Code that contains a redundant access. Listing B.80 Redundant-Access Initial C Code ... 272 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 273 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations int tab[MAX]; int i,j; for(i=0, j=0; j<MAX; j++) { tab[i]=j; ... tab[i+1]=1; ... c=tab[i]; i++; } ... /*write access at slot i*/ /*redundant read access at same slot*/ If the optimizer does not eliminate this redundant write/read memory access, the compiler produces the assembly code of Listing B.81. This code includes both a write access and read access (assignment to _c). Listing B.81 Redundant-Access Assembly Code ... DW_5 sub d0,d0,d0 adda #>-36,sp,r0 adda #>-40,sp,r1 doen3 #<10 dosetup3 L5 move.w #<1,d1 loopstart3 L5 move.l d0,(r1) move.l d1,(r0) move.l (r1),d2 move.l d2,<_c inc d0 adda #<4,r1 adda #<4,r0 loopend3 ... ;[14];CLR instruction ;[17] ;[15] ;[0] ;[0] ;[0] ;[15] ;[17] ;[19] ;[19] ;[20] ;[20] ;[20] Detecting and simplifying such a redundant access eliminates the second access: the system saves the stored value in a register for the _c assignment. Listing B.82 shows the optimized assembly code. Listing B.82 Redundant-Access Simplified Assembly Code ... Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 273 Freescale Semiconductor, Inc. MWEntComp.book Page 274 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations DW_5 sub d0,d0,d0 adda #>-36,sp,r0 adda #>-40,sp,r1 doen3 #<10 dosetup3 L5 move.w #<1,d1 loopstart3 L5 move.l d0,(r1) move.l d1,(r0) move.l d0,<_c inc d0 adda #<4,r1 adda #<4,r0 loopend3 L4 ... ;[14];CLR instruction ;[17] ;[15] ;[0] ;[0] ;[0] ;[15] ;[17] ;[19] ;[20] ;[20] ;[20] Access Packing (Vectorization) The StarCore architecture’s multiple-move feature means that just one instruction can perform several moves from or to registers. Such multiple-move instructions amount to a specific type of vectorization. Their effectiveness depends on: • Type of data, • Alignment of the related memory segment, • Stride between memory slots, • Domination relation between successive accesses, and • Number of moves to be done at the same time (two or four). Sequences of memory accesses meet most conditions for using multiple-move instructions. However, the compiler also needs data about memory-segment alignment, and it can obtain part of this data from symbol tables and data-flow information. Pragmas may be additional sources of such data, and help ensure alignment of function-argument array addresses Access Packing Illustration To illustrate the effect of access packing, consider the initial source code from the sequential-access example: Listing B.58. Without access packing, the compiler transforms this example source code to the assembly code of Listing B.83. 274 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 275 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations Listing B.83 Assembly Code without Packing ... DW_3 adda #>-22,sp,r0 adda #>-24,sp,r1 doen3 #<5 dosetup3 L5 sub d0,d0,d0 move.w #<1,d1 loopstart3 L5 move.w d0,(r1) move.w d1,(r0) adda #<4,r1 adda #<4,r0 loopend3 L4 ... ;[18] ;[16] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[16] ;[18] ;[19] ;[19] But this transformed code sequence matches several considerations for access packing: • It concerns short integers. • It concerns an aligned array. • Its initial value for variable i, when first entering the loop, is known at compile time. Furthermore, this value corresponds to an aligned memory slot (one whose address is a multiple value of the cell size). • The code preserves alignment from one loop iteration to the next. • It concerns two consecutive memory slots. • No specific data dependency prevents this packing. Access packing yields the optimized code of Listing B.84: one double move replaces the two simple moves. This means that code execution requires one address register instead of two. Listing B.84 Assembly Code with Packing ... DW_3 adda #>-24,sp,r0 doensh3 #<5 sub d0,d0,d0 move.w #<1,d1 loopstart3 L5 ;[16] ;[0] ;[0];CLR instruction ;[0] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 275 Freescale Semiconductor, Inc. MWEntComp.book Page 276 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations move.2w d0:d1,(r0) adda #<4,r0 loopend3 ;[16] ;[19] ... Access Packing Examples This section shows several examples of the optimizer’s access packing. The listings are: Listing B.85 Access Packing: Array and Multi-Step IV ... short array[10]; ... i=0; for(...){ ... ... = array[i]; i++; ... = array[i]; i++; ... } ... Listing B.86 Access Packing: Array and Simple Step IV, Different Static Offsets ... short array[10]; ... i=0; for(...){ ... ... = array[i]; ... ... = array[i+1]; ... i+=2; } ... 276 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 277 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations Listing B.87 Access Packing: Pointer and Multi-Step IV ... void fct(short ptr[]) { #pragma align *ptr 4 ... for(...){ ... ... = *ptr; ptr++; ... ... = *ptr; ptr++; ... } ... } ... Listing B.88 Access Packing: Pointer and Simple Step IV, Different Static Offsets ... void fct(short ptr[]) { #pragma align *ptr 4 ... for(...){ ... ... = *ptr; ... ... = *(ptr+1); ptr+=2; ... } ... } ... Listing B.89 Access Packing: Extracted from Complex Sequences ... int array[40]; ... for(i=0; i<16;){ Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 277 Freescale Semiconductor, Inc. MWEntComp.book Page 278 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations tab[i] i++; tab[i] i+=3; tab[i] i+=5; tab[i] i+=3; tab[i] i++; tab[i] i++; = ...; = ...; <---|- first pair of packed accesses <---- = ...; = ...; = ...; = ...; <---|- second pair of packed accesses <---- } ... Listing B.90 Access Packing: Interleaved Accesses on Different Arrays ... int array1[10]; int array2[10]; ... for(i=0; i<5; i+=2){ acc1=L_add(acc1, L_mult(array1[i], array2[i])); acc2=L_add(acc2, L_mult(array1[i+1], array2[i+1])); } ... In Listing B.91, note that the defined structure type Struct_tab contains an array of integer tab. This lets the optimizer pack the successive accesses to the array contents, yielding the code of Listing B.92. Listing B.91 Access Packing: Arrays in Structures ... typedef struct Type_struct_tab *Pt_struct_tab; typedef struct Type_struct_tab { long x; short tab[MAX]; } Struct_tab; ... 278 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 279 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Sequential Accesses, Related Optimizations Listing B.92 Improved Code for Arrays in Structures ... Struct_tab array_tab; ... for(ind1=0 ; ind1<MAX/2; ind1+=2) { array_tab.tab[ind1]=ind1; array_tab.tab[ind1+1]=ind1+1; } ... In Listing B.93, the structure describes a complex data type. This means that the optimizer can detect access to the array fields as a packed access, yielding the code of Listing B.94. Listing B.93 Access Packing: Simple Fields in Structures ... typedef struct Type_cplx *Pt_cplx; typedef struct Type_cplx { short re; short im; } Struct_cplx; ... Listing B.94 Improved Code for Fields in Structures ... Struct_cplx array[10]; ... for(ind1=0 ; ind1<MAX/2; ind1+=2) { array[ind1].re=0; array[ind1].im=1; } ... Although multidimensional accesses are more complex, sometimes the optimizer can packed them as well. The Listing B.95 example accesses a linearized 4x4 array. Moreover, the code structure is a two-level nest of loops. Both the inner and outer loops modify the pointer for actual access. Analysis shows that the outer-loop modification of the pointer preserves the alignment. This means that it is valid to pack the four accesses to consecutive columns. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 279 Freescale Semiconductor, Inc. MWEntComp.book Page 280 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Listing B.95 Access Packing: Multi-Dimensional Accesses ... void fct(..., short* block, ...) { #pragma align *block 8 ... int k, i; ... p_b = block; for(k=0; k<4; k++) { ... for(i=0; i<4; i++) { ... = *(p_b+(4*i)+0); ... = *(p_b+(4*i)+1); ... = *(p_b+(4*i)+2); ... = *(p_b+(4*i)+3); } ... p_b+=16; /*this modification ... } ... /*i is the row index*/ /*1st columns accessed /*2nd columns accessed /*3rd columns accessed /*4th columns accessed in in in in row*/ row*/ row*/ row*/ to change row*/ Cross-Loop Induction Previous explanations covered induction for one loop at a time, mainly optimizing innermost loops. While single-loop induction does improve code, it may not lead to the most efficient assembly code possible. However, the compiler’s high-level optimizer includes powerful cross-loop induction mechanisms that can optimize entire loop nests. Simple Matrix Example Listing B.96 includes a simple access to a two-dimensional matrix. Listing B.96 Simple Matrix Access: Initial C Code ... short matrix[20][10]; ... for(ind1=0; ind1<20; ind1++) { for(ind2=0; ind2<10; ind2++) { matrix[ind1][ind2]=0; 280 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 281 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction } } ... Single-loop induction yields the assembly code of Listing B.97. This code uses two address registers: • $r0 to store the initial address of each row. The outer loop updates this register. • $r1 to access each row. The inner loop updates this register. The compiler computes the $r1 initial value in the outer loop (that is, for each outer-loop iteration), using register $r0. Listing B.97 Simple Matrix Access: Single-Loop Induction Assembly Code ... DW_2 move.w #400,r6 nop adda r6,sp DW_5 move.w #<0,r0 doen2 #<20 dosetup2 L10 sub d0,d0,d0 loopstart2 L10 adda #>-400,sp,r1 adda r0,r1 doensh3 #<10 nop loopstart3 L9 move.w d0,(r1) adda #<2,r1 loopend3 L6 adda #<20,r0 nop loopend2 L8 ... ;[7] ;[0] AGU stall ;[7] ;[16] ;[0] ;[0] ;[0];CLR instruction ;[16] ;[16] ;[0] ;[0] L_D_3 ;[16] ;[15] ;[14] ;[0] L_L_4 Figure B.4 depicts this two-register access of the single-loop assembly code. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 281 Freescale Semiconductor, Inc. MWEntComp.book Page 282 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Figure B.4 Two-Dimensional Matrix Access $r0 (column index) $r1 (row index) However, the single-loop assembly code includes redundancy, as one address register could perform the full matrix access. Furthermore, if the array representation in memory is linear, as Figure B.5 depicts, the register need not be updated in the outer loop. Figure B.5 One-Dimensional Matrix Access The cross-loop induction mechanisms take advantage of these considerations to produce the improved code of Listing B.98. The number of instructions in the inner loop is the same, but the outer loop now contains one actual instruction. This means that the nest is a perfect loop nest; just one address register is needed. Listing B.98 Simple Matrix Access: Cross-Loop Induction Assembly Code ... DW_5 adda #>-400,sp,r0 doen2 #<20 dosetup2 L10 sub d0,d0,d0 loopstart2 L10 doensh3 #<10 nop loopstart3 L9 move.w d0,(r0) adda #<2,r0 loopend3 L6 nop 282 ;[0] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[0] L_D_3 ;[16] ;[15] ;[0] L_N_1 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 283 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction nop loopend2 ;[0] L_L_4 L8 ... However, it is possible to collapse this loop nest even further. You compiler delivers the optimized code of Listing B.99. The hardware loop requirement drops from two to one, and the code is more compact. Listing B.99 Simple Matrix Access: Further Collapsed Assembly Code ... DW_5 adda #>-400,sp,r0 move.w #200,r1 nop doensh3 r1 sub d0,d0,d0 loopstart3 L9 move.w d0,(r0) adda #<2,r0 loopend3 L8 ... ;[0] ;[0] ;[0] AGU stall ;[0] ;[0];CLR instruction ;[16] ;[15] Linear Domains Scope Although the example above is specific and trivial, its general approach applies to any multi-dimensional access performed in loop nests, provided that: 1. Loop bounds are invariant or induction variables, in the enclosing loop. This corresponds to the description of linear iteration spaces. 2. Execution does not bypass the loop — or that it is possible to determine the number of bypassed iterations at compile time. These conditions track with many loop nests in DSP applications, and the CodeWarrior compiler handles the corresponding access patterns. Figure B.6 depicts these access patterns for a two-dimensional iteration space (that is, for two consecutive loops of a nest). Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 283 Freescale Semiconductor, Inc. MWEntComp.book Page 284 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Figure B.6 Access Patterns Full Rectangular (Block) Triangular Truncated Triangular Diagonal Trapezoidal High-Dimension, Mixed Nests, Perfect Loop Nests There is no limit to the number of dimensions (that is, the depth of the nest). The compiler can handle loop nests with different successive domain shapes. For example, the compiler can process and optimize triangular access to successive layers of a cube, as Figure B.7 depicts. 284 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 285 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Figure B.7 Three-Dimension, Mixed Access ... for(i=0; i<MAX; i++) { for(j=0; j<MAX; j++) { for(k=0; k<j; k++) { ...tab[i][j][k]...; } } } ... k j i Furthermore, this approach handles any kind of nest, whether perfect or not. The only restrictions concern re-using induction variables across the nest. Cross-File Examples The remaining subsections of this appendix explain several types of cross-file optimizations. Partial (Block) Matrix Access Listing B.100 is C source code that accesses only a sub-block of a matrix. The traversal is not linear: the pointer must jump from the end of one row to the beginning of the next. But the cross-loop optimizer still succeeds, using just one address register to monitor access across the nest. Listing B.101 shows the corresponding assembly code. Listing B.100 Partial (Block) Matrix Access Source Code ... short matrix[20][10]; ... for(i=0; i<20; i++) { for(j=2; j<5; j++) { Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 285 Freescale Semiconductor, Inc. MWEntComp.book Page 286 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction matrix[i][j]=0; } } ... Listing B.101 Partial (Block) Matrix Access Assembly Code ... DW_5 adda #>-396,sp,r0 doen2 #<20 dosetup2 L10 sub d0,d0,d0 loopstart2 L10 doensh3 #<3 nop loopstart3 L9 move.w d0,(r0) adda #<2,r0 loopend3 L6 adda #<14,r0 nop loopend2 L8 ... ;[0] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[0] L_D_3 ;[16] ;[15] ;[0] ;[0] L_L_4 Triangular Access Figure B.8 depicts a two-dimensional triangular access, with a superior-triangle domain. Figure B.8 Triangular Domain (Superior) ... short matrix[MAX][MAX]; ... for(i=i; i<MAX; i++) { for(j=i; j<MAX; j++) { ... 286 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 287 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction A single-loop induction process leads to the assembly code of Listing B.102. Notice that: • The inner loop contains two instructions; the outer loop contains many instructions. • The inner-loop bypass test still exists, even though it never can be active. • Computing the address across the nest requires four data registers and four address registers. Listing B.102 Triangular Access: Single-Loop Assembly Code ... DW_5 sub d0,d0,d0 sub d0,d0,d1 sub d0,d0,d2 doen2 #<10 dosetup2 L10 loopstart2 L10 cmpgt.w #<9,d1 jt L4 move.l d1,r0 move.w #<10,r1 nop suba r0,r1 add d2,d0,d3 move.l d3,r2 adda #>-200,sp,r3 adda r3,r2 doensh3 r1 sub d0,d0,d3 loopstart3 L9 move.w d3,(r2) adda #<2,r2 loopend3 L6 L4 add #<2,d2 inc d1 add #<20,d0 loopend2 ... ;[16];CLR instruction ;[15];CLR instruction ;[16];CLR instruction ;[0] ;[0] ;[15] ;[15] ;[0] ;[0] ;[0] AGU stall ;[0] ;[16] ;[16] ;[16] ;[16] ;[0] ;[0];CLR instruction ;[16] ;[15] ;[14] ;[14] ;[14] Listing B.103 shows the assembly code after cross-loop induction. The improvements are: • Fewer instructions in the outer loop. • Removal of the useless inner-loop bypass test. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 287 Freescale Semiconductor, Inc. MWEntComp.book Page 288 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction • Using register $r0 to monitor the triangular-access address across the nest. The code sets the $r0 value before the loop nest, inducting it in both the inner and outer loops. The induction in the outer loop is second order (that is, the step is an induction variable in the outer loop, stored in $r1). This reduces the number of data registers to two. Listing B.103 Triangular Access: Cross-Loop Assembly Code ... DW_5 sub d0,d0,d0 adda #>-200,sp,r0 move.w #<2,r1 doen2 #<10 dosetup2 L10 sub d0,d0,d1 loopstart2 L10 move.l d0,r2 move.w #<10,r3 nop suba r2,r3 doensh3 r3 nop loopstart3 L9 move.w d1,(r0) adda #<2,r0 loopend3 L6 adda r1,r0 inc d0 adda #<2,r1 loopend2 L8 ... ;[15];CLR instruction ;[0] ;[0] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[0] ;[0] AGU stall ;[0] ;[0] ;[0] L_D_3 ;[16] ;[15] ;[0] ;[14] ;[0] Shifted Triangular Access The next example is another two-dimension, triangular access: the inferior-triangle domain that Figure B.9 depicts. The inner-loop highest bound is different from the main diagonal line (in other words, the bound is shifted). 288 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 289 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Figure B.9 Shifted Triangular Domain (Inferior) ... short matrix[MAX][MAX]; ... for(i=3; i<MAX; i++) { for(j=0; j<=i-3; j++) { ... The single-loop induction process leads to the assembly code of Listing B.104. This code has the same characteristics as the corresponding code for the triangular-access example (Listing B.102), including the never-used bypass test. Listing B.104 Shifted Triangular Access: Single-Loop Assembly Code ... DW_5 move.w #<60,r0 sub d0,d0,d0 doen2 #<7 dosetup2 L10 loopstart2 L10 tstge d0 jf L4 addnc.w #<1,d0,d1 adda #>-200,sp,r1 adda r0,r1 doensh3 d1 sub d0,d0,d1 nop loopstart3 L9 move.w d1,(r1) adda #<2,r1 loopend3 L6 L4 inc d0 adda #<20,r0 nop loopend2 L8 ... ;[16] ;[15];CLR instruction ;[0] ;[0] ;[15] ;[15] ;[0] ;[16] ;[16] ;[0] ;[0];CLR instruction ;[0] L_D_3 ;[16] ;[15] ;[14] ;[14] ;[0] L_C_1 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 289 Freescale Semiconductor, Inc. MWEntComp.book Page 290 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Listing B.105 shows the assembly code after cross-loop induction. The improvements are the same kind as for the triangular-access example (Listing B.103), even though fewer instructions could be removed. Listing B.105 Shifted Triangular Access: Cross-Loop Assembly Code ... DW_5 sub d0,d0,d0 adda #>-140,sp,r0 move.w #<18,r1 doen2 #<7 dosetup2 L10 sub d0,d0,d2 loopstart2 L10 addnc.w #<1,d0,d1 doensh3 d1 nop nop loopstart3 L9 move.w d2,(r0) adda #<2,r0 loopend3 L6 adda r1,r0 inc d0 suba #<2,r1 loopend2 L8 ... ;[15];CLR instruction ;[0] ;[0] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[0] ;[0] L_D_3 ;[0] L_D_3 ;[16] ;[15] ;[0] ;[14] ;[0] Truncated Triangular Access Figure B.10 depicts a truncated, two-dimensional triangular access. 290 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 291 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Figure B.10 Truncated Triangular Access ... short matrix[MAX][MAX]; ... for(i=3; i<MAX; i++) { for(j=0; j<i; j++) { ... The single-loop induction process leads to the assembly code of Listing B.106. This code includes the same optimization potential as the previous triangular-access examples, including the never-used bypass test. Listing B.106 Truncated Triangular Access: Single-Loop Assembly Code ... DW_5 move.w #<3,d0 move.w #<60,r0 doen2 #<7 dosetup2 L10 loopstart2 L10 tstgt d0 jf L4 move.l d0,r1 adda #>-200,sp,r2 adda r0,r2 doensh3 r1 sub d0,d0,d1 loopstart3 L9 move.w d1,(r2) adda #<2,r2 loopend3 L6 L4 inc d0 adda #<20,r0 nop loopend2 L8 ... ;[14] ;[16] ;[0] ;[0] ;[15] ;[15] ;[0] ;[16] ;[16] ;[0] ;[0];CLR instruction ;[16] ;[15] ;[14] ;[14] ;[0] L_C_1 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 291 Freescale Semiconductor, Inc. MWEntComp.book Page 292 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Cross-loop induction process yields the assembly code of Listing B.107, which shows improvements like those of the two previous examples. Listing B.107 Truncated Triangular Access: Cross-Loop Assembly Code ... DW_5 move.w #<3,d0 adda #>-140,sp,r0 move.w #<14,r1 doen2 #<7 dosetup2 L10 sub d0,d0,d1 loopstart2 L10 move.l d0,r2 nop doensh3 r2 nop loopstart3 L9 move.w d1,(r0) adda #<2,r0 loopend3 L6 adda r1,r0 inc d0 suba #<2,r1 loopend2 L8 ... ;[14] ;[0] ;[0] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[0] AGU stall ;[0] ;[0] L_D_3 ;[16] ;[15] ;[0] ;[14] ;[0] Mixed High-Dimension Access The last example shows how the optimizer handles cases of additional dimensions and mixed domain shapes. Figure B.11 depicts a three-dimension, mixed square/triangular iteration space. (This example is almost identical to that of Figure B.7: the only difference is in the third for statement.) 292 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 293 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction Figure B.11 Three-Dimension, Mixed Access 2 ... for(i=0; i<MAX; i++) { for(j=0; j<MAX; j++) { for(k=0; k<=j; k++) { ...tab[i][j][k]...; } } } ... k j i Single-loop induction leads to the code of Listing B.108. Listing B.108 Three-Dimension Mixed Access: Single-Loop Assembly Code ... DW_2 move.w #2000,r6 nop adda r6,sp DW_5 sub d0,d0,d0 doen1 #<10 dosetup1 L15 loopstart1 L15 sub d0,d0,d1 move.l d0,r0 doen2 #<10 dosetup2 L14 falign loopstart2 L14 tstge d1 ;[7] ;[0] AGU stall ;[7] ;[17];CLR instruction ;[0] ;[0] ;[15];CLR instruction ;[17] ;[0] ;[0] ;[16] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 293 Freescale Semiconductor, Inc. MWEntComp.book Page 294 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction jf L6 addnc.w #<1,d1,d2 adda #>-2000,sp,r1 adda r0,r1 doensh3 d2 sub d0,d0,d2 nop loopstart3 ;[16] ;[0] ;[17] ;[17] ;[0] ;[0];CLR instruction ;[0] L_D_3 move.w d2,(r1) adda #<2,r1 loopend3 ;[17] ;[16] inc d1 adda #<20,r0 nop loopend2 ;[15] ;[15] ;[0] L_C_1 addnc.w #200,d0,d0 loopend1 ;[14] L13 L8 L6 L10 L12 ... Cross-loop induction yields the improved code of Listing B.109. The improvements are similar to those of previous examples: • When MAX equals 10, the number-of-cycles gain, with optimization level 1, is about 8.8 percent (2147 instead of 2354). • With optimization level 3, the gain is 7.5% (1364 cycles instead of 1474). Listing B.109 Three-Dimension Mixed Access: Cross-Loop Assembly Code ... DW_5 sub d0,d0,d0 move.w #<18,d1 adda #>-2000,sp,r0 doen1 #<10 dosetup1 L15 sub d0,d0,d3 loopstart1 L15 doen2 #<10 dosetup2 L14 falign loopstart2 294 ;[15];CLR instruction ;[0] ;[0] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[0] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 295 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction L14 addnc.w #<1,d0,d2 doensh3 d2 nop nop loopstart3 ;[0] ;[0] ;[0] L_D_3 ;[0] L_D_3 move.w d3,(r0) adda #<2,r0 loopend3 ;[17] ;[16] move.l nop adda inc sub loopend2 ;[0] ;[0] AGU stall ;[0] ;[15] ;[0] L13 L8 d1,r1 r1,r0 d0 #<2,d1 L10 tfr d3,d0 move.w #<18,d1 loopend1 ;[0] ;[0] L12 ... Controlling Cross-Loop Induction Although cross-loop induction usually leads to more efficient code, its uncontrolled application sometimes decreases performance: • Increasing the lifetime of variables inside a loop nest may increase register pressure beyond limits. The consequence is spills inside the loop nest. • As the optimizer applies cross-loop induction from the innermost to the outermost loops, the process affects all variables, regardless of their use in enclosing loops. This may lead to less than optimal patterns. For these reasons, the compiler controls cross-loop induction according to the resources available and the optimization options you specify: • If you optimize for size, the compiler disables cross-loop induction in loops that contain only IVs never recombined with the IVs of the enclosing loops. • If you optimize for speed, the compiler monitors the estimated register pressure. As soon as the pressure may lead to spills, the compiler disables cross-loop induction in loops that contain only IVs never recombined with the IVs of the enclosing loops. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 295 Freescale Semiconductor, Inc. MWEntComp.book Page 296 Monday, September 27, 2004 2:17 PM Induction-Related Loop Optimizations Cross-Loop Induction 296 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 297 Monday, September 27, 2004 2:17 PM C Loop Restructuring and Reordering This appendix explains transformations that modify the structure of loops or computations inside loops. Loop restructuring is like unrolling and pipelining, as it preserves the order of computation. Loop reordering is like interchanging and jamming, as it changes the relative execution order for loop-nest iterations. Consequently: • Both restructuring and reordering require accurate control: the optimizer should apply them only if they will produce a gain. This point is critical for transformations that can interact strongly with other optimizations. Controlling such a transformation may require information not easily available at the time, such as register pressure and intrinsic code parallelism. • Reordering techniques require proof of validity, with regard to data dependency. The only loop optimizations of early versions of the compiler were loop collapse and loop peeling. Furthermore, the compiler performed those optimizations automatically. Unrolling and unroll-and-jam were available, but only through pragmas. Recent compiler releases, however, include automatic control of unrolling: the compiler applies this optimization only if it improves code speed. This automatic control involves these restructuring techniques: • Loop collapse — reducing perfect loop nests to single loops where possible, • Loop peeling — transforming wrap-around variables. • Loop unrolling — replicating loop bodies. Dedicated pragmas provide two additional reordering techniques: • Loop unroll-and-jam — unrolling outer loops and merging copies of inner loops. • Loop multi-sampling — a combination of loop-unroll-and-jam and loop unrolling that yields results similar to those of the common multi-sampling technique. Loop-Collapse To improve the results of full-matrix access regularization, the CodeWarrior compiler implements a simple collapse of perfect loop nests. This leaves the loop structure Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 297 Freescale Semiconductor, Inc. MWEntComp.book Page 298 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop-Collapse unchanged, but modifies the nest’s actual loop count. The code generation stage modifies the loop structure: the single loop makes possible pure linear accesses. This simple collapse transformation consists of: • Removing all useless induction instructions, to reveal perfect loop nests, • Collapsing perfect loop nests recursively, processing innermost loops first. NOTE This transformation does not make use of induction variable (IV) information. The optimizer performs this transformation after the induction process transforms all loops of an entry. In other words, if the optimizer finds that two consecutive loops of a nest form a perfect nest, it: • Multiplies the outer loop count by the inner-loop count, and • Sets the inner-loop-count to one. The optimizer performs this process recursively, from innermost loops toward outer-most loops. During code generation, the compiler removes useless back edges of the flow graphs. Consider the example source code of Listing C.1. Listing C.1 Example Source Code ... short matrix[MAX][MAX]; ... for(ind1=0; ind1<MAX; ind1++) { for(ind2=0; ind2<MAX; ind2++) { matrix[ind1][ind2]=0; } } ... The optimizer first uses loop normalization and cross-loop induction to transform this code to that of Listing C.2. Listing C.2 First Code Transformation ... short matrix[MAX][MAX]; ... pt=matrix; ... ind1=0; 298 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 299 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop-Collapse for(lc1=MAX; lc1>0; lc1--) { ind2=0; for(lc2=MAX; lc2>0; lc2--) { *pt=0; pt = pt + 2; ind2++; } ind1++; } ... Next, the optimizer simplifies useless induction variables, yielding this Listing C.3 code: Listing C.3 Second Code Transformation ... short matrix[MAX][MAX]; ... pt=matrix; ... for(lc1=MAX; lc1>0; lc1--) { for(lc2=MAX; lc2>0; lc2--) { *pt=0; pt = pt + 2; } } ... But the Listing C.3 transformation makes the loop nest perfect. This means that the optimizer can collapse the loop nest, yielding the final code of Listing C.4. Listing C.4 Final Code Transformation ... short matrix[MAX][MAX]; ... pt=matrix; ... for(lc1=MAX*MAX; lc1>0; lc1--) { *pt=0; pt = pt + 2; } ... Applying cross-loop induction to the full-matrix-access example yields the code of Listing C.5. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 299 Freescale Semiconductor, Inc. MWEntComp.book Page 300 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop-Collapse Listing C.5 Full Matrix Access: Cross-Loop Induction ... DW_5 adda #>-200,sp,r0 doen2 #<10 dosetup2 L10 sub d0,d0,d0 loopstart2 L10 doensh3 #<10 nop loopstart3 L9 move.w d0,(r0) adda #<2,r0 loopend3 L6 nop nop loopend2 L8 ... ;[0] ;[0] ;[0] ;[0];CLR instruction ;[0] ;[0] L_D_3 ;[17] ;[16] ;[0] L_N_1 ;[0] L_L_4 But in this case, it is possible to collapse the loop nest, producing the optimized code of Listing C.6. This reduces the number of cycles the loop needs, and reduces the number of hardware loops from two to one. Listing C.6 Full Matrix Access: Cross-Loop Induction with Loop Collapse ... DW_5 adda #>-200,sp,r0 move.w #100,r1 nop doensh3 r1 sub d0,d0,d0 loopstart3 L9 move.w d0,(r0) adda #<2,r0 loopend3 L8 ... 300 ;[0] ;[0] ;[0] AGU stall ;[0] ;[0];CLR instruction ;[17] ;[16] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 301 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Peeling Loop Peeling Loop peeling is necessary to process wraparound variables. This transformation consists of: • Verifying that peeling the loop is possible, • Replicating the loop body several times before the loop itself, according to the peeling factor, and • Modifying loop control by subtracting the peeling factor from the loop-count initial value. The optimizer considers loop peeling if it detects at least one wraparound variable in a loop. The optimizer performs loop peeling after detecting any induction variables (IVs) in the loop, before transforming any of the IVs. (Table C.1 summarizes IV types.) Table C.1 Induction Variable Types IV Type Description Basic Linear Variable decremented or incremented within a loop body by a constant value (a literal) or by a loop-invariant step. Static IV whose step is a constant (literal) Dynamic IV whose step is an invariant value. Multi-Step IV incremented more than once within a loop body. Non-Basic (Derived) IV derived from any other IV by means of a linear function, where the gain is a constant value and the offset is either a constant or a loop-invariant value. Composed IV that is a linear combination of any other IVs, where gains are constant values and the offset is either a constant or a loopinvariant value The example code of Listing C.7 has a wraparound variable, so is suitable for peeling. Peeling the loop once yields the optimized code of Listing C.8. Listing C.7 Loop Peeling: Example Source Code ... wrap = f(...); ... i=0; for(...) { Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 301 Freescale Semiconductor, Inc. MWEntComp.book Page 302 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unrolling ...array[wrap]...; wrap = i; i++; } ... Listing C.8 Loop Peeling: Optimized Code ... wrap = f(...); ... i=0; /*** first iteration peeled ***/ ...array[wrap]...; wrap = i; i++; /******************************/ for(...) { ...array[wrap]...; wrap = i; i++; } ... Loop peeling lets the optimizer apply the induction process to wraparound variables. This makes the assembly code of the related loop similar to loop assembly code after simplifying regular induction variables. Loop Unrolling Unrolling is replicating the body of a loop several times. The main advantage of highlevel unrolling, for a StarCore-type processor, is exposing patterns that the high-level loop optimizer can transform, potentially: • Increasing the use of the multiple-move instructions, • Reducing the number of memory accesses, and • Improving code parallelism. However, gains due only to high-level unrolling are speculative. Actual improvements result from multiple moves, redundant memory accesses, and other high-level optimizations that loop unrolling makes feasible. Accordingly, loop unrolling should take place before loop optimization. 302 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 303 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unrolling But this prevents predicting actual improvement beforehand. Nothing can be known about actual code details, such as registers allocated, instructions selected, or opportunities for parallelism. Furthermore, it is possible for unrolling to increase register pressure. A worst case would be exceeding the register limit, introducing memory spills inside the loop. Accordingly, appropriate control is necessary. This control must involve both the highlevel code representation and the low-level target architecture features, such as mapping and scheduling improvements. In your CodeWarrior software, a high-level scheduler controls loop unrolling. This scheduler assesses the best unrolling factor for a given loop, estimating the effect of code generation and parallelism on the loop’s intermediate code. Loop Unrolling Restrictions These restrictions apply to automatic unrolling: 1. The loop count must be a multiple of the unrolling factor, either: a. A static loop count (that is, known at compile time), or b. A dynamic loop count with divisibility properties specified by cw_assert or by a loop count pragma. 2. The loop body must not contain any control flow: there can be only one block in the loop body. 3. The loop body must not contain any call to a function returning structure. 4. The loop body must not contain any modulo induction variable. Loop Unrolling Example The -u compiler option enables loop unrolling: • -u0 — specifies no unrolling (level 0). • -u2 — specifies unrolling of simpler loops, according to the decision of the highlevel scheduler. • -u4 — specifies unrolling of as many loops as possible, according to the decision of the high-level scheduler. If a local pragma specifies loop unrolling, that unrolling always takes place, regardless of the high-level scheduler decision. Code optimization for size (-Os) always disables loop unrolling. The innermost loop of the Listing C.9 example code includes opportunities for loopunrolling improvements. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 303 Freescale Semiconductor, Inc. MWEntComp.book Page 304 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unrolling Listing C.9 Loop Unrolling: Example Source Code ... Word16 y[L_WINDOW]; ... do { ... if (...) { ... for (i = 0; i < L_WINDOW; i++) { y[i] = shr (y[i], 2); } } } while (...); ... If the compiler generates assembly code without unrolling loops, it produces the assembly code of Listing C.10. The code for the innermost loop is between the keywords loopstart3 and loopend3. Pipelining positions some related instructions before and after the loop. The loop body contains two packets. Listing C.10 Loop Unrolling: Assembly Code without Unrolling PL000 [ mac d1,d1,d6 adda #>-504,sp,r0 ] [ cmpeq d2,d6 tfra r0,r1 ] [ move.f (r1)+,d1 bf <L21 ] [ asrr #<2,d1 suba #<1,r3 move.f #<4,d5 ] [ add d4,d5,d4 doensh3 r3 ] [ move.w #<1,d5 304 ;[146] 1%=1 ;[153] B6 ;[0] ;[0] B6 ;[153] 0%=0 B6 ;[148] ;[153] 1%=0 ;[0] ;[149] ;[149] ;[0] ;[150] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 305 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unrolling adda #<1,r3 ;[0] ] skipls PL002 nop loopstart3 ;[0] ;[0] L_C_2 moves.f move.f d1,(r0)+ (r1)+,d1 ;[154] 2%=1 ;[153] 0%=0 asrr #<2,d1 loopend3 PL002 moves.f d1,(r0)+ L35 ;[153] 1%=0 [ ] ;[154] 2%=1 But if the compiler applies unrolling with the maximum unrolling factor (the -u4 compiler option), the scheduler confirms that it makes sense to unroll the loop by 4. Listing C.11 shows the resulting assembly code. The loop body contains only two packets, including one with two 4-moves. Moreover, this code makes possible a much more aggressive pipeliner transformation. Listing C.11 Loop Unrolling: Assembly Code with Unrolling PL000 [ mac adda ] [ cmpeq tfra ] [ ift add ifa bf ] [ move.4f doensh3 ] [ asrr asrr asrr move.w ] asrr d4,d4,d3 #>-504,sp,r0 ;[146] 1%=1 ;[153] B6 d5,d3 r0,r2 ;[0] ;[0] B6 d1,d7,d1 <L21 ;[149] B6 ;[148] (r2)+,d8:d9:d10:d11 #59 ;[153] 0%=0 ;[0] @II2 #<2,d8 #<2,d9 #<2,d10 #<1,d2 ;[153] 1%=0 ;[153] 1%=0 ;[153] 1%=0 ;[150] #<2,d11 ;[153] 1%=0 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 305 Freescale Semiconductor, Inc. MWEntComp.book Page 306 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unroll-and-Jam loopstart3 [ moves.4f d8:d9:d10:d11,(r0)+ move.4f (r2)+,d8:d9:d10:d11 ;[154] 2%=1 ;[153] 0%=0 asrr asrr asrr asrr ;[153] ;[153] ;[153] ;[153] ] [ #<2,d8 #<2,d9 #<2,d10 #<2,d11 1%=0 1%=0 1%=0 1%=0 ] loopend3 moves.4f d8:d9:d10:d11,(r0)+ ;[154] 2%=1 L35 Loop Unroll-and-Jam The loop unroll-and-jam transformation consists of: • Unrolling the enclosing loop a certain number of times; this number is the unrolland-jam factor (UJF). • Merging multiple instances of the enclosed loop. The goal of this optimization is increasing the parallelism available for pipelining. Unlike loop unrolling, loop unroll-and-jam changes the execution order of the loop iterations. Figure C.1 depicts this change, for UJF 3. 306 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 307 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unroll-and-Jam Figure C.1 Iteration Space Before and After Unroll-and-Jam Key: inner index outer index before after This re-ordering means that the unroll-and-jam transformation is not always valid: it could violate data-dependency constraints. Such a violation may occur as soon as an iteration (i0,j0) depends on any iteration (i,j), such that: • j > j0 and i >= ujf * (i0 % ujf), • j > j0 and i >= ujf * (1 + (i0 % ujf)), or • j = j0 and i > i0 But the compiler considers a simpler condition. The main difference between initial and unrolled-and-jammed shapes occurs upon reaching any iteration i0 of the outer loop. Contrary to the initial case, the (i0 % ujf) previous ones are not completed in the unrolled-and-jammed nest. Consequently, a avoiding a dependency violation requires that iteration i0 of the upper loop must not depend on any of the (i0 % ujf) previous ones. The UJF maximizes this quantity. Loop Unroll-and-Jam Restrictions The loop unroll-and-jam transformation is possible only for code nests that meet these restrictions: Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 307 Freescale Semiconductor, Inc. MWEntComp.book Page 308 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unroll-and-Jam 1. The loop counts of both enclosing and enclosed loops must be static values. 2. The loop count of the enclosing loop must be a multiple of the unrolling factor. 3. There must be only one enclosed loop. 4. The enclosed loop body must not contain any control flow: there can be only one block in the loop body, there cannot be any early exits. 5. Although the bodies the enclosing loop and the enclosed loop may contain calls to prototype functions, they may not contain calls to any other functions. 6. Neither the body of the enclosing loop nor the body of the enclosed loop may contain any modulo IV. Code optimization for size always disables the loop unroll-and-jam transformation. Unroll-and-Jam Example To enable this transformation, place the dedicated pragma after the head of the enclosed loop. Include the unroll-and-jam factor: 2 or 4, for StarCore processors. Follow the Listing C.12 syntax example. Listing C.12 Loop Unroll-and-Jam: Syntax ... for(...) { ... for(...) { #pragma loop_unroll_and_jam 4 ... } ... } ... Listing C.13 shows initial source code that contains a simple FIR loop nest. The compiler can consider L and N as constants; for this example, assume that L = 32 and N = 128. Listing C.13 Loop Unroll-and-Jam: Initial Source Code ... for (i=0; i<N; i++) { sum = 0; for (j=0; j<L; j++) { #pragma loop_unroll_and_jam 4 sum = L_add(sum,L_mult(input[i-j],FIR_COEF[j])); } output[i] = extract_h(sum); 308 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 309 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unroll-and-Jam } ... Without the pragma, the compiler produces the assembly code of Listing C.14. Nest execution requires 4480 cycles: ((1*31)+4)*128. Listing C.14 Loop Unroll-and-Jam: Assembly Code without Unroll-and-Jam ... [ doen2 #128 dosetup2 L10 ;[0,1] ;[0,1] move.l (sp-12),r5 move.l #_FIR_COEF,r4 move.w #64,r3 falign loopstart2 ;[36,1] ;[34,1] ;[0,1] sub doensh3 move.f ;[29,1];CLR instruction ;[0,0] @II1 ;[34,1] 0%=0 ] L10 [ d0,d0,d0 #31 (r1)-,d3 ] move.f (r4)+,d4 loopstart3 ;[34,1] 0%=0 mac move.f move.f d3,d4,d0 (r4)+,d4 (r1)-,d3 ;[34,1] 1%=1 ;[34,1] 0%=0 ;[34,1] 0%=0 d3,d4,d0 #>66,r1,r1 r3,r4 ;[34,1] 1%=1 ;[0,1] ;[0,1] [ ] loopend3 [ mac adda suba ] moves.f d0,(r5)+ loopend2 ;[36,1] ... With the pragma, the compiler produces the assembly code of Listing C.15. Nest execution requires 3200 cycles: ((3*31)+7)*32 — an efficiency gain of 28.5 percent. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 309 Freescale Semiconductor, Inc. MWEntComp.book Page 310 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Unroll-and-Jam Listing C.15 Loop Unroll-and-Jam: Assembly Code with Unroll-and-Jam ... [ doen2 #<32 dosetup2 L10 ;[0,1] ;[0,1] dosetup3 L9 move.l (sp-12),r12 ;[0,1] ;[36,1] move.l #_FIR_COEF,r2 ;[34,1] adda adda #>6,r1,r15 #>4,r1,r3 ;[0,1] ;[0,1] adda move.w #>2,r1,r4 #64,r0 ;[0,1] ;[0,1] ] [ ] [ ] [ ] falign loopstart2 L10 [ sub sub sub sub doen3 move.f d0,d0,d8 d0,d0,d9 d1,d1,d10 d1,d1,d11 #31 (r1)-,d5 ;[29,1];CLR instruction ;[29,1];CLR instruction ;[29,1];CLR instruction ;[29,1];CLR instruction ;[0,0] @II3 ;[34,1] 0%=0 move.f move.f (r4)-,d2 (r3)-,d0 ;[34,1] 0%=0 ;[34,1] 1%=0 ] [ ] [ falign loopstart3 L9 [ mac mac mac mac move.f move.f d3,d4,d8 d3,d4,d11 d0,d4,d10 d2,d4,d9 (r1)-,d5 (r4)-,d2 ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[34,1] 3%=1 3%=1 3%=1 3%=1 0%=0 0%=0 ] [ 310 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 311 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Multi-Sampling move.f move.f (r3)-,d0 (r15)-,d3 ;[34,1] 1%=0 ;[34,1] 1%=0 ] move.f (r2)+,d4 loopend3 ;[34,1] 2%=0 mac mac mac mac adda ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[0,1] [ d5,d4,d8 d3,d4,d11 d0,d4,d10 d2,d4,d9 #>72,r1,r1 3%=1 3%=1 3%=1 3%=1 ] [ moves.4f d8:d9:d10:d11,(r12)+ adda #>72,r4,r4 ;[36,1] ;[0,1] adda adda ;[0,1] ;[0,1] ] [ #>72,r3,r3 #>72,r15,r15 ] suba r0,r2 loopend2 ;[36,1] ... Loop Multi-Sampling The multi-sampling transformation, like unroll-and-jam, improves code parallelism for loop nests, leading to more efficient use of DSP resources. Programmers usually perform multi-sampling manually in assembly code, or before compilation. This transformation consists of: • Unrolling and jamming the nest, then • Unrolling the enclosed loop. This transformation exposes more opportunities for vectorizing memory accesses than does unroll-and-jam. Multi-Sampling Restrictions The multi-sampling transformation is possible only for code nests that meet these restrictions (the same as those for unroll-and-jam): 1. The loop counts of both enclosing and enclosed loops must be static values. 2. The loop count of the enclosing loop must be a multiple of the unrolling factor. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 311 Freescale Semiconductor, Inc. MWEntComp.book Page 312 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Multi-Sampling 3. There must be only one enclosed loop. 4. The enclosed loop body must not contain any control flow: there can be only one block in the loop body, there cannot be any early exits. 5. Although the bodies the enclosing loop and the enclosed loop may contain calls to prototype functions, they may not contain calls to any other functions. 6. Neither the body of the enclosing loop nor the body of the enclosed loop may contain any modulo IV. Code optimization for size always disables the multi-sampling transformation. Multi-Sampling Example To enable this transformation, place the dedicated pragma after the head of the enclosed loop. Include the unroll-and-jam factor: 2 or 4, for StarCore processors. Follow the syntax of Listing C.16. NOTE Although there is no automatic control for the unroll-and-jam stage, an automatic control does monitor unrolling the enclosed loop. This means that the mutt-sampling unrolling factor can be lower than the unroll-and-jam factor. Listing C.16 Loop Multi-Sampling: Syntax ... for(...) { ... for(...) { #pragma loop_multi_sample 4 ... } ... } ... This example starts with the same initial code as the unroll-and-jam example: Listing C.13. Without the multi-sample pragma, the compiler produces the same code as it did without the unroll-and-jam pragma: Listing C.14. Nest execution requires the same 4480 cycles: ((1*31)+4)*128. With the multi-sample pragma, the compiler produces the assembly code of Listing C.17. This code contains many packets of four to six instructions, including many multiple moves. Nest execution requires 1120 cycles: ((4*7)+7)*32 — an efficiency gain of about 75 percent. 312 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 313 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Multi-Sampling Listing C.17 Loop Multi-Sampling: Assembly Code with Multi-Sampling ... [ push push d6 d7 ;[0,0] ;[0,0] ] DW_2 [ dosetup3 L9 doen2 #<32 ;[0,1] ;[0,1] dosetup2 L10 tfra r1,r2 ;[0,1] ;[0,1] push push r6 r7 ;[0,0] ;[0,0] move.l tfra #_FIR_COEF,r5 r1,r4 ;[34,1] ;[0,1]] suba move.l #<6,r4 (sp-28),r7 ;[0,1] ;[36,1] suba move.w #<4,r1 #-4,n2 ;[0,1] ;[0,0] move.w move.w #64,r0 #-2,n3 ;[0,1] ;[0,0] ] [ ] [ ] DW_5 [ ] [ ] [ ] [ ] falign loopstart2 L10 [ move.4f move.4f (r5)+,d0:d1:d2:d3 (r2)-,d4:d5:d6:d7 ;[34,1] 0%=0 ;[34,1] 0%=0 mpy mpy mpy d7,d0,d15 d5,d0,d13 d6,d0,d14 ;[34,1] 1%=0 ;[34,1] 1%=0 ;[34,1] 1%=0 ] [ Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 313 Freescale Semiconductor, Inc. MWEntComp.book Page 314 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Loop Multi-Sampling mpy doen3 move.2f d4,d0,d12 #7 (r1)+n3,d8:d9 ;[34,1] 1%=0 ;[0,0] @II4 ;[34,1] 1%=0 mac mac mac mac move.f d9,d1,d12 d6,d1,d15 d5,d1,d14 d4,d1,d13 (r4)+n2,d7 ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[34,1] 2%=0 2%=0 2%=0 2%=0 1%=0 mac mac mac mac d5,d2,d15 d9,d2,d13 d8,d2,d12 d4,d2,d14 ;[34,1] ;[34,1] ;[34,1] ;[34,1] 3%=0 3%=0 3%=0 3%=0 ] [ ] [ ] falign loopstart3 L9 [ mac mac mac mac move.4f move.4f d7,d3,d12 d4,d3,d15 d9,d3,d14 d8,d3,d13 (r2)-,d4:d5:d6:d7 (r5)+,d0:d1:d2:d3 ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[34,1] 4%=1 4%=1 4%=1 4%=1 0%=0 0%=0 mac mac mac mac move.2f move.f d7,d0,d15 d4,d0,d12 d6,d0,d14 d5,d0,d13 (r1)+n3,d8:d9 (r4)+n2,d7 ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[34,1] 1%=0 1%=0 1%=0 1%=0 1%=0 1%=0 mac mac mac mac d6,d1,d15 d4,d1,d13 d9,d1,d12 d5,d1,d14 ;[34,1] ;[34,1] ;[34,1] ;[34,1] 2%=0 2%=0 2%=0 2%=0 mac mac mac mac d5,d2,d15 d9,d2,d13 d8,d2,d12 d4,d2,d14 ;[34,1] ;[34,1] ;[34,1] ;[34,1] 3%=0 3%=0 3%=0 3%=0 ] [ ] [ ] [ ] 314 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 315 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Partial Summation [ mac mac mac mac adda d7,d3,d12 d4,d3,d15 d9,d3,d14 d8,d3,d13 #>72,r2,r2 ;[34,1] ;[34,1] ;[34,1] ;[34,1] ;[0,1] 4%=1 4%=1 4%=1 4%=1 ] [ moves.4f d12:d13:d14:d15,(r7)+ adda #>72,r4,r4 ;[36,1] ;[0,1] adda suba ;[0,1] ;[0,1] ] [ #>72,r1,r1 r0,r5 ] loopend2 ... Partial Summation In some cases, data dependency prevents the parallelizer from doing the best possible job. This is particularly likely for multiple accumulation, as in the code of Listing C.18. Listing C.18 Partial Summation: Multiple Accumulation Example ... accu=0; for(...) { accu=accu+tab[i++]; ... accu=accu+tab[i++]; ... } ... The simple transformation to the code of Listing C.19 consists of splitting the sequence of accumulations. This may suppress the data dependency that the accu variable carries, without modifying code semantics. Listing C.19 Partial Summation: Data Dependency Suppression ... accu1=0; accu2=0; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 315 Freescale Semiconductor, Inc. MWEntComp.book Page 316 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Partial Summation for(...) { accu1=accu1+tab[i++]; ... accu2=accu2+tab[i++]; ... } accu=accu1+accu2; ... This transformation is partial summation. Digital signal programmers often perform this transformation manually in their C or assembly code. Partial Summation Restrictions Partial summation must comply with these restrictions: • Saturation and monotonicity — The high-level optimizer can performed partial summation automatically, probably enhancing unrolling, provided that: – If the accumulator is an integer (signed or unsigned), a sufficient condition consists of combining accumulations involving additions, subtractions, or both, as in: acc=acc+/-var – If the accumulator is a fractional, a sufficient condition consists of only processing monotonic accumulation instructions that cannot reach saturation at any stage of the calculation. This restricts transformations to quadratic accumulation involving either addition or subtraction, as in: acc=Add/ Sub(acc, Mult(var, var)) • Other Accumulator Accesses — The high-level optimizer performs the transformation only if there is no redefinition or re-use of the accumulator variable outside the accumulation instructions inside the loop. This holds for both direct accesses and accesses through aliases. • Relevance Strategy — Any of these cases make partial summation irrelevant, so block the transformation: – The accumulation instruction is an induction instruction. – The accumulator is neither an integer nor a fractional data type, accessed directly. (For example, this restrictions excludes pointers.) – The register pressure inside the loop is too great. Immediate Accumulator Example The example source code of Listing C.20 features an immediate accumulator, computing an energy value. Such a typical loop appears in many applications. 316 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 317 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Partial Summation Listing C.20 Partial Summation: Immediate Accumulator Source Code ... Word16 y[L_WINDOW]; Word32 sum; ... do { ... sum = 0L; for (i = 0; i < L_WINDOW; i++) { sum = L_mac (sum, y[i], y[i]); } ... } while(...) ... The scheduler chooses the unrolling factor that can yield the best results of partial summation. For example, suppose that you submit the Listing C.20 example code to the compiler, with options -u4 and -O3 (maximum unrolling factor is 4, code is parallelized). The unrolling control strategy would dictate not unrolling the loop at all, so that the compiler generates the assembly code of Listing C.21. The core of the loop is between flags loopstart3 and loopend3. This reduces the effectiveness of code parallelization and pipelining. (Instructions related with the loop have number 145 in their comments.) Listing C.21 Partial Summation: Immediate Accumulator Default Assembly Code ... L17 [ sub sub suba adda d0,d0,d2 d0,d0,d3 #<1,r1 #>-504,sp,r0 ;[141];CLR instruction ;[142];CLR instruction ;[0] ;[145] doensh3 r1 ;[0] adda move.f #<1,r1 (r0)+,d4 ;[0] ;[145] 0%=0 ] [ ] skipls PL000 loopstart3 ;[0] mac move.f ;[146] 1%=1 ;[145] 0%=0 [ d4,d4,d3 (r0)+,d4 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 317 Freescale Semiconductor, Inc. MWEntComp.book Page 318 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Partial Summation ] loopend3 PL000 [ mac d4,d4,d3 adda #>-504,sp,r0 ] ... ;[146] 1%=1 ;[153] B6 However, if you disable the unrolling control strategy and force unrolling by 4, the compiler produces the code of Listing C.22. Because of data dependency, the core of the loop contains four packets. Listing C.22 Partial Summation: Immediate Accumulator Assembly Code, Unrolled by 4 ... L17 [ sub sub adda doen3 d0,d0,d3 d0,d0,d2 #>-504,sp,r0 #59 ;[142];CLR instruction ;[141];CLR instruction ;[145] ;[0] @II4 ] [ move.4f (r0)+,d4:d5:d6:d7 dosetup3 L54 ;[145] 0%=0 ;[0] mac d4,d4,d3 mac d5,d5,d3 mac d6,d6,d3 falign loopstart3 ;[145] 1%=0 ;[145] 2%=0 ;[145] 3%=0 mac move.4f ;[146] 4%=1 ;[145] 0%=0 ] L54 [ d7,d7,d3 (r0)+,d4:d5:d6:d7 ] mac d4,d4,d3 mac d5,d5,d3 mac d6,d6,d3 loopend3 ;[145] 1%=0 ;[145] 2%=0 ;[145] 3%=0 mac move.l ;[146] 4%=1 ;[148] [ d7,d7,d3 #2147483647,d4 ] ... 318 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 319 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Partial Summation Listing C.23 shows the combined effects of automatic unrolling and partial summation (for optimization level -O3). This code has more opportunities for pipelining improvements: many 145-flagged instructions are before and after the loop. Also note that the loop core now contains only one packet: Listing C.23 Partial Summation: Immediate Accumulator Final Assembly Code ... L17 [ sub sub adda d0,d0,d4 d0,d0,d8 #>-480,sp,r5 ;[145];CLR instruction ;[141];CLR instruction ;[145] sub sub sub doensh3 move.4f d0,d0,d5 d0,d0,d7 d1,d1,d6 #59 (r5)+,d0:d1:d2:d3 ;[145];CLR instruction ;[145];CLR instruction ;[145];CLR instruction ;[0] @II1 ;[145] 0%=0 ] [ ] nop loopstart3 ;[0] L_D_3 mac mac mac mac move.4f d0,d0,d5 d1,d1,d7 d2,d2,d6 d3,d3,d4 (r5)+,d0:d1:d2:d3 ;[145] ;[145] ;[145] ;[146] ;[145] 1%=1 1%=1 1%=1 1%=1 0%=0 mac mac mac mac adda d0,d0,d5 d1,d1,d7 d2,d2,d6 d3,d3,d4 #>-480,sp,r1 ;[145] ;[145] ;[145] ;[146] ;[153] 1%=1 1%=1 1%=1 1%=1 B6 add tfra d14,d5,d1 r1,r6 ;[145] ;[0] B6 add add d1,d7,d5 d5,d6,d0 ;[145] ;[145] add move.4f d0,d4,d4 (r6)+,d0:d1:d2:d3 ;[145] ;[153] 0%=0 B6 [ ] loopend3 [ ] [ ] [ ] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 319 Freescale Semiconductor, Inc. MWEntComp.book Page 320 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Partial Summation ... Array-Cell Accumulation Example Many applications use an array for storing and reading accumulation values. Listing C.24 shows example source code. Listing C.24 Partial Summation: Array-Cell Accumulator Source Code ... Word16 tabf[SIZE][L_WINDOW]; Word32 accf[SIZE]; ... for(i=0; i<SIZE; i++) { accf[i]=0; for(j=0; j<L_WINDOW; j++) { accf[i]=L_mac (accf[i], tabf[i][j], tabf[i][j]); } } ... For such cases, successive optimization stages let the compiler deliver efficient code: Stage 1 — Automatic loop unrolling, according to the corresponding option (-u2 or u4). The resulting assembly code is equivalent to the Listing C.25 code (for -u4). Stage 2 — Access scalarization. Inside the inner-most loop, i is invariant, so scalarization is possible for accesses to array acc[i]. This exposes an accumulation sequence, as in the code of Listing C.26. The corresponding accumulator is variable t1. Stage 3 — Applying partial summation to this accumulation sequence. The high-level scheduler decides to preserve the unrolled version of the loop, leading to the final, optimized assembly code (Listing C.27). Listing C.25 Partial Summation: Array-Cell Accumulator Loop Unrolling ... Word16 tabf[SIZE][L_WINDOW]; Word32 accf[SIZE]; ... for(i=0; i<SIZE; i++) { accf[i]=0; for(j=0; j<L_WINDOW; ) { accf[i]=L_mac (accf[i], tabf[i][j], tabf[i][j]); j++; 320 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 321 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Partial Summation accf[i]=L_mac (accf[i], tabf[i][j], tabf[i][j]); j++; accf[i]=L_mac (accf[i], tabf[i][j], tabf[i][j]); j++; accf[i]=L_mac (accf[i], tabf[i][j], tabf[i][j]); j++; } } ... Listing C.26 Partial Summation: Array-Cell Accumulator Scalarization ... Word16 tabf[SIZE][L_WINDOW]; Word32 accf[SIZE]; ... for(i=0; i<SIZE; i++) { accf[i]=0; t1=accf[i]; for(j=0; j<L_WINDOW; j++) { t1=L_mac (t1, tabf[i][j], t1=L_mac (t1, tabf[i][j], t1=L_mac (t1, tabf[i][j], t1=L_mac (t1, tabf[i][j], } accf[i]=t1; } ... tabf[i][j]); tabf[i][j]); tabf[i][j]); tabf[i][j]); Listing C.27 Partial Summation: Array-Cell Accumulator Final Assembly Code ... DW_18 [ doen2 #<16 dosetup2 L30 ] ... DW_20 move.l #_accf,r0 move.l #_tabf,r1 falign loopstart2 L30 [ sub d0,d0,d1 sub d0,d0,d2 ;[0] ;[0] ;[36] ;[0] ;[38];CLR instruction ;[38];CLR instruction Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 321 Freescale Semiconductor, Inc. MWEntComp.book Page 322 Monday, September 27, 2004 2:17 PM Loop Restructuring and Reordering Partial Summation sub move.w doensh3 d1,d1,d3 #<0,d0 #3 ;[38];CLR instruction ;[36] ;[0] @II1 move.l move.4f d0,(r0) (r1)+,d4:d5:d6:d7 ;[36] ;[38] 0%=0 ] [ ] loopstart3 [ mac mac mac mac move.4f d4,d4,d0 d5,d5,d1 d6,d6,d2 d7,d7,d3 (r1)+,d4:d5:d6:d7 ;[38] ;[38] ;[38] ;[39] ;[38] 1%=1 1%=1 1%=1 1%=1 0%=0 mac mac mac mac d5,d5,d1 d4,d4,d0 d6,d6,d2 d7,d7,d3 ;[38] ;[38] ;[38] ;[39] 1%=1 1%=1 1%=1 1%=1 add add add move.l loopend2 d0,d1,d4 d4,d2,d5 d5,d3,d6 d6,(r0)+ ;[38] ;[38] ;[38] ;[0] ] loopend3 [ ] ... 322 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 323 Monday, September 27, 2004 2:17 PM D Loop Restrictions This appendix explains important restrictions or limitations regarding loop optimizations, and explains a case study. It consists of these sections: • Choosing Types • Choosing TypesSingle-Loop Induction Limitations • Cross-Loop Limitations • Sequential Access, Packing Limitations • Case Study: G729 cor_h Function Choosing Types Your default choice for declaring integer variables should be signed, 32-bit integers. Remember that all integer types are not equivalent in C. In many cases, the language forces you to use casts to long integer, in order to perform operations on chars and shorts. There are similar constraints for unsigned integer types. These casts may lead to more complex, less efficient code. Note as well that unsigned integers must comply with wraparound behavior, but this requirement does not apply to signed integers. This means that overflow can make your resulting code implementation dependent. Accordingly, the only times you should use types char, short, or unsigned is when they are absolutely needed — as would be the case for wraparound behavior. Furthermore, late optimizations assign the most efficient types and operations for each variable, according to its range. For example, even if you declare a variable to be a long (32-bit) integer, the optimizer can map it on a short (16-bit) word. The only restriction on the optimizer is that such an action may not change the program semantics. Only if your program imposes constraints on the type of data, should you declare integer variables to be 8 or 16 bits. Single-Loop Induction Limitations • Induction Variable Redefinition • Ambiguous Definition Due to Function Call Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 323 Freescale Semiconductor, Inc. MWEntComp.book Page 324 Monday, September 27, 2004 2:17 PM Loop Restrictions Single-Loop Induction Limitations • Multiple Conditional Induction • Second Order Induction Induction Variable Redefinition The optimizer recognizes the induction variables (IVs) that Table D.1 lists. Table D.1 Induction Variable Types IV Type Description Basic Linear Variable decremented or incremented within a loop body by a constant value (a literal) or by a loop-invariant step. Static IV whose step is a constant (literal) Dynamic IV whose step is an invariant value. Multi-Step IV incremented more than once within a loop body. Non-Basic (Derived) IV derived from any other IV by means of a linear function, where the gain is a constant value and the offset is either a constant or a loop-invariant value. Composed IV that is a linear combination of any other IVs, where gains are constant values and the offset is either a constant or a loopinvariant value But if redefinition of an IV changes its inducted behavior, the optimizer no longer can detect the variables as an IV. For example, the optimizer would not recognize as IVs: • a non-basic IV with multiple definitions • a basic IV and non-basic IV with killing redefinition The optimizer would not detect IVs in any of these code examples. • Constant redefinition — Listing D.1. • Multiple dependence of basic IVs — Listing D.2. • Definition as both basic and non-basic IVs — Listing D.3. Listing D.1 IV Redefinition: Constant Redefinition ... for(...) { ... ind3 = 2*ind1; 324 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 325 Monday, September 27, 2004 2:17 PM Loop Restrictions Single-Loop Induction Limitations ... ind3 = 0; ... ind1++; } ... Listing D.2 IV Redefinition: Multiple Dependence ... for(...) { ... ind3 = 2*ind1; ... ind3 = 3*ind1; ... ind1++; } ... Listing D.3 IV Redefinition: Basic/Non-Basic Definition ... for(...) { ... ind3 = 2*ind1; ... ind3++; ... ind1++; } ... A possible solution is using two different variables to de-correlate the conflicting definitions, as in the code of Listing D.4. Listing D.4 IV Redefinition: Possible Solution ... for(...) { ... ind3 = 2*ind1; ... ind3_bis = 3*ind1; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 325 Freescale Semiconductor, Inc. MWEntComp.book Page 326 Monday, September 27, 2004 2:17 PM Loop Restrictions Single-Loop Induction Limitations ... ind1++; } ... Ambiguous Definition Due to Function Call A function call that is apt to modify an IV amounts to a special case of redefinition. Listing D.5 shows an example. Listing D.5 Function-Call Ambiguous Definition ... for(...) { ... ... fct(..., &not_basic_iv, ...)...; ... not_basic_iv=not_basic_iv+1; not_non_basic_iv = not_basic_iv * 3; ... } ... In this case, the variable does not meet the definition of a basic IV. And as a linear function of this variable defines other variables, neither do those other variables meet the definition of non-basic IVs. Note that this limitation is general. It also concerns: • Invariant code motion (any variable that receives its address as a function input argument does not meet the definition of a loop invariant variable), • Sequences of memory accesses and packing (such an ambiguous definition may break a sequence), • Cross-loop optimization. A possible solution is using a copy to be passed as a function argument, as Listing D.6 shows. However, for such a solution to work, the function must not actually modify the value of the variable. Listing D.6 Function-Call Ambiguous Definition: Possible Solution ... for(...) { ... 326 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 327 Monday, September 27, 2004 2:17 PM Loop Restrictions Single-Loop Induction Limitations aux_var = basic_iv; ... fct(..., &aux_var, ...)...; ... basic_iv= basic_iv+1; non_basic_iv = basic_iv * 3; ... } ... Multiple Conditional Induction Another limitation concerns conditional branches of a loop body — branches that induct variables several times. Listing D.7 is an example: the variable does not meet the definition of a basic IV, nor do variables that a linear function of this variable defines meet the definition of non-basic IVs . Listing D.7 Multiple Conditional Induction: Loop Branch ... for(...) { ... if(...) { var = var + 1; } else { var = var + 2; } ... } ... The same kind of limitation concerns a multi-step IV with conditional induction, as Listing D.8 shows. Listing D.8 Multiple Conditional Induction: Multi-Step IV ... for(...) { ... if(...) { var = var + 1; } ... var = var + 2; ... } Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 327 Freescale Semiconductor, Inc. MWEntComp.book Page 328 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations ... Unfortunately, there is no way to overcome this limitation. Second Order Induction Even if the cross-loop mechanism handles second-order IVs (that is, induction variables that have inducted steps), the compiler cannot cope with user-defined second order induction. In the code of Listing D.9, for example, var2 is an induction variable, but var1 is not. Listing D.9 Second Order Induction ... for(...) { ... var1 = var1 + var2; ... var2++; ... } ... As with multiple conditional induction, there is no way to overcome this limitation of second order induction. Cross-Loop Limitations • Loop Step General Restriction • Reused Variables • Implicit Cross-Loop Combination • Conditional Inner Loop • Bypassed Inner Loop Loop Step General Restriction The optimizer’s cross-loop mechanism deals only with hardware loops. It handles loops controlled by variables whose step is either: • An integer equal to a power of two (including one). The optimizer takes into account both short and long integers. 328 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 329 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations • A short integer that can be computed via fractional multiplication, provided that the only steps equal 3, 5, or 7. If variable steps do not meet these constraints, the optimizer does not apply the cross-loop mechanism to the loops. Moreover, a step that is not a unit step reduces the gain of cross-loop optimization, even if the step fits the constraints above. This is particularly the case if a loop contains induction variables whose step value is less than that of the loop-control variable used for loop control. This is because the cross-loop mechanism must introduce new instructions to compute the loop count. The formula for large inequalities is: LC = (High_Bound – Low_Bound + step) / step The formula for strict inequalities is: LC = (High_Bound – Low_Bound – 1 + step) / step Furthermore, such code also requires some intermediate divisions (or shift operations) that the induction process cannot simplify. The only way to overcome this limitation is rewriting the loop with an appropriate step and appropriate bounds. It may be possible to rewrite loops with a unit step control, even if this requires extra multiplications in the loop body. For example, the loop of Listing D.10 involves non-unit step control. It is possible to rewrite the code for unit step control, as Listing D.11 shows. Although this rewrite may not seem to be intuitive, it leads to more efficient assembly code. Listing D.10 Non-Unit Loop Step Control ... for(ind1=0; ind1<16; ind1+=4) { for(ind2=ind1; ind2<16; ind2+=4) { tab[ind2-ind1] = 0; } } ... Listing D.11 Unit Loop Step Control ... for(ind1=0; ind1<4; ind1+=1) { for(ind2=ind1; ind2<4; ind2+=1) { tab[4*(ind2-ind1)] = 0; } } Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 329 Freescale Semiconductor, Inc. MWEntComp.book Page 330 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations ... Reused Variables The idea of cross-loop induction is moving code out of loop nests. A key step is replacing induction-variable initialization with an equivalent reset instruction positioned after the related loop. For example, the two pieces of code in Listing D.12 and Listing D.13 are functionally equivalent, but the Listing D.13 code is more efficient. Listing D.12 Reused Variables: Three-Dimension Mixed Example ... for(...) { i = 0 ; for(a=0 ; a<LC ; a++) { ... use(i) ; ... i++ ; } ... Listing D.13 Reused Variables: Efficient Three-Dimension Mixed Example ... i = 0; for(...) { i = 0 ; for(a=0 ; a<LC ; a++) { ... use(i) ; ... i++ ; } i = i - LC ; ... As the inner loop may contain a bypass test, the new reset instruction must be in the related conditional epilog. This means that any re-use of variable i after the inner loop invalidates the transformation, as in Listing D.14. 330 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 331 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations Listing D.14 Reused Variables: Invalidated Transformation ... for(...) { i = 0 ; for(a=0 ; a<LC ; a++) { ... use(i) ; .. i++ ; } ... use2(i) ; } ... A possible solution is creating a second variable, independent from i. This modification holds even if the inner-loop count is neither a constant nor an outer-loop invariant (triangular iteration space), as Listing D.15 shows. Listing D.15 Reused Variables: Possible Solution ... for(...) { i = 0 ; for(a=0 ; a<LC ; a++) { ... use(i) ; .. i++ ; } ... i2 = LC ; use2(i2) ; } ... Implicit Cross-Loop Combination The code of Listing D.16 performs a triangular access to a linearized array: Listing D.16 Implicit Combination: Triangular Access ... for(i=0 ; i<MAX ; i++) { Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 331 Freescale Semiconductor, Inc. MWEntComp.book Page 332 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations ... index = (i*GAIN) + 1 ; for(j=i+1 ; j<MAX ; j++) { ... tab[index]=0; ... index++ ; j++ ; } ... i++ ; } ... Notice that: • Induction of the index variable takes place in the inner loop. • The index variable is defined as a non-basic IV of the outer loop. • Execution bypasses the inner loop once (during the last iteration of the outer loop, when i = MAX-1), but this is not a key point here. This pattern is a special case of IV redefinition. Because of the multiple and cross-loop induction, the optimizer does not recognize the index variable as a cross-loop composed IV. Listing D.17 shows the resulting assembly code. Listing D.17 Implicit Combination: Assembly Code without IV Recognition ... DW_5 move.w #<1,d0 move.w #<10,d1 move.w #<1,d2 doen2 #<5 dosetup2 L10 loopstart2 L10 cmpgt.w #<9,d0 jt L4 asr d1,d3 move.l d2,r0 nop asla r0 adda #>-40,sp,r1 adda r1,r0 doensh3 d3 sub d0,d0,d3 nop 332 ;[17] ;[0] ;[16] ;[0] ;[0] ;[17] ;[17] ;[0] ;[18] ;[0] AGU stall ;[18] ;[18] ;[18] ;[0] ;[0];CLR instruction ;[0] L_D_3 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 333 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations loopstart3 L9 move.w d3,(r0) adda #<2,r0 loopend3 ;[18] ;[19] add #<4,d2 sub #<2,d1 add #<2,d0 loopend2 ;[15] ;[15] ;[15] L6 L4 L8 ... The possible solution is separating the different components of the index cross-loop IV. Furthermore, the corresponding definition should be in the inner loop, to allow bypassing the combination. Listing D.18 shows this modified source code, which leads to the improved assembly code of Listing D.19: Listing D.18 Implicit Combination: Separated IV Components ... for(i=0 ; i<MAX ; i++) { ... index = 0 ; for(j=i+1 ; j<MAX ; j++) { invar = (i*GAIN) + 1 ; ... tab[index + invar]=0; ... index++ ; j++ ; } ... i++ ; } ... Listing D.19 Implicit Combination: Assembly Code with IV Recognition ... .code /* START */ . 1 .move_w($d0 = 1); . 1 .moveu_l($r0 = &_tab2+(4)); . 1 ($r1 = 4294967268); (50; 0) (0; 0) (0; 0) Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 333 Freescale Semiconductor, Inc. MWEntComp.book Page 334 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations . . . 1 1 1 /* START . 10 . 10 . 10 . 10 . 10 . 10 /* START . 250 . 250 /* START ; (0; 0) /* START . 10 . 10 . 10 /* START ; (0; 0) ... .move_w($lc2 = 10); (0; 0) .dosetup(2, L18, L16); (0; 0) .move_w($d1 = 10); (0; 0) */ /* STOP */ L18: .do($d2 = $d1 - $d0); (0; 0) .do(.tst_gt($d2, 0)); (50; 0) .goto (L8) .if (!$t) ; (50; 0) .move_l($lc3 = $d2); (0; 0) .dosetup(3, L17, L14); (0; 0) .do(.clr($d4)); (0; 0) */ L17: .move_l($ram[$r0] = $d4) .W 226; (54; 0) .do($r0 = $r0 + 4); (55; 0) */ L14: */ L8: .do($r0 = $r0 + $r1); .do($d0 = $d0++); .do($r1 = $r1 + 4); */ L16: (0; 0) (47; 0) (0; 0) The Listing D.19 code stores the memory-access pointer in $r0. It is set outside the loop nest and monitored across the nest. This is possible despite the inner-loop bypass test. Conditional Inner Loop Another arrangement that blocks the cross-loop mechanism is including the inner loop in a conditional branch of the outer-loop body. (This does not pertain to an inner loop with a bypass test, which the optimizer does analyze.) Listing D.20 shows such an arrangement: Listing D.20 Conditional Inner Loop ... for(...) { ... if(condition) { ... for(j=0 ; j<LC ; j++) { ... ... tab[i][j] ... ; ... j++ ; } ... 334 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 335 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations } ... i++ ; } ... In this case, it is not possible to recombine inner and outer loop IVs. Initialization of the memory-access pointer must be in the conditional branch, so cannot be moved out of the nest. Unswitching the outer loop may overcome this limitation. Listing D.21 shows such unswitching, moving the condition out of the nest. Unfortunately, this transformation is not always valid, especially if the loop nest is not perfect, or if the condition is not invariant in the outer loop. Listing D.21 Conditional Inner Loop: Unswitched Outer Loop ... if(condition) { for(...) { ... for(j=0 ; j<LC ; j++) { ... ... tab[i][j] ... ; ... j++ ; } ... i++ ; } } else { for(...) { ... i++ ; } } ... Bypassed Inner Loop Some cases involve bypassing an inner loop, even if it is not located in a conditional branch. The programmer’s style may affect such bypass tests, especially if any loop bounds have dynamic values (that is, that they are unknown at compile time). In Listing D.22, for example, the dynamic definition of bound means that bypass tests always must be present in the intermediate code. This makes the domain of the outer-loop Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 335 Freescale Semiconductor, Inc. MWEntComp.book Page 336 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations IV greater than the access pattern, as Figure D.1 shows. Listing D.23 shows the resulting assembly code. Listing D.22 Bypassed Inner Loop: Initial C Code ... for(i=0; i<MAX; i++) { for(j=0 ; j<=i-bound; j++) { ... tab[i][j] ... ; ... ] ... Figure D.1 Bypassed Inner Loop: Initial Code Domain Outer Loop IV Domain Bypass Test Needed Listing D.23 Bypassed Inner Loop: Assembly Code with By-Pass Test ... /* START */ . 1 .do(.clr($d0)); . 1 .move_w($d1 = $ram[&..._bound]) . 1 .do($d1 = -$d1); . 1 .move_w($lc2 = 10); . 1 .dosetup(2, L10, L8); . 1 .move_w($d3 = 1); . 1 .move_w($d4 = 40); /* START */ /* STOP */ L10: . 10 .do(.tst_ge($d1, 0)); . 10 .goto (L4) .if (!$t); . 10 .do($d2 = .tfr($d3)); . 10 .do($d2 = .iadd($d2, $d1)); . 10 .move_l($r0 = $d0); . 10 .moveu_l($r1 = &_tab3); . 10 .do($r1 = $r1 + $r0); . 10 .move_l($lc3 = $d2); 336 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 337 Monday, September 27, 2004 2:17 PM Loop Restrictions Cross-Loop Limitations . . 10 .dosetup(3, L9, L6); 10 .do(.clr)$d2)); /* START */ L9: . 250 .move_l($ram[$r1] = $d2) . 250 .do($r1 = $r1 + 4); /* START */ L6: /* START */ L4: . 10 .do($d1 = .iadd($d1, The rewritten code of Listing D.24 is functionally equivalent to the Listing D.22 code, provided that the loops are perfectly nested. (This means that the outer loop contains only the inner loop and induction instructions.) But execution never by-passes the inner loop of Listing D.24. This makes the by-pass test useless, so the optimizer can remove it. Figure D.2 shows that the domain of the outer-loop IV is the same as the access pattern. Listing D.25 shows the resulting assembly code, which is more efficient than the assembly code of Listing D.23. Listing D.24 Bypassed Inner Loop: Rewritten C Code ... for(i=bound; i<MAX; i++) { for(j=0 ; j<=i-bound; j++) { ... tab[i][j] ... ; ... ] ... Figure D.2 Bypassed Inner Loop: Rewritten Code Domain Outer Loop IV Domain Bypass test to be removed Listing D.25 Bypassed Inner Loop: Assembly Code without By-Pass Test ... /* START */ /* STOP */ . 1 .move_w($d0= $ram[&..._bound]) . 1 .do(.cmp_gt($d0, 10-1)); Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 337 Freescale Semiconductor, Inc. MWEntComp.book Page 338 Monday, September 27, 2004 2:17 PM Loop Restrictions Sequential Access, Packing Limitations . . . . . . . . . . . . . . . . . . . 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 .goto (L2) .if ($t); .move_w($d1 = 10); .do($d2 = $d1 - $d0); .move_w($d3 = 65535); .do($4 = .tfr($d0)); .do($d4 = .imac($d3, $d0)); .do($d4 = .sxt_w($d4)); .do($d4 = $d4++); .do($d0 = .impy($d0, 40)); .move_l($r0 = $d0); .moveu_l($r1 = &_tab3); .do($r0 = $r0 + $r1); .do(.clr($d5)); .do($d4 = .asl_imm($d4, 2)); .do($d4 = .sxt_w($d4)); .move_w($d6 = 40); .do($d7 = $d6 - $d4); .move($lc2 = $d2); .dosetup(2, L10, L8); The optimized code of Listing D.25 is larger than the code of Listing D.23, but is more efficient. If MAX equals 10, bound equals 7, and tab is a 10x10 array, then the number of cycles decreases from 187 to 134 for this simple example. Sequential Access, Packing Limitations • Aliasing and Conflicting Interleaved Read/Write Accesses • Aliasing and Interprocedural Effect • Missing Initial Alignment Aliasing and Conflicting Interleaved Read/ Write Accesses Consider a function that receives two pointers as arguments. The use for these pointers is copying the contents of one array to another array, as in the code of Listing D.26. Listing D.27 shows the equivalent sequence of basic instructions in the loop. Listing D.26 Access Packing: Initial C Code ... void copy_fct(short* A1, short* A2) { #pragma noinline 338 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 339 Monday, September 27, 2004 2:17 PM Loop Restrictions Sequential Access, Packing Limitations #pragma align *A1 8; #pragma align *A2 8; for(i=0, j=0; i<MAX; i+=2, j+=2) { A2[i] = A1[j]; A2[i+1] = A1[j+1]; } } ... Listing D.27 Access Packing: Equivalent C Code ... for(i=0, j=0; i<MAX; i+=2, j+=2) { tmp1 = A1[j]; A2[i] = tmp1; tmp2 = A1[j+1]; A2[j+1] = tmp2; } ... /* /* /* /* instruction instruction instruction instruction 1 2 3 4 */ */ */ */ For the access packing optimization, the optimizer would try to change the code to the form of Listing D.28. It would pack read accesses to A1 together on one side, and pack write accesses to A2 on the other side. Listing D.28 Access Packing: Optimizer Code Version ... for(i=0, j=0; i<MAX; i+=2, j+=2) { tmp1 = A1[j]; tmp2 = A1[j+1]; A2[i] = tmp1; A2[j+1] = tmp2; } ... /* /* /* /* instruction instruction instruction instruction 1 3 2 4 */ */ */ */ Unfortunately, in this case, the code receives pointers A1 and A2 as input arguments. This means that the optimizer cannot know anything precise about A1 and A2, so that they must belong to the same alias class. In other words, the expressions A1[i] and A2[j+1] may point the same memory location. This means that moving instruction 3 before instruction 2 is not valid, as instruction 3 may redefine the contents of A2[j+1]. Accordingly, it is not possible to pack these accesses. A possible solution is transforming the code, to make packing valid. For this example, the transformation simply is avoiding interleaved accesses. The programmer presumes that Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 339 Freescale Semiconductor, Inc. MWEntComp.book Page 340 Monday, September 27, 2004 2:17 PM Loop Restrictions Sequential Access, Packing Limitations this avoidance is valid, due to the use for the function. Listing D.29 shows the rewritten loop. Listing D.29 Access Packing : Possible Solution ... for(i=0, j=0; i<MAX; i+=2, j+=2) { tmp1 = A1[j]; tmp2 = A1[j+1]; A2[i] = tmp1; A2[j+1] = tmp2; } ... /* /* /* /* instruction instruction instruction instruction 1 3 2 4 */ */ */ */ Aliasing and Interprocedural Effect Reconsider the previous code example, but this time with a new function call between the two read accesses. In the code of Listing D.30, this function receives pointer A1 as an input argument. Listing D.30 Interprocedural Effect ... int fct(short* tab) { #pragma noinline return(tab[0]); } void copy_fct(short* A1, short* A2) { #pragma noinline #pragma align *A1 8; #pragma align *A2 8; short tmp1, tmp2; for(i=0, j=0; i<MAX; i+=2, j+=2) { tmp1 = A1[j]; c = fct(A1); tmp2 = A1[j+1]; A2[i] = tmp1; A2[j+1] = tmp2; } ... 340 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 341 Monday, September 27, 2004 2:17 PM Loop Restrictions Sequential Access, Packing Limitations } ... Function fct receives the pointer as an input argument, so modifications are likely for the pointer value or the contents of related memory locations. The appropriate solution is not moving the function call out of the sequence: execution still may redefine the pointer, violating the alignment condition. The only solutions are: • Declaring that function fct has no side effects, due to the related nosideeffects pragma. This prevents the compiler from choosing the default worst case assumption concerning aliasing, • Inlining function fct, to make data dependencies explicit. In many cases, function calls may introduce this kind of ambiguity. Missing Initial Alignment Listing D.31 shows a more complex function, in which execution performs the sequence of accesses in a triangular loop. Listing D.31 Missing Initial Alignment ... void fct(short* A1) { #pragma noinline #pragma align *A1 8; short tmp1, tmp2; for(i=0; i<MAX; i+=2) { for(j=i; j<MAX; j++) { tmp1 = A1[j]; tmp2 = A1[j+1]; ... /*tmp1 and tmp2 assumed to be used in loop*/ ... } } ... } ... Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 341 Freescale Semiconductor, Inc. MWEntComp.book Page 342 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function In this case, the definition of index j uses a dynamic initial value, derived from the outerloop IV. This blocks access packing, as the compiler cannot verify that the alignment condition is satisfied. A possible solution is adding one function where the inner loop is implemented, and where a pragma specifies the initial array alignment, as Listing D.32 shows. Listing D.32 Missing Initial Alignment: Possible Solution ... void fct_inner(short* A1) { #pragma noinline #pragma align *A1 8; short tmp1, tmp2; for(j=i; j<MAX; j++) { tmp1 = A1[j]; tmp2 = A1[j+1]; ... /*tmp1 and tmp2 assumed to be used in loop*/ ... } ... } ... void fct(short* A1, short* A2) { #pragma noinline for(i=0; i<MAX; i+=2) { fct_inner(A1); } ... } ... Case Study: G729 cor_h Function A function from a real signal processing application illustrates the restrictions of the highlevel optimizer. This study includes a possible way to rewrite this function, to work around the compiler constraints. Listing D.33 shows the initial code for the example, which corresponds to a loop nest of the real G729 vocal coder cor_h function. 342 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 343 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function Listing D.33 Case Study: Initial C Code ... i1= 0; i2= 1; p3 = rri2i3- 2; p2 = rri1i2- 1; p1 = rri0i1- 1; p0 = rri0i4- 4; l_fin = MSIZE; for(k=0; p3+= p2+= p1+= p0+= k<NB_POS; k++) { 2*l_fin; l_fin; l_fin; 2*l_fin; cor0= 0; for(i= k+1; i< NB_POS; i++) { cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p3=mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p2 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p1 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p0 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); p3 p2 p1 p0 -= -= -= -= 2*(NB_POS+ 1); NB_POS+ 1; NB_POS+ 1; 2*(NB_POS+ 1); } cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p3 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 343 Freescale Semiconductor, Inc. MWEntComp.book Page 344 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function *p2 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p1 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); l_fin-= NB_POS+ 1; p0+= 2*(NB_POS- 1); i1-= (NB_POS-k-1)*5+4; i2-= (NB_POS-k-1)*5+4- STEP; } ... Step 1: Removing Reused IVs Notice the inner-loop IVs i1 and i2. After the inner loop, execution re-uses these variables in the outer loop. Consequently, the cross-loop mechanism cannot apply the reset transformation. Both induction and redefinition (reset) of variables i1 and i2 takes place in the outer loop. The redefinition involves k, another local IV. All these characteristics are restrictions for the high-level optimizer. The solution is using a different set of variables for memory access in the inner and outer loops. The two new induction variables for the outer loop are i1b and i2b. The code sets these variables to the appropriate values. This means that the outer loop defines variables i1 and i2, but no longer resets them. Listing D.34 shows the corresponding code. Listing D.34 Case Study: Reused IVs Removed ... i1= 0; i2= 1; p3 = rri2i3- 2; p2 = rri1i2- 1; p1 = rri0i1- 1; p0 = rri0i4- 4; l_fin = MSIZE; for(k=0; k<NB_POS; k++) { p3+= 2*l_fin; p2+= l_fin; p1+= l_fin; p0+= 2*l_fin; cor0= 0; i1 = 0; i2 = (k*STEP)+1; /*i1 and i2 now set before inner loop*/ for(i= k+1; i< NB_POS; i++) { 344 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 345 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p3=mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p2 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p1 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); cor0 = L_mac(cor0, h[i1], h[i2]); i1++; i2++; *p0 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2])); p3 p2 p1 p0 -= -= -= -= 2*(NB_POS+ 1); NB_POS+ 1; NB_POS+ 1; 2*(NB_POS+ 1); } i1b=5*(NB_POS-(k+1)); /*new variables i1b, i2b set here*/ i2b=5*(NB_POS-(k+1))+((k*STEP)+1); cor0 = L_mac(cor0, h[i1b], h[i2b]); i1b++; i2b++; / *new variables i1b, i2b used*/ cor0 = L_mac(cor0, h[i1b], h[i2b]); i1b++; i2b++; *p3 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b], Sign_Dn[L_SUBFR-i2b])); cor0 = L_mac(cor0, h[i1b], h[i2b]); i1b++; i2b++; *p2 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b], Sign_Dn[L_SUBFR-i2b])); cor0 = L_mac(cor0, h[i1b], h[i2b]); i1b++; i2b++; *p1 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b], Sign_Dn[L_SUBFR-i2b])); l_fin-= NB_POS+ 1; p0+= 2*(NB_POS- 1); } ... Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 345 Freescale Semiconductor, Inc. MWEntComp.book Page 346 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function Step 2: Removing Implicit Cross-Loop Combination This modified code still contains a conflict: it uses the outer-loop IV k to set the innerloop IV i2. The compiler does not handle such an implicit cross-loop combination. The solution is separating each subpart of the combination: placing the inner-loop invariant part (the outer-loop IV) on one side, and placing the inner-loop IV on the other side. The new variable invar stores the invariant part of indices. This code appropriately modifies the initial value of i2 and the actual indices. Listing D.35 shows this transformed code. Listing D.35 Case Study: Implicit Cross-Loop Combination Removed ... i1= 0; i2= 1; p3 = rri2i3- 2; p2 = rri1i2- 1; p1 = rri0i1- 1; p0 = rri0i4- 4; l_fin = MSIZE; for(k=0; p3+= p2+= p1+= p0+= k<NB_POS; k++) { 2*l_fin; l_fin; l_fin; 2*l_fin; cor0= 0; i1 = 0; i2 = 0; for(i= k+1; i< NB_POS; i++) { invar = (k*STEP)+1; cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; *p3 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2-invar])); cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; *p2 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2-invar])); cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; *p1 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2-invar])); 346 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 347 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; *p0 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2-invar])); p3 p2 p1 p0 -= -= -= -= 2*(NB_POS+ 1); NB_POS+ 1; NB_POS+ 1; 2*(NB_POS+ 1); } i1b=5*(NB_POS-(k+1)); i2b=5*(NB_POS-(k+1))+((k*STEP)+1); cor0 = L_mac(cor0, h[i1b], h[i2b]); i1b++; i2b++; cor0 = L_mac(cor0, h[i1b], h[i2b]); i1b++; i2b++; *p3 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b], Sign_Dn[L_SUBFR-i2b])); cor0 = L_mac(cor0, h[i1b], h[i2b]); i1b++; i2b++; *p2 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b], Sign_Dn[L_SUBFR-i2b])); cor0 = L_mac(cor0, h[i1b], h[i2b]); i1b++; i2b++; *p1 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b], Sign_Dn[L_SUBFR-i2b])); l_fin-= NB_POS+ 1; p0+= 2*(NB_POS- 1); } ... Step 3: Removing Redefined IVs from Outer Loop The last restrictive pattern concerns variables i1b and i2b, which are redefined IVs: • Their initialization is like non-basic IVs, derived from k (i1b=5*(NB_POS(k+1)). • Their induction is like multi-step IVs (i1b++ occurs three times). The optimizer cannot handle such patterns, so the solution is: • Removing multi-step induction for both i1b and i2b, and • Modifying indices for memory accesses, successively replacing i1b by i1b, i1b+1, i1b+2, and so forth. Listing D.36 shows the final transformed code. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 347 Freescale Semiconductor, Inc. MWEntComp.book Page 348 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function Listing D.36 Case Study: Final C Code ... i1= 0; i2= 1; p3 = rri2i3- 2; p2 = rri1i2- 1; p1 = rri0i1- 1; p0 = rri0i4- 4; l_fin = MSIZE; for(k=0; p3+= p2+= p1+= p0+= k<NB_POS; k++) { 2*l_fin; l_fin; l_fin; 2*l_fin; cor0= 0; i1 = 0; i2=0; for(i= k+1; i< NB_POS; i++) { invar = (k*STEP)+1; cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; *p3 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2-invar])); cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; *p2 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2-invar])); cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; *p1 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2-invar])); cor0 = L_mac(cor0, h[i1], h[i2+invar]); i1++; i2++; *p0 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1], Sign_Dn[L_SUBFR-i2-invar])); p3 p2 p1 p0 -= -= -= -= 2*(NB_POS+ 1); NB_POS+ 1; NB_POS+ 1; 2*(NB_POS+ 1); } i1b=5*(NB_POS-(k+1)); i2b=5*(NB_POS-(k+1))+((k*STEP)+1); 348 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 349 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function cor0 = L_mac(cor0, h[i1b], h[i2b]); cor0 = L_mac(cor0, h[i1b+1], h[i2b+1]); *p3 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b-2], Sign_Dn[L_SUBFR-i2b-2])); cor0 = L_mac(cor0, h[i1b+2], h[i2b+2]); *p2 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b-3], Sign_Dn[L_SUBFR-i2b-3])); cor0 = L_mac(cor0, h[i1b+3], h[i2b+3]); *p1 = mult(extract_h(cor0), mult(Sign_Dn[L_SUBFR-i1b-4], Sign_Dn[L_SUBFR-i2b-4])); l_fin-= NB_POS+ 1; p0+= 2*(NB_POS- 1); } ... The actual cor_h function contains four loop nests with a similar structure. Transforming those loop nests as text above proposes yields an overall gain of about 2000 cycles. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 349 Freescale Semiconductor, Inc. MWEntComp.book Page 350 Monday, September 27, 2004 2:17 PM Loop Restrictions Case Study: G729 cor_h Function 350 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 351 Monday, September 27, 2004 2:17 PM E Migrating from Other Environments The Metrowerks Enterprise C compiler includes header files that make it easy to migrate C code developed for certain other compilers. Still, differences between specific compilers and environments can affect compilation and results. For example, the compiler may not support assembler error messages for inlined code. Another possibility is loss of efficiency for functions implemented in a different way. Code Migration Overview In most circumstances, the compiler successfully compiles standard ANSI code that: • Does not use compiler-specific extensions, • Does not rely implicitly on the sizes of data types, • Does not rely on system-specific features, such as memory maps or peripherals, and • Does not rely on undefined compiler behavior. The compiler runtime libraries include a header file for each environment for which code is accepted: • DSP56600 compilers: port566toSC1.h header file • TI6xx compilers: portc6xtoSC1.h header file These header files define the features the specified environment uses, with correct values. This makes sure that compiling succeed without affecting your code. To use these definitions, merely include the appropriate header file in your source code. For example, to migrate code from the DSP56600 compiler environment, use the code of Listing E.1 to include the port566toSC1.h header file. Listing E.1 Migrating Code from Other Environments #include <port566toSC1.h> void main() { } Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 351 Freescale Semiconductor, Inc. MWEntComp.book Page 352 Monday, September 27, 2004 2:17 PM Migrating from Other Environments Migrating DSP56600 Code Migrating DSP56600 Code This section explains considerations for using the Metrowerks Enterprise C compiler with code developed for the DSP56600 compiler family. Integer Data Types The DSP56600 and SC100 compilers map certain integer data types to different sizes. Table E.1 lists the data-type size discrepancies for integers. Table E.1 DSP56600 Integer Data Type Differences Data Type DSP56600 Compiler SC100 C Compiler char unsigned char Saved in memory as 16 bits. Some operations are performed with 16 bits, others with 8. 8 bits packed char 8 bits Not supported int unsigned int 16 bits 32 bits enum 16 bits 32 bits Fractional Data Types DSP56600 compilers use built-in data types for declaring fractional variables. The Metrowerks Enterprise C compiler uses standard integer types for both fractional and integer values. Table E.2 lists the fractional data-type differences. . Table E.2 DSP56600 Fractional Data Type Differences 352 Data Type DSP56600 Compiler SC100 C Compiler 16-bit fraction _fract Word16 32-bit fraction long_fract Word32 40-bit accumulator long_fract Word40 64-bit fraction Not supported Word64 Complex fractions _complex Not supported directly Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 353 Monday, September 27, 2004 2:17 PM Migrating from Other Environments Migrating DSP56600 Code Floating-Point Data Types DSP56600 compilers represent floating-point data types according to a 32-bit proprietary format. The Metrowerks Enterprise C compiler maps fractional data types to a single-precision IEEE-754 type, using 32 bits. This may lead to differences in the numerical accuracy of floating-point calculations. Pointers Table E.3 shows the difference in pointer sizes. : Table E.3 DSP56600 Pointer Size Differences Data Type DSP56600 Compiler SC100 C Compiler pointer to char 16 bits 32 bits pointer to short 16 bits 32 bits, even addresses only pointer to long 16 bits 32 bits, quad addresses only The difference in pointer size is unlikely to have any impact. This is because compilers usually map relevant addresses to different numerical values for different processors. Fractional Arithmetic DSP56600 compilers support fractional arithmetic using integer-like operators, such as the plus sign (+) and multiplication symbol (*). The Metrowerks Enterprise C compiler uses intrinsic functions to implement fractional operations. Table E.4 lists the counterpart fractional operations and intrinsic functions. : Table E.4 DSP56600 Fractional Arithmetic Differences Fractional Operation DSP56600 Compiler SC100C Compiler Addition + Word16 add Word32 L_add Subtraction - Word16 sub Word32 L_sub Absolute value _fabs _lfabs Word16 abs_s Word32 L_abs Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 353 Freescale Semiconductor, Inc. MWEntComp.book Page 354 Monday, September 27, 2004 2:17 PM Migrating from Other Environments Migrating DSP56600 Code Table E.4 DSP56600 Fractional Arithmetic Differences (continued) Fractional Operation DSP56600 Compiler SC100C Compiler Multiplication * Word16 mult Word32 L_mult Word16 mult_r Shift right >> Word16 shr Word32 L_shr Shift left << Word16 shl Word32 L_shl Negate - Word16 negate Word32 L_negate Round _fract_round Word16 round Divide _pdiv Word16 div_s Normalize Can be implemented using _asm Word16 norm_s Word16 norm_l Saturation control Can be implemented using _asm void setnosat void setsat32 The Metrowerks Enterprise C compiler supports many other fractional operations, including 40-bit and 64-bit fractional functions, which the DSP56600 environment does not support. Inlined Assembly and C Code DSP56600 compilers use _inline and _asm to designate a C routine for inlining, as well as to define instructions, operands, and modifiers for inlined assembly statements. The Metrowerks Enterprise C compiler uses the pragma #pragma inline to specify an inlined function. Intrinsic Functions The Metrowerks Enterprise C compiler library routines support many DSP56600 intrinsic functions, as Table E.5 shows. 354 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 355 Monday, September 27, 2004 2:17 PM Migrating from Other Environments Migrating DSP56600 Code Table E.5 DSP56600 Intrinsic Function Differences Description DSP56600 Compiler SC100 C Compiler Bit field operations _bfchg() _bfclr() _bfset() _bftsth() _bftstl() Can be implemented by library routines Cache control _cache_get_start() _cache_get_end() _pflush() _pflushun() _pfree() _plock() _punlock() Not available Fraction to integer coercion _fract2int() _lfract2long Not needed (both represented by integers) Integer to fraction coercion _intt2fract() _long2lfract() Not needed (both represented by integers) Extend byte in accumulator _ext() Not applicable Fractional square root _fsqrt() Can be implemented by a library routine String copy (inlined) _strcmp() Supported as a library routine (strcmp) Absolute of long integer _labs labs() Insert NOP instruction _nop() _asm(“nop”) STOP instruction _stop() stop() Software interrupt _swi() trap() WAIT instruction _wait() wait() Viterbi operation _vsl Can be implemented by a library routine Pragmas To support the functions of DSP56600 inlined assembly pragmas asm, asm_noflush, and endasm, the Metrowerks Enterprise C compiler uses a function qualifier. The Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 355 Freescale Semiconductor, Inc. MWEntComp.book Page 356 Monday, September 27, 2004 2:17 PM Migrating from Other Environments Migrating DSP56600 Code optimization pragma #pragma loop_count is the equivalent of DSP56600 pragmas iterate_at_least_once and no_iterate_at_least_once. These DSP56600 pragmas have no equivalent in the Metrowerks Enterprise C compiler environment: • cache_align_now • cache_region_endpack_strings • cache_region_start • cache_sector_size • jumptable_memory • nopack_strings • nosource • source Interrupt Handlers The Metrowerks Enterprise C compiler pragma #pragma interrupt performs the function of both _fast_interrupt and _long_interrupt in the DSP56600 environment. Storage Specifiers The DSP56600 compilers support several storage specifiers, that the SC100 environment does not use, or specifies at link time. Table E.6 list these storage specifiers. : Table E.6 DSP56600 Storage Specifiers 356 Storage DSP56600 Compiler SC100 C Compiler X memory _X Not applicable Y_memory _Y Not applicable Program memory _P Not applicable L memory _L Not applicable Lowest 64 words in data memory _near Not applicable Internal memory _internal Specified at link time Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 357 Monday, September 27, 2004 2:17 PM Migrating from Other Environments Migrating TI6xx Code Table E.6 DSP56600 Storage Specifiers (continued) Storage DSP56600 Compiler SC100 C Compiler External memory _external Specified at link time Absolute address for global variable _at Specified at link time in the application configuration file Miscellaneous Table E.7 lists a few additional differences between the two compilers. Table E.7 DSP56600 Miscellaneous Differences Description DSP56600 Compiler SC100 C Compiler Wrap-around semantics for fractional data _nosat Not applicable Force DSP56300 GNU calling convention _compatible Not applicable Circular buffer support _circ Addressing calculations using the C modulo (%) operator Migrating TI6xx Code This section explains considerations for using the Metrowerks Enterprise C compiler with code developed for the TI6xx compiler family. Data Types TI6xx compilers map the integer type long to 40 bits. The Metrowerks Enterprise C compiler defines integer type long as 32 bits. If your C code relies on type long being 40 bits wide, you must modify the code before you migrate. Keywords The Metrowerks Enterprise C compilerdoes not support the TI6xx keywords cregister, near, or far. If you include the migration header file, the Metrowerks Enterprise C compiler accepts these keywords, but the keywords have no effect on compilation results. Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 357 Freescale Semiconductor, Inc. MWEntComp.book Page 358 Monday, September 27, 2004 2:17 PM Migrating from Other Environments Migrating TI6xx Code The Metrowerks Enterprise C compiler does support TI6xx keywords inline and interrupt, but implements them differently, using #pragma inline and #pragma interrupt. This prevents automatic translation, so you must modify your code to use these pragmas. Pragmas The Metrowerks Enterprise C compiler ignores TI6xx pragmas. It issues warnings if it finds such a pragma, but this does not affect correctness of the compilation. Inlined Assembly Code By definition, inlined assembly code is not portable from one environment to another. The SC100 Assembler cannot recognize inlined TI6xx assembly code, so issues error messages. Intrinsic Functions The Metrowerks Enterprise C compiler supports the TI6xx intrinsic functions listed in header file portc6xtoSC1.h. This support is functionally equivalent to these TI6xx intrinsic functions, but could affect performance significantly. 358 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 359 Monday, September 27, 2004 2:17 PM F Modulo Addressing Example The modulo addressing support provides a fully functional C implementation, regardless of the target or compiler. You can use a simulator on a PC or workstation to compile this example, and receive correct results. If you use the -mod option (of the Metrowerks Enterprise C compiler) to compile this example for the SC140 target processor, the compiler tries to use the modulo addressing mode. To do so, however, the compiler must verify that modulo addressing is valid. This means that the modulo must be equivalent to a conditional subtraction reflecting this modulo-addressing implementation on the target: if (Pointer > (Base + Mod)), then Pointer = Pointer - Mod Optimal modulo access support involves offsets; the base can be either an array or a pointer. Listing F.1 shows ways of using modulo addressing if bases are pointers. Listing F.1 Modulo Addressing Examples int fct(short *pt, short *pt1, unsigned int Max) { // First style: straightforward usage of the loop index // combined with modulo int i, j; int Acc = 0; for (i = j = 0; i<Max; i++, j++) { Acc = pt[i%3] + pt1[i%5]; } return Acc; } int fct_1(short *pt, short *pt1, unsigned int Max) { // Second style: explicit update of the // index : index = (index + step) % buf_size // // This one will always work if step < buf_size and Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 359 Freescale Semiconductor, Inc. MWEntComp.book Page 360 Monday, September 27, 2004 2:17 PM Modulo Addressing Example // if intial_value(index) < (pt + buf_size) int i, j, k; int Acc = 0; for (i = j = k = 0; i<Max; i++) { Acc = pt[j] + pt1[k]; j = (j+1)%3; k = (k+2)%7; } return Acc; } ;************************************************************** ; File Name : ce2.sl ; Invocation line: /home/comtools/enterprise/new_prod/real-bin/scc mod -s -c ce2.c ; ;************************************************************** .file "ce2.c" section .data local align 8 F__MemAllocArea align 4 endsec section .text local TextStart_ce2 bb_cs_offset__fct bb_cs_offset_DW_2 bb_cs_offset_DW_20 bb_cs_offset_DW_21 equ equ equ equ 0 2 22 20 ; ; ; ; at at at at _fct sp = 0 DW_2 sp = 2 DW_20 sp = 22 DW_21 sp = 20 ;*************************************************************** ; ; Function _fct ; ; Stack frame size: 48 ; ; Calling Convention: Standard ; ; Parameter pt passed in register r0 360 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 361 Monday, September 27, 2004 2:17 PM Modulo Addressing Example ; Parameter pt1 passed in register r1 ; Parameter Max passed in stack with offset -12 ; ; Returned value ret_fct passed in register d0 ; ;*************************************************************** _fct [ global align type _fct 16 func clr push push d0 r6 r7 ;[23] ;[17] ;[17] move.l adda (sp-20),r2 #40,sp,r6 ;[25] ;[0] tfra tfra r6,sp r0,r3 ;[0] ;[26] B1 tsteqa move.w r2 #<6,m0 ;[25] ;[0] B1 bt move.l <L2 (sp-60),d4 ;[25] ;[0] move.w bmset #<10,m1 #32768,mctl.l ;[0] ;[0] move.w tfra #<0,d0 r0,r11 ;[0] ;[0] max tfra bmset d0,d4 r1,r10 #2304,mctl.l ;[0] ;[0] ;[0] doensh3 tfra d4 r1,r2 ;[0] ;[26] ] DW_2 [ ] [ ] DW_4 [ ] [ ] [ ] [ ] [ ] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 361 Freescale Semiconductor, Inc. MWEntComp.book Page 362 Monday, September 27, 2004 2:17 PM Modulo Addressing Example nop nop loopstart3 ;[0] L_D_3 ;[0] L_D_3 move.w move.w ;[26] ;[26] L10 [ (r2)+,d1 (r3)+,d0 ] add d0,d1,d0 loopend3 bmclr #3840,mctl.l bmclr #61440,mctl.l ;[25] ;[0] ;[0] L2 move.w nop suba DW_20 [ pop pop ] DW_21 rts Ffct_end #40,r6 r6,sp ;[29] ;[0] AGU stall ;[29] r6 r7 ;[29] ;[29] ;[29] bb_cs_offset__fct_1 bb_cs_offset_DW_23 bb_cs_offset_DW_41 bb_cs_offset_DW_42 equ equ equ equ 0 2 26 24 ; ; ; ; at at at at _fct_1 sp = 0 DW_23 sp = 2 DW_41 sp = 26 DW_42 sp = 24 ;************************************************************** ; ; Function _fct_1 ; ; Stack frame size: 56 ; ; Calling Convention: Standard ; ; Parameter pt passed in register r0 ; Parameter pt1 passed in register r1 ; Parameter Max passed in stack with offset -12 ; ; Returned value ret_fct_1 passed in register d0 ; ;************************************************************** global 362 _fct_1 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 363 Monday, September 27, 2004 2:17 PM Modulo Addressing Example align \16 _fct_1 type func [ clr d0 push r6 push r7 ] DW_23 [ move.l (sp-20),r2 adda #48,sp,r6 ] [ tfra r6,sp tfra r1,r3 ] DW_25 [ tsteqa r2 move.w #<6,m0 ] bt <L4 move.l (sp-68),d4 [ move.w #2,n3 move.w #<14,m1 ] [ bmset #2048,mctl.l move.w #<0,d0 ] [ max d0,d4 tfra r1,r11 tfra r0,r10 ] [ doensh3 d4 bmset #36864,mctl.l ] tfra r0,r2 nop loopstart3 L9 [ move.w (r3)+n3,d1 move.w (r2)+,d0 ] ;[38] ;[32] ;[32] ;[40] ;[0] ;[0] ;[41] B1 ;[40] ;[0] B1 ;[40] ;[0] ;[0] ;[0] ;[0] ;[0] ;[0] ;[0] ;[0] ;[0] ;[0] ;[41] ;[0] L_D_3 ;[41] ;[41] Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 363 Freescale Semiconductor, Inc. MWEntComp.book Page 364 Monday, September 27, 2004 2:17 PM Modulo Addressing Example add d0,d1,d0 loopend3 bmclr #61440,mctl.l bmclr #3840,mctl.l ;[42] ;[0] ;[0] L4 move.w nop suba DW_41 [ pop pop ] DW_42 rts Ffct_1_end #48,r6 r6,sp ;[45] ;[0] AGU stall ;[45] r6 r7 ;[45] ;[45] ;[45] TextEnd_ce2 endsec 364 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 365 Monday, September 27, 2004 2:17 PM Index Symbols *asctime time function 178 *bsearch function 175 *ctime time function 178 *getenv environment function 175 *gmtime time function 179 *localtime time function 179 *qsort function 175 __DATE__ predefined macro 98 __FILE__ predefined macro 98 __INCLUDE_LEVEL__ predefined macro 99 __LINE__ predefined macro 98 __SIGNED_CHARS__ predefined macro 99 __STDC__ predefined macro 98 __STDC_VERSION__ predefined macro 99 __TIME__ predefined macro 98 __VERSION__ predefined macro 99 _ENTERPRISE_C_ predefined macro 99 _SC100_ predefined macro 99 _SC110_ predefined macro 99 _SC140_ predefined macro 99 Numerics 16-bit data values 59 40-bit data values 60 A abort environment function 175 abs integer arithmetic function 174 abs_s intrinsic function 63 access packing optimization 274–280 acos trigonometric function 167 add intrinsic function 63 add2 intrinsic function 63 adding directories to include path 31 addressing mode, forcing 87 administrative functions jmp_buf 169 longjmp 169 non-local jumps 169 NULL 169 offsetof 169 ptrdiff_t 169 raise 169 setjmp 169 signal 169 signal handling 169 size_t 169 standard definitions 169 va_arg 169 va_end 169 va_list 169 va_start 169 variable argument 169 wchar_t 169 align pragma 80, 81 aligning a function 83 variables 94, 95 allocating static data 122 application configuration files 126–137 applications, compiling 10 architecture defining 37 primitive functions 73–76 argument pointers, calling conventions 156, 157 arithmetic, fractional/integer 58–60 asin trigonometric function 167 assembly instruction, inlining one 101, 102 assembly sequence inlining defining 103–107 guidelines 102, 103 assumptions, optimizer 216 atan trigonometric function 167 atan2 trigonometric function 167 atexit environment function 175 atof string conversion function 174 atoi string conversion function 174 atol string conversion function 175 avoiding pipeline restrictions optimization 212 B bare board startup code 115 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 365 Freescale Semiconductor, Inc. MWEntComp.book Page 366 Monday, September 27, 2004 2:17 PM basic blocks, optimizer 182 big-endian mode, specifying 39 bit field types 57, 58 bit-reverse-induction optimization 251–256 br_inc intrinsic function 76 bss_seg_name pragma 81 C C dialects 40–50 K&R/PCC mode 45–50 standard extensions 40–45 C environment startup code 115, 116 C language options 33, 34 call_conv pragma 81 calling conventions 138–157 creating 142–156 examples 147–152 frame/argument pointers 156, 157 hardware loops 157 interrupt handlers 156 operating modes 157 remarks 145 rules 154–156 setting, configuration 133 specifying 145–147 stack frame layout 140, 141 stack pointer 138 stack-based 138–140 syntax extensions 152–154 calling function in different file 107–109 calloc memory allocation function 174 case study G279 cor_h 342–349 ceil function 168 changing preprocessed output 30 character types 52, 53 character typing/conversion libraries 160, 161 characteristics floating-point 161–163 integer 166 clearerr stream function 170 clearSRbit intrinsic function 73 clip intrinsic function 73 clock time function 178 clock_t time function 178 366 CLOCKS_PER_SEC 179 code migration overview 351 mixing 101–111 startup 113–117 transformations, optimizer 181, 182 command file, specifying 28, 29 common subexpression elimination optimization 199, 200 comparison functions 177 compilation stages 13–15 compiler shell program 13–20 using 13–99 compiling applications 10 components, configuration 134–137 composed variable loops 193, 194 composition of induction variables 238–241 concatenation functions 177 conditional execution/predication optimization 212, 213 conditional subtractions 248 configuration controlling 126–137 file, machine 123–126 files, defining 38 heap 121, 122 memory 119–126 memory map 122, 123 runtime stack 120, 121 stack and heap 120–122 startup code 116, 117 constant folding/propagation optimization 200, 201 constant, time 179 control option settings, configuration 131–133 control strategy, sequential accesses optimization 264–271 controlling cross-loop induction optimization 295 shell behavior 27–29 shell processing stops 27, 28 controlling configuration 126–137 affect on S1 files 137 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 367 Monday, September 27, 2004 2:17 PM calling convention setting 133 components 134–137 control option settings 131–133 section definition 128, 129 section settings 129 variable settings 130, 131 views 126–128 conventions, calling 138–157 copying functions 176, 177 initialized variables 39 cor_h case study 342–349 cos trigonometric function 167 cosh hyperbolic function 168 creating a program 11, 12 calling convention 142–156 cross-file optimization 9, 10, 15–17, 187 cross-loop induction controlling 295 linear domains 283, 284 loop nests 284, 285 optimization 280–295 cw_assert intrinsic function 76 D D_add intrinsic function 68 D_add_opt intrinsic function 68 D_cmpeq intrinsic function 68 D_cmpgt intrinsic function 69 D_extract_h intrinsic function 69 D_extract_l intrinsic function 69 D_get_lsb intrinsic function 69 D_get_msb intrinsic function 69 D_mac intrinsic function 69 D_msu intrinsic function 69 D_mult intrinsic function 69 D_mult_msp intrinsic function 69 D_mult_opt intrinsic function 69 D_round intrinsic function 70 D_sat intrinsic function 70 D_set intrinsic function 70 D_sub intrinsic function 70 data sizes 51 data types 51–62 bit fields 57, 58 characters 52, 53 floating point 55, 56 fractional 56 integers 53–55 intrinsic functions 60–62 long longs/doubles 51, 52 pointers 57 data values 16-bit 59 40-bit 60 data, static, allocation 122 data_seg_name pragma 81 Db_to_LL intrinsic function 72 DD_get_lsb intrinsic function 72 DD_get_msb intrinsic function 72 dead code elimination optimization 202 dead storage/assignment elimination optimization 202, 203 debug intrinsic function 75 debugev intrinsic function 75 declaration differences, K&R/PCC mode 47, 48 declarations, standard C 42 default_call_conv pragma 81 defining a loop count 89, 90 an interrupt handler 85 architecture 37 configuration files 38 inlined sequence 103–107 memory address mode 38, 39 preprocessor macros 30, 31 startup files 38 dependencies, optimization 188 detecting hardware-mappable loops 221–224 di intrinsic function 76 difftime time function 179 displaying shell help page 29 div integer arithmetic function 174 div_iter intrinsic function 66 div_s intrinsic function 63 double types 51, 52 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 367 Freescale Semiconductor, Inc. MWEntComp.book Page 368 Monday, September 27, 2004 2:17 PM double-precision fractional arithmetic primitive functions 68–70 DSP56600 code migration 352–357 dynamic loops 191, 192 dynamic memory allocation 121, 122 dynamic pragma 79 extended precision fractional arithmetic primitive functions 70–72 extensions, preprocessor 40, 41 Extract intrinsic function 66 extract_h intrinsic function 63 extract_l intrinsic function 63 ExtractU intrinsic function 66 E ei intrinsic function 76 elimination, common subexpressions 199, 200 EnableFPExceptions, floating-point interface 165, 166 environment functions 175, 176 runtime 113–157 variables 19, 20 environments, migrating from 351–358 examples access packing optimization 276–280 calling convention 147–152 calling convention setting, configuration 133 component, configuration 134–137 control option setting, configuration 131, 132 cross-loop induction 285–295 intrinsic functions 77, 78 loop optimizations 222–224 mixed high-dimension access 292–295 modulo addressing 359–364 partial matrix access 285, 286 section definition, configuration 128, 129 section settings, configuration 129 shifted triangular access 288–290 simple matrix, cross-loop induction optimization 280–283 triangular access 286–288 truncated triangular access 290–292 exit environment function 175 exp exponential function 168 exponential functions 168 expression/statement differences, K&R/PCC mode 49, 50 expressions/statements, standard C 43–45 368 F fabs function 168 far pragma 79, 81 fclose stream function 171 fct_never_return pragma 79 feof stream function 171 ferror stream function 171 fflush miscellaneous function 173 fgetc input function 170 fgetpos stream function 171 fgets output function 172 file extensions, overriding 31, 32 machine configuration 123–126 types and extensions 18, 19 filling delay slots optimization 211, 212 float.h 161–163 floating-point characteristics 161–163 library interface 163–166 math 167, 168 types 55, 56 floating-point functions exponential/logarithmic 168 hyperbolic 168 other 168 power 168 floating-point interface EnableFPExceptions 165, 166 FLUSH_TO_ZERO 164 IEEE_exceptions 164, 165 round mode 164 floor function 168 fltmath.h 163–166 FLUSH_TO_ZERO, floating-point interface 164 fmod function 168 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 369 Monday, September 27, 2004 2:17 PM fopen miscellaneous function 173 for/do-while loops 221, 222 forcing addressing mode 87 forcing modulo optimization 86 fprintf output function 172 fputc output function 172 fputs output function 172 fractional arithmetic 58–60 fractional arithmetic primitive functions 63–66 fractional types 56 frame pointers, calling conventions 156, 157 fread input function 170 free memory allocation function 174 freopen stream function 171 frexp exponential function 168 fscanf input function 170 fseek stream function 171 fsetpos stream function 171 ftell stream function 171 function pragmas 79, 80, 83–87 functions *asctime 178 *bsearch 175 *ctime 178 *getenv 175 *gmtime 179 *localtime 179 *qsort 175 abort 175 abs 174 acos 167 aligning 83 asin 167 atan 167 atan2 167 atexit 175 atof 174 atoi 174 atol 175 calling in different file 107–109 calloc 174 ceil 168 clearerr 170 clock 178 clock_t 178 comparison 177 concatenation 177 copying 176, 177 cos 167 cosh 168 defining interrupt handler 85 difftime 179 div 174 environment 175, 176 exit 175 exp 168 exponential/logarithmic 168 fabs 168 fclose 171 feof 171 ferror 171 fflush 173 fgetc 170 fgetpos 171 fgets 172 floor 168 fmod 168 fopen 173 fprintf 172 fputc 172 fputs 172 fread 170 free 174 freopen 171 frexp 168 fscanf 170 fseek 171 fsetpos 171 ftell 171 fwrite 172 general utility 174–176 getc 170 getchar 170 gets 172 hyperbolic 168 I/O library 170–173 inlining 83, 84, 199 input 170 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 369 Freescale Semiconductor, Inc. MWEntComp.book Page 370 Monday, September 27, 2004 2:17 PM integer arithmetic 174 intrinsic 60–78 jmp_buf 169 labs 174 ldexp 168 ldiv 174 log 168 log10 168 longjmp 169 malloc 174 mblen 176 mbstwcs 176 mbtowc 176 memchr 177 memcmp 177 memcpy 176 memmove 176 memory allocation 174 memset 178 miscellaneous I/O 173 mktime 179 modf 168 multibyte character 176 non-local jumps 169 non-standard returns 84, 85 NULL 169 offsetof 169 optimization 187–215 other 168 other string 178 output 172, 173 perror 173 pow 168 power 168 printf printf output function 173 program administrative 168, 169 pseudo random number generation 175 ptrdiff_t 169 putc 173 putchar 173 puts 173 raise 169 rand 175 realloc 174 370 remove 171 rename 171 rewind 171 scanf 170 search 177, 178 searching/sorting 175 setbuf 172 setjmp 169 setvbuf 172 signal 169 signal handling 169 sin 167 sinh 168 size_t 169 sprintf 173 sqrt 168 srand 175 sscanf 170 standard definitions 169 stderr 172 stdin 172 stdout 172 strcat 177 strchr 177 strcmp 177 strcoll 177 strcpy 177 strcspn 177 stream 170–172 strerror 178 strftime 179 string 176–178 string conversion 174, 175 strlen 178 strncat 177 strncmp 177 strncpy 177 strpbrk 178 strrchr 178 strspn 178 strstr 178 strtod 175 strtok 178 strtol 175 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 371 Monday, September 27, 2004 2:17 PM strtoul 175 strxfrm 177 system 176 tan 167 tanh 168 time 178–180 time_t 179 tmpfile 172 tmpnam 172 ungetc 173 va_arg 169 va_end 169 va_list 169 va_start 169 variable argument 169 vfprintf 173 vprintf 173 vsprintf 173 wchar_t 169 wcstombs 176 wctomb 176 fwrite output function 172 G general utility functions 174–176 generating listing/map files 35, 36 Get_Overflow intrinsic function 73 getc input function 170 getchar input function 170 gets output function 172 getting started 11, 12 guidelines, inlining an assembly sequence 102, 103 H hardware loops, calling conventions 157 hardware model/configuration options 37–39 heap configuration 121, 122 help page, displaying 29 hyperbolic functions 168 I I/O functions clearerr 170 fclose 171 feof 171 fflush 173 fgetc 170 fgetpos 171 fgets 172 fopen 173 fprintf 172 fputc 172 fputs 172 fread 170 freopen 171 frerror 171 fscanf 170 fseek 171 fsetpos 171 ftell 171 fwrite 172 getc 170 getchar 170 gets 172 input 170 miscellaneous 173 output 172, 173 perror 173 printf 173 putc 173 putchar 173 puts 173 remove 171 rename 171 rewind 171 scanf 170 setbuf 172 setvbuf 172 sprintf 173 sscanf 170 stderr 172 stdin 172 stdout 172 stream 170–172 tmpfile 172 tmpnam 172 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 371 Freescale Semiconductor, Inc. MWEntComp.book Page 372 Monday, September 27, 2004 2:17 PM ungetc 173 vfprintf 173 vprintf 173 vsprintf 173 I/O library functions 170–173 Icode options 217–219 file syntax 217, 218 list 218, 219 specifying 217 IEEE_exceptions, floating-point interface 164, 165 illegal intrinsic function 76 include path, adding directories 31 induction variables (IVs) bit-reverse induction 251–256 composition 238–241 conditional subtraction 248 min/max function induction 257–259 modulo classes 246, 247 modulo induction 243–251 modulo limitations 247, 248 modulo pointer/array value after loop 248– 251 monotonic 242, 243 multi-step 235–238 simple 232–235 simplifying redundant 259–262 types 231, 232 wraparound 241, 242 induction-related loop optimizations 221–295 induction-related optimizations loop detection/normalization 221–226 init_seg_name pragma 81 inititialized variables, copying 39 inline pragma 79 inline_call pragma 79 inlining a function 83, 84 assembly sequence 102–107 functions 199 one assembly instruction 101, 102 input functions 170 instruction scheduling optimization 210–212 integer 372 arithmetic 58–60 arithmetic functions 174 characteristics 166 types 53–55 interrupt handlers, calling conventions 156 interrupt pragma 80 intrinsic functions 60–78 abs_s 63 add 63 add2 63 architecture primitives 73–76 br_inc 76 clearSRbit 73 clip 73 cw_assert 76 D_add 68 D_add_opt 68 D_cmpeq 68 D_cmpgt 69 D_extract_h 69 D_extract_l 69 D_get_lsb 69 D_get_msb 69 D_mac 69 D_msu 69 D_mult 69 D_mult_msp 69 D_mult_opt 69 D_round 70 D_sat 70 D_set 70 D_sub 70 data types 60–62 Db_to_LL 72 DD_get_lsb 72 DD_get_msb 72 debug 75 debugev 75 di 76 div_iter 66 div_s 63 double-precision fractional arithmetic primitives 68–70 ei 76 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 373 Monday, September 27, 2004 2:17 PM examples 77, 78 extended precision fractional arithmetic primitives 70–72 Extract 66 extract_h 63 extract_l 63 ExtractU 66 fractional arithmetic primitives 63–66 Get_Overflow 73 illegal 76 L_abs 66 L_add 66 L_deposit_h 66 L_deposit_l 66 L_mac 63 L_max 67 L_maxm 67 L_min 67 L_msu 63 L_mult 67 L_mult_ls 73 L_mult_nomac 67 L_mult_sl 73 L_negate 67 L_rol 73 L_ror 74 L_sat 67 L_shl 67 L_shl_nosat 67, 76 L_shr 67 L_shr_nosat 68, 76 L_shr_r 68 L_sub 68 LL_get_lsb 73 LL_get_msb 73 LL_to_Db 73 long fractional arithmetic primitives 66–68 long long/double support 72, 73 mac_r 64 mark 76 max 64 max2 64 maxm 64 min 64 min2 64 miscellaneous 76, 77 mpysu 74 mpysu_shr16 73 mpyus 74 mpyus_shr16 73 mpyuu 74 msu_r 64 mult 64 mult_nomac 64 mult_r 65 neg_norm_l 76 neg_norm_s 65, 77 negate 65 norm_l 68 norm_s 65 optimized primitives 73 OSP 74 Ovl_Load_Address 74 Read_64 68 readSR 74 round 65 saturate 65 Set_Overflow 75 set2crm 74 setcnvrm 74 setnosat 74 setPPL 74 setsat32 75 setSRbit 75 shl 65 shl_nosat 65, 77 shr 65 shr_nosat 65, 77 shr_r 66 stop 76 sub 66 sub2 66 Test_Overflow 75 trap 76 trap_d 75 trap_r 75 wait 76 Write_64 68 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 373 Freescale Semiconductor, Inc. MWEntComp.book Page 374 Monday, September 27, 2004 2:17 PM writeOSP 75 writeSR 75 X_abs 70 X_add 70 X_cmpeq 70 X_cmpgt 70 X_extend 70 X_extract_h 70 X_extract_l 70 X_guard 70 X_mac 71 X_msu 71 X_mult 71 X_norm 71 X_or 71 X_rol 71 X_rol_unsafe 71 X_ror 71 X_ror_unsafe 71 X_round 71 X_sat 72 X_set 72 X_shl 72 X_shr 72 X_sub 72 X_trunc 72 X_xor 72 introduction 9–10 invoking the optimizer 186 the shell 20, 21 isalnum library 160 isalpha library 160 iscntrl library 160 isdigit library 160 isgraph library 160 islower library 160 isprint library 160 ispunct library 160 isspace library 160 isupper library 160 isxdigit library 161 IV (induction variable) types 231, 232 374 J jmp_buf non-local jump function 169 jump-to-jump elimination optimization 201 K K&R/PCC declaration differences 47, 48 expression/statement differences 49, 50 mode 45–50 preprocessor differences 46 remaining incompatibilities 50 syntax differences 46, 47 type differences 48, 49 L L_abs intrinsic function 66 L_add intrinsic function 66 L_deposit_h intrinsic function 66 L_deposit_l intrinsic function 66 L_mac intrinsic function 63 L_max intrinsic function 67 L_maxm intrinsic function 67 L_min intrinsic function 67 L_msu intrinsic function 63 L_mult intrinsic function 67 L_mult_ls intrinsic function 73 L_mult_nomac intrinsic function 67 L_mult_sl intrinsic function 73 L_negate intrinsic function 67 L_rol intrinsic function 73 L_ror intrinsic function 74 L_sat intrinsic function 67 L_shl intrinsic function 67 L_shl_nosat intrinsic function 67, 76 L_shr intrinsic function 67 L_shr_nosat intrinsic function 68, 76 L_shr_r intrinsic function 68 L_sub intrinsic function 68 labels, offset, including in output file 110, 111 labs integer arithmetic function 174 language features 39–99 layout memory 119–126 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 375 Monday, September 27, 2004 2:17 PM stack frame 140, 141 ldexp exponential function 168 ldiv integer arithmetic function 174 levels/options, optimizer 183–185 libraries character typing/conversion 160, 161 isalnum 160 isalpha 160 iscntrl 160 isdigit 160 isgraph 160 islower 160 isprint 160 ispunct 160 isspace 160 isupper 160 isxdigit 161 runtime 159–180 supported runtime 159, 160 testing functions 160, 161 tolower 161 toupper 161 library interface, floating-point 163–166 limitations ambiguous definition 326, 327 bypassed inner loop 335–338 conditional inner loop 334, 335 cross-loop 328–338 implicit cross-loop combination 331–334 induction variable redefinition 324–326 loop step restriction 328, 329 multiple condition induction 327 reused variables 330, 331 second order induction 328 sequential access/packing 338–342 single-loop induction 323–328 limits.h 166 linear domains, cross-loop induction 283, 284 linear/parallelized code, optimizer 182, 183 listing files 35, 36 listing/messages options 35–37 LL_get_lsb intrinsic function 73 LL_get_msb intrinsic function 73 LL_to_Db intrinsic function 73 locale.h 166, 167 locales 166, 167 log logarithmic function 168 log10 logarithmic function 168 logarithmic functions 168 long fractional arithmetic primitive functions 66– 68 long long types 51, 52 long long/double support functions 72, 73 longjmp non-local jump function 169 loop collapse optimization 297–300 count, defining 89, 90 detection/normalization 221–226 induction-related optimizations 221–295 invariant code optimization 200 multi-sampling optimization 311–315 nest, multi-sampling 98 nest, unrolling/jamming 97 nests, cross-loop induction 284, 285 optimization examples 222–224 peeling optimization 301, 302 restrictions 323–349 restrictions, types 323 restructuring/reordering 297–322 transformations 189–198 unroll-and-jam optimization 306–311 unrolling optimization 302–306 loop_count pragma 82 loop_multi_sample pragma 82 loop_unroll pragma 82 loop_unroll_and_jam pragma 82 loop-invariant code motion optimization 226, 227 loops ambiguous definition limitation 326, 327 bypassed inner-loop limitation 335–338 case study G279 cor_h 342–349 composed variable 193, 194 conditional inner-loop limitation 334, 335 cross-loop limitations 328–338 detecting hardware-mappable 221–224 dynamic 191, 192 for/do-while 221, 222 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 375 Freescale Semiconductor, Inc. MWEntComp.book Page 376 Monday, September 27, 2004 2:17 PM implicit cross-loop combination limitation 331–334 induction variable redefinition limitation 324–326 invariant code motion 226, 227 loop step restriction 328, 329 multiple condition induction limitation 327 multi-step 192, 193 normalizing hardware 225, 226 optimizing 97 partial summation optimization 315–322 pointer promotion 230, 231 reused variables limitation 330, 331 scalarization 227–230 second order induction limitation 328 sequential access/packing limitations 338– 342 simple 190, 191 single-loop induction 231–262 single-loop induction limitations 323–328 square 194–196 triangular 196–198 M mac_r intrinsic function 64 machine configuration file 123–126 macros __DATE__ 98 __FILE__ 98 __INCLUDE_LEVEL__ 99 __LINE__ 98 __SIGNED_CHARS__ 99 __STDC__ 98 __STDC_VERSION__ 99 __TIME__ 98 __VERSION__ 99 _ENTERPRISE_C_ 99 _SC100_ 99 _SC110_ 99 _SC140_ 99 predefined 98, 99 preprocessor 30, 31 malloc memory allocation function 174 map files 35, 36 376 mapping switch statements 90–93 mark intrinsic function 76 math functions exponential/logarithmic 168 hyperbolic 168 other 168 power 168 math, floating-point 167, 168 math.h 167, 168 mathematical functions acos 167 asin 167 atan 167 atan2 167 ceil 168 cos 167 cosh 168 exp 168 fabs 168 floor 168 fmod 168 frexp 168 ldexp 168 log 168 log10 168 modf 168 pow 168 sin 167 sinh 168 sqrt 168 tan 167 tanh 168 max intrinsic function 64 max2 intrinsic function 64 maxm intrinsic function 64 mblen multibyte character function 176 mbstowcs multibyte character function 176 mbtowc multibyte character function 176 memchr search function 177 memcmp comparison function 177 memcpy copying function 176 memmove copying function 176 memory dynamic, allocation 121, 122 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 377 Monday, September 27, 2004 2:17 PM layout/configuration 119–126 models 117, 118 memory address mode, defining 38, 39 memory allocation functions 174 memory map, configuring 122, 123 memset other string function 178 migrating DSP56600 code 352–357 migrating from other environments 351–358 migrating TI6xx code 357–358 min intrinsic function 64 min/max function induction optimization 257– 259 min2 intrinsic function 64 miscellaneous functions 76, 77 miscellaneous I/O functions 173 mixed high-dimension access optimization example 292–295 mixing C/assembly code 101–111 mktime time function 179 models, memory 117, 118 modf exponential function 168 modulo addressing example 359–364 induction 243–251 optimization, forcing 86 pointer/array value after loop 248–251 modulo IV classes 246, 247 limitations 247, 248 monotonic variables 242, 243 mpysu intrinsic function 74 mpysu_shr16 intrinsic function 73 mpyus intrinsic function 74 mpyus_shr16 intrinsic function 73 mpyuu intrinsic function 74 msu_r intrinsic function 64 mult intrinsic function 64 mult_nomac intrinsic function 64 mult_r intrinsic function 65 multibyte character functions 176 multi-sampling a loop nest 98 multi-step induction variables 235–238 loops 192, 193 N near pragma 80, 81 neg_norm_l intrinsic function 76 neg_norm_s intrinsic function 65, 77 negate intrinsic function 65 never_return pragma 80 noinline pragma 80 non-local jump functions 169 non-standard returns 84, 85 norm_l intrinsic function 68 norm_s intrinsic function 65 normalizing hardware loops 225, 226 noswitchtable pragma 80 NULL standard definition function 169 O offset labels, including in output file 110, 111 offsetof standard definition function 169 one assembly instruction, inlining 101, 102 operating modes, calling conventions 157 opt_level pragma 82 optimization avoiding pipeline restrictions 212 common subexpression elimination 199, 200 composed variable loops 193, 194 conditional execution/predication 212, 213 constant folding/propagation 200, 201 cross-file 9, 10, 15–17 dead code elimination 202 dead storage/assignment elimination 202, 203 dependencies/parallelization 188 dynamic loops 191, 192 filling delay slots 211, 212 function inlining 199 instruction scheduling 210–212 jump-to-jump elimination 201 level, specifying 95, 96 loop invariant code 200 loop transformations 189–198 multi-step loops 192, 193 peephole 206, 207 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 377 Freescale Semiconductor, Inc. MWEntComp.book Page 378 Monday, September 27, 2004 2:17 PM post-increment detection 207, 208 simple loops 190, 191 software pipelining 208–210 space 215 speculative execution 214, 215 square loops 194–196 strength reduction 189–198 target-independent 188–203 target-specific 203–215 techniques/hints 181–216 triangular loops 196–198 optimizations access packing 274–280 access packing examples 276–280 ambiguous definition limitation 326, 327 bit-reverse induction 251–256 bypassed inner-loop limitation 335–338 case study G729 cor_h 342–349 composition of induction variables 238–241 conditional inner-loop limitation 334, 335 conditional subtraction 248 controlling cross-loop induction 295 cross-loop induction 280–295 cross-loop induction examples 285–295 cross-loop induction linear domains 283, 284 cross-loop induction loop nests 284, 285 cross-loop induction simple matrix 280–283 cross-loop limitations 328–338 detecting hardware-mappable loops 221– 224 for/do-while loops 221, 222 implicit cross-loop combination limitation 331–334 induction variable (IV) types 231, 232 induction variable redefinition limitation 324–326 induction-related 221–295 loop collapse 297–300 loop detection/normalization 221–226 loop examples 222–224 loop multi-sampling 311–315 loop peeling 301, 302 loop step restriction 328, 329 378 loop unroll-and-jam 306–311 loop unrolling 302–306 loop-invariant code motion 226, 227 min/max function induction 257–259 mixed high-dimension access example 292– 295 modulo induction 243–251 modulo IV classes 246, 247 modulo IV limitations 247, 248 modulo pointer/array value after loop 248– 251 monotonic variables 242, 243 multiple condition induction limitation 327 multi-step induction variables 235–238 normalizing hardware loops 225, 226 partial matrix access example 285, 286 partial summation 315–322 pointer promotion 230, 231 reused variables limitation 330, 331 scalarization 227–230 second order induction limitation 328 sequential access/packing limitations 338– 342 sequential accesses 263–280 sequential accesses control strategy 264–271 shifted triangular access example 288–290 simple induction variables 232–235 simplifying redundant IVs 259–262 simplifying redundant memory accesses 271–274 single-loop induction 231–262 single-loop induction limitations 323–328 triangular access example 286–288 truncated triangular access example 290– 292 vectorization 274–280 wraparound variables 241, 242 optimized primitive functions 73 optimizer assumptions 216 basic blocks 182 code transformations 181, 182 cross-file optimizing 187 invoking 186 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 379 Monday, September 27, 2004 2:17 PM levels/options 183–185 linear/parallelized code 182, 183 optimizing for space 186 overview 181–185 types/functions 187–215 using 185–187 optimizing for space 186 optimizing loops 97 options C language 23, 33, 34 hardware model/configuration 26, 37–39 Icode 217–219 library/other 27 listing file/message output 25 listing/messages 35–37 optimization and code 24 output file extensions 22 output filename/location 22, 32, 33 passthrough 24 preprocessing 22, 30–31 shell behavior control 22 shell control 21–39 tools 34, 35 OSP intrinsic function 74 other environments, migrating from 351–358 functions 168 pragmas 81–83, 93–98 string functions 178 output file, including offset labels 110, 111 filename/location options 32, 33 functions 172, 173 overriding input file extensions 31, 32 overview code migration 351 manual 9 optimizer 181–185 Ovl_Load_Address intrinsic function 74 P parallelization, optimization 188 partial matrix access optimization example 285, 286 partial summation optimization 315–322 peephole optimization 206, 207 perror output function 173 pgm_seg_name pragma 83 pipelining optimization, software 208–210 placement, pragmas 79 pointer frame/argument, calling conventions 156, 157 promotion optimization 230, 231 stack 138 types 57 post-increment detection optimization 207, 208 pow power function 168 power functions 168 pragmas 78–98 align 80, 81 aligning a function 83 aligning variables 94, 95 bss_seg_name 81 call_conv 81 data_seg_name 81 default_call_conv 81 defining a loop count 89, 90 defining interrupt handler 85 dynamic 79 far 79, 81 fct_never_return 79 for functions 83–87 for statements 87–93 forcing addressing mode 87 forcing modulo optimization 86 function 79, 80 init_seg_name 81 inline 79 inline_call 79 inlining a function 83, 84 interrupt 80 loop_count 82 loop_multi_sample 82 loop_unroll 82 loop_unroll_and_jam 82 mapping switch statements 90–93 multi-sampling a loop nest 98 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 379 Freescale Semiconductor, Inc. MWEntComp.book Page 380 Monday, September 27, 2004 2:17 PM near 80, 81 never_return 80 noinline 80 non-standard returns 84, 85 noswitchtable 80 opt_level 82 optimizing loops 97 other 81–83, 93–98 pgm_seg_name 83 placement 79 profile 80 renaming ELF-file segments 96, 97 rom_seg_name 83 safe_mod 80 saving system context 85 specifying a profile value 87–89 specifying optimization level 95, 96 statement 80, 81 switchtable 80 switchtablebyte 80 switchtableword 81 syntax 78, 79 unrolling/jamming a loop nest 97 variables 81 predefined macros 98, 99 __DATE__ 98 __FILE__ 98 __INCLUDE_LEVEL__ 99 __LINE__ 98 __SIGNED_CHARS__ 99 __STDC__ 98 __STDC_VERSION__ 99 __TIME__ 98 __VERSION__ 99 _ENTERPRISE_C_ 99 _SC100_ 99 _SC110_ 99 _SC140_ 99 preprocessed output changing 30 preprocessing options 30–31 adding directories 31 changing output 30 defining macros 30, 31 preprocessor 380 differences, K&R/PCC mode 46 extensions 40, 41 processing stops, controlling 27, 28 profile pragma 80 profile value, specifying 87–89 program administrative functions 168, 169 pseudo random number generation functions 175 ptrdiff_t standard definition function 169 putc output function 173 putchar output function 173 puts output function 173 R raise signal handling function 169 rand pseudo random number generation function 175 Read_64 intrinsic function 68 readSR intrinsic function 74 realloc memory allocation function 174 remaining incompatibilities, K&R/PCC mode 50 remarks, creating calling convention 145 remove stream function 171 rename stream function 171 renaming ELF-file segments 96, 97 restrictions, loop 323–349 rewind stream function 171 rom_seg_name pragma 83 round intrinsic function 65 round mode, floating-point interface 164 rules, calling conventions 154–156 running a program 11, 12 runtime environment 113–157 runtime libraries 159–180 character typing/conversion 160, 161 isalnum 160 isalpha 160 iscntrl 160 isdigit 160 isgraph 160 islower 160 isprint 160 ispunct 160 isspace 160 isupper 160 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 381 Monday, September 27, 2004 2:17 PM isxdigit 161 supported 159, 160 testing functions 160, 161 tolower 161 toupper 161 runtime stack configuration 120, 121 S S1 files, configuration affect 137 safe_mod pragma 80 saturate intrinsic function 65 saving system context 85 scalarization optimization 227–230 scanf input function 170 search functions 177, 178 searching/sorting functions 175 section definition, configuration 128, 129 settings, configuration 129 segments, ELF-file, renaming 96, 97 sequential accesses optimization 263–280 Set_Overflow intrinsic function 75 set2crm intrinsic function 74 setbuf stream function 172 setcnvrm intrinsic function 74 setjmp non-local jump function 169 setnosat intrinsic function 74 setPPL intrinsic function 74 setsat32 intrinsic function 75 setSRbit intrinsic function 75 setvbuf stream function 172 shell behavior controlling processing stops 27, 28 displaying help page 29 specifying a command file 28, 29 shell control behavior options 22 C language options 23, 33, 34 controlling shell behavior 27–29 filename/location options 32, 33 hardware model/configuration options 26, 37–39 library/other options 27 listing file/message output options 25 listing/messages options 35–37 optimization and code options 24 options 21–39 options, summary 21–27 output file extensions options 22 output filename/location options 22 overriding file extensions 31, 32 passthrough options 24 preprocessing options 22, 30–31 tools options 34, 35 shell program 13–20 compilation stages 13–15 control options 21–39 cross-file optimization 15–17 environment variables 19, 20 file types and extensions 18, 19 invoking 20, 21 shifted triangular access optimization example 288–290 shl intrinsic function 65 shl_nosat intrinsic function 65, 77 shr intrinsic function 65 shr_nosat intrinsic function 65, 77 shr_r intrinsic function 66 signal handling functions 169 signal signal handling function 169 simple induction variables 232–235 simple loops 190, 191 simple matrix example, cross-loop induction 280–283 simplifying redundant IV optimization 259–262 simplifying redundant memory accesses optimization 271–274 sin trigonometric function 167 single-loop induction optimization 231–262 sinh hyperbolic function 168 size_t standard definition function 169 sizes and types 50–58 sizes, data 51 software pipelining optimization 208–210 space, optimizing for 186, 215 specifying a profile value 87–89 big-endian mode 39 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 381 Freescale Semiconductor, Inc. MWEntComp.book Page 382 Monday, September 27, 2004 2:17 PM calling convention 145–147 Icode options 217 optimization level 95, 96 shell command file 28, 29 speculative execution optimization 214, 215 sprintf output function 173 sqrt power function 168 square loops 194–196 srand pseudo random number generation function 175 sscanf input function 170 stack configuration 120–122 frame layout 140, 141 pointer 138 stack-based calling convention 138–140 stages, compilation 13–15 standard C declarations 42 expressions/statements 43–45 extensions 40–45 syntax 41, 42 types 42, 43 standard definition functions 169 starting 11, 12 startup code 113–117 bare board 115 C environment 115, 116 configuring 116, 117 startup files, defining 38 statement pragmas 80, 81, 87–93 static data allocation 122 stderr stream function 172 stdin stream function 172 stdio.h 170–173 stdlib.h 174–176 stdout stream function 172 stop intrinsic function 76 strcat concatenate function 177 strchr search function 177 strcmp comparison function 177 strcnpy copying function 177 strcoll comparison function 177 strcpy copying function 177 382 strcspn search function 177 stream functions 170–172 strength reduction 189–198 strerror other string function 178 strftime time function 179 string conversion functions 174, 175 string functions 176–178 comparison 177 concatenation 177 copying 176, 177 memchr 177 memcmp 177 memcpy 176 memmove 176 memset 178 other 178 search 177, 178 strcat 177 strchr 177 strcmp 177 strcoll 177 strcpy 177 strcspn 177 strerror 178 strlen 178 strncat 177 strncmp 177 strncpy 177 strpbrk 178 strrchr 178 strspn 178 strstr 178 strtok 178 strxfrm 177 string.h 176–178 strlen other string function 178 strncat concatenate function 177 strncmp comparison function 177 strpbrk search function 178 strrchr search function 178 strspn search function 178 strstr search function 178 strtod string conversion function 175 strtok search function 178 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com Freescale Semiconductor, Inc. MWEntComp.book Page 383 Monday, September 27, 2004 2:17 PM strtol string conversion function 175 strtoul string conversion function 175 strxfrm comparison function 177 sub intrinsic function 66 sub2 intrinsic function 66 supported runtime libraries 159, 160 switch statements, mapping 90–93 switchtable pragma 80 switchtablebyte pragma 80 switchtableword pragma 81 syntax differences, K&R/PCC mode 46, 47 extensions, calling conventions 152–154 Icode option file 217, 218 pragmas 78, 79 standard C 41, 42 system environment function 176 tolower library 161 tools options 34, 35 toupper library 161 trap intrinsic function 76 trap_d intrinsic function 75 trap_r intrinsic function 75 triangular access optimization example 286–288 triangular loops 196–198 truncated triangular access optimization example 290–292 type differences, K&R/PCC mode 48, 49 types and sizes 50–58 data 51 loop restrictions 323 optimization 187–215 standard C 42, 43 T U tan trigonometric function 167 tanh hyperbolic function 168 target-independent optimization 188–203 target-specific optimization 203–215 Test_Overflow intrinsic function 75 testing functions libraries 160, 161 TI6xx code migration 357–358 time constant 179 time function 179 time functions 178–180 *asctime 178 *ctime 178 *gmtime 179 *localtime 179 clock 178 clock_t 178 difftime 179 mktime 179 strftime 179 time 179 time_t 179 time.h 178–180 time_t time function 179 tmpfile stream function 172 tmpnam stream function 172 ungetc miscellaneous function 173 unrolling/jamming a loop nest 97 using the compiler 13–99 the optimizer 185–187 utility functions 174–176 *bsearch 175 *getenv 175 *qsort 175 abort 175 abs 174 atexit 175 atof 174 atoi 174 atol 175 calloc 174 div 174 environment 175, 176 exit 175 free 174 integer arithmetic 174 labs 174 ldiv 174 malloc 174 mblen 176 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com 383 Freescale Semiconductor, Inc. MWEntComp.book Page 384 Monday, September 27, 2004 2:17 PM mbstowcs 176 mbtowc 176 memory allocation 174 multibyte character 176 pseudo random number generation 175 rand 175 realloc 174 searching/sorting 175 srand 175 string conversion 174, 175 strtod 175 strtol 175 strtoul 175 system 176 wcstombs 176 wctomb 176 V va_arg variable argument function 169 va_end variable argument function 169 va_list variable argument function 169 va_start variable argument function 169 variable argument functions 169 variable settings, configuration 130, 131 variables aligning 94, 95 environment 19, 20 pragmas 81 vectorization optimization 274–280 vfprintf output function 173 views, configuration 126–128 vprintf output function 173 vsprintf output function 173 X X_abs intrinsic function 70 X_add intrinsic function 70 X_cmpeq intrinsic function 70 X_cmpgt intrinsic function 70 X_extend intrinsic function 70 X_extract_h intrinsic function 70 X_extract_l intrinsic function 70 X_guard intrinsic function 70 X_mac intrinsic function 71 X_msu intrinsic function 71 X_mult intrinsic function 71 X_norm intrinsic function 71 X_or intrinsic function 71 X_rol intrinsic function 71 X_rol_unsafe intrinsic function 71 X_ror intrinsic function 71 X_ror_unsafe intrinsic function 71 X_round intrinsic function 71 X_sat intrinsic function 72 X_set intrinsic function 72 X_shl intrinsic function 72 X_shr intrinsic function 72 X_sub intrinsic function 72 X_trunc intrinsic function 72 X_xor intrinsic function 72 W wait intrinsic function 76 wchar_t standard definition function 169 wcstombs multibyte character function 176 wctomb multibyte character function 176 wraparound variables 241, 242 Write_64 intrinsic function 68 writeOSP intrinsic function 75 writeSR intrinsic function 75 384 Metrowerks Enterprise C Compiler User Manual For More Information: www.freescale.com ">
/
Downloaden
Even een vriendelijke herinnering. U kunt het document hier bekijken. Maar het belangrijkste is dat onze AI het al heeft gelezen. Het kan complexe dingen in eenvoudige bewoordingen uitleggen, uw vragen in elke taal beantwoorden en u helpen snel te navigeren, zelfs in de langste of meest ingewikkelde documenten.
Advertentie