Top Banner
Search Advanced Search Log In | Not a Member? Support  ADC Home > Tools > This article provides an overview of the GNU Compiler Collection (GCC) from the Free Software Foundation and its use on Mac OS X. GCC is a free soft ware proj ect that has been used for many years to create software for UNIX and other platforms. Apple's developer tool Xcode (and previously, Project Builder) uses GCC under the hood for building executable images from source code. The GNU Debugger (GDB), a companion to GCC, comprises the foundation of the Xcode debugger. The examples presented here are command-line driven for several reasons: 1. Many UNIX devel opers are comforta ble with command-lin e based tool s. 2. Command-line tools provide a least common denominator for de velopers working on multiple platforms (including UNIX variants). 3. Many development projects are already set up with makefiles that simplify the build process. Rewriting those as Xcode project s may be time consuming and non-portabl e. 4. GCC is widely used in universities, and students new to Mac OS X programming will find the implementation on Mac OS X works very similarly to other platforms, with the addition of Apple-specific options. How GCC Works GCC consists of a set of tools that may be invoked using a single command plus options. True to the UNIX philosophy, the GCC tools perform specialized functions but work in harmony, passing the output from one tool as input to the next. GCC invokes these tools in a series of stages: compiler, assembler, and linker. 1. The compiler preprocesses, parses and analyzes source code; the output is a set of assembly language instructions. Preprocessing, which expands directives such as #include and #define , is performed by the compiler and not by a separate program. This is a change from previous versions of GCC. 2. The assembler produces object files from the assembly input. In the examples in this article the assemble r stage is included implicitly. 3. The linker transforms the object code into an executable image. Source and header file s may be any of several types, mos t common ly .c, .cc, .cp, .m, .mm, and .h on Mac OS X. GCC supports a variety of languages and extensions denoting source files, precompiled headers, source files not requiring preprocessing, and so on. Refer to the GCC manual for more information. A link is provi ded at the end of this article. Apple's vers ion of GCC is based on standa rd GCC relea ses and adds features that suppo rt Mac OS X. Some of these feature s get folde d in to the s tandard relea ses. Since GCC is an open source projec t it depends on its developer community for enhancements and fixes. Developers are encouraged to participate so that GCC can continue to evolve to support new languages, new processors, better optimization techniques, and so on. A Simple Example The Carbon Example (52KB) illust rates compiling , linkin g, and running a simple applicatio n that has no user inter face but does use a timer task . It install s the task in the Time Manag er queue. Every second the task trigge rs and invokes a Timer UPP, or callba ck functio n, defin ed in our source code. The callback simpl y logs the current time to stdout. The #include statement at the top of the file pulls in all other frameworks and headers used by the CoreServ ices
17

The GNU Compiler Collection on Mac OS X Development

Apr 07, 2018

Download

Documents

gbritososa
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 1/17

Search

Advanced Search

Log In | Not a Member? Support 

ADC Home > Tools >

This article provides an overview of the GNU Compiler Collection (GCC) from the Free Software Foundation and its

use on Mac OS X. GCC is a free software project that has been used for many years to create software for UNIX

and other platforms. Apple's developer tool Xcode (and previously, Project Builder) uses GCC under the hood for

building executable images from source code. The GNU Debugger (GDB), a companion to GCC, comprises the

foundation of the Xcode debugger.

The examples presented here are command-line driven for several reasons:

1. Many UNIX developers are comfortable with command-line based tools.

2. Command-line tools provide a least common denominator for developers working on multiple platforms

(including UNIX variants).

3. Many development projects are already set up with makefiles that simplify the build process. Rewriting

those as Xcode projects may be time consuming and non-portable.

4. GCC is widely used in universities, and students new to Mac OS X programming will find the implementation

on Mac OS X works very similarly to other platforms, with the addition of Apple-specific options.

How GCC Works

GCC consists of a set of tools that may be invoked using a single command plus options. True to the UNIX

philosophy, the GCC tools perform specialized functions but work in harmony, passing the output from one tool

as input to the next.

GCC invokes these tools in a series of stages: compiler, assembler, and linker.

1. The compiler preprocesses, parses and analyzes source code; the output is a set of assembly language

instructions. Preprocessing, which expands directives such as #include and #define , is performed by the

compiler and not by a separate program. This is a change from previous versions of GCC.

2. The assembler produces object files from the assembly input. In the examples in this article the assembler

stage is included implicitly.

3. The linker transforms the object code into an executable image.

Source and header files may be any of several types, most commonly .c, .cc, .cp, .m, .mm, and .h on Mac OS X.GCC supports a variety of languages and extensions denoting source files, precompiled headers, source files not

requiring preprocessing, and so on. Refer to the GCC manual for more information. A link is provided at the end

of this article.

Apple's version of GCC is based on standard GCC releases and adds features that support Mac OS X. Some of 

these features get folded in to the standard releases. Since GCC is an open source project it depends on its

developer community for enhancements and fixes. Developers are encouraged to participate so that GCC can

continue to evolve to support new languages, new processors, better optimization techniques, and so on.

A Simple Example

The Carbon Example (52KB) illustrates compiling, linking, and running a simple application that has no user

interface but does use a timer task. It installs the task in the Time Manager queue. Every second the task triggersand invokes a TimerUPP, or callback function, defined in our source code. The callback simply logs the current

time to stdout.

The #include statement at the top of the file pulls in all other frameworks and headers used by the CoreServices

Page 2: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 2/17

framework. The #include syntax is <frameworkName/headerFileName.h>. For example, Mac OS X Time Manager

tasks are handled by functions declared in Timer.h in the CarbonCore framework. Since CoreServices is an

umbrella framework, its single include file CoreServices.h includes CarbonCore/CarbonCore.h , which includes

CarbonCore/Timer.h and other appropriate headers. Put another way:

CoreServices/CoreServices.h includes CarbonCore/CarbonCore.h includes CarbonCore/Timer.h

This eases the burden on the programmer: rather than hunt down individual header files, you only need to include

one framework/header combination. You can include other frameworks as needed.

The top of the file contains declarations for several global variables, including the timer proc that gets installed inthe Time Manager queue. Once the application runs its course (five iterations), it disposes of the timer proc rather

than leave it installed.

main first calls an init function to setup the timer task, then loops waiting for a flag to set. After disposing of the

timer proc, main returns.

The timer proc (MyTimerProc) prints the current time and increments the counter. If the counter is below its limit,

MyTimerProc re-primes the timer task, otherwise it sets the done flag.

MyInit sets up the timer task, installs it, then primes it the first time.

You could write this application to instead provide a user interface with windows, menus, and so on. Simply

include the appropriate frameworks in the source code files.

#include <CoreServices/CoreServices.h>

void MyInit( void );

void MyTimerProc( TMTaskPtr tmTaskPtr );

Boolean gQuitFlag = false;

int gCount = 0;

TimerUPP gMyTimerProc = NULL;

int main( int argc, char *argv[])

{

MyInit();

while ( false == gQuitFlag ) {

;

}

DisposeTimerUPP( gMyTimerProc );

return 0;

}

 

void MyTimerProc( TMTaskPtr tmTaskPtr )

{

DateTimeRec localDateTime; 

GetTime( &localDateTime );

printf( "MyTimerProc at %d:%d:%d\n", localDateTime.hour,

localDateTime.minute, localDateTime.second );

gCount++;

if ( gCount > 4 )

{

gQuitFlag = true;

}

else{

PrimeTimeTask( ( QElemPtr ) tmTaskPtr, 1000 );

}

}

Page 3: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 3/17

void MyInit( void )

{

struct TMTask myTask;

OSErr err = 0;

gMyTimerProc = NewTimerUPP( MyTimerProc );

if ( gMyTimerProc != NULL )

{

myTask.qLink = NULL;

myTask.qType = 0;myTask.tmAddr = gMyTimerProc;

myTask.tmCount = 0;

myTask.tmWakeUp = 0;

myTask.tmReserved = 0;

 

err = InstallTimeTask( ( QElemPtr )&myTask );

 

if ( err == noErr )

PrimeTimeTask( ( QElemPtr )&myTask, 1000 );

else {

DisposeTimerUPP( gMyTimerProc );

gMyTimerProc = NULL;

gQuitFlag = true;

}

}

}

Mac OS X frameworks allow you to add system features and user interface capabilities to your applications. The

frameworks are arranged hierarchically, so you only need to include in your source code the top-level framework

of interest, rather than sub-frameworks underneath. When invoking GCC, the -framework linker option may be

fed to the compiler, which will pass the option to the linker. The following GCC invocation compiles test.c , links

against the CoreServices framework, and generates the executable output file test , as specified by the -o flag.

% gcc -framework CoreServices -o test test.c

To run the executable, invoke it by name. This example runs the file test in the current directory. The "./"

specifies that the path to the command starts in the current directory, and "test" is the name of the file to

execute. The output appears in the Terminal window.

% ./test

MyTimerProc at 16:41:27

MyTimerProc at 16:41:28

MyTimerProc at 16:41:29

MyTimerProc at 16:41:30

MyTimerProc at 16:41:31%

Useful Flags

Here are brief descriptions of several GCC command-line options:

The verbose flag (-v ) displays details of each command executed by GCC.

% gcc -v

Reading specs from /usr/libexec/gcc/darwin/ppc/3.3/specs

Thread model: posix

gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)

%

Page 4: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 4/17

Page 5: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 5/17

The -framework linker option was discussed above. This example links against the CoreServices framework,

and invokes the compiler in verbose mode (-v) so you can see the generated linker call. The output file will

be named test, and the input to this step is the file test.o .

% gcc -v -framework CoreServices -o test test.o

Reading specs from /usr/libexec/gcc/darwin/ppc/3.3/specs

Thread model: posix

gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)

ld -arch ppc -dynamic -o test -lcrt1.o -lcrt2.o -L/usr/lib/gcc/darwin/3.3

-L/usr/lib/gcc/darwin -L/usr/libexec/gcc/darwin/ppc/3.3/../../..-framework CoreServices test.o -lgcc -lSystem |

c++filt3

%

To link against multiple frameworks, include each with its own -framework flag:

-framework CoreServices -framework Carbon

You can change compiler versions using gcc_select .

sudo /usr/sbin/gcc_select <version: 2, 3 or 3.x>

% sudo /usr/sbin/gcc_select 3.1

Default compiler has been set to:

Apple Computer, Inc. GCC version 1256, based on gcc version 3.1 20021003

(prerelease)

%

The -l flag lists available compiler versions.

% gcc_select -l

Available compiler versions:

2.95.2 3.1 3.3 3.3-fast

%

Run gcc_select -h to view additional options.

The compiler version matters because changes to the Application Binary Interface since Mac OS X v10.0 have

rendered C++ and Objective-C++ executables incompatible with earlier releases. However, C and Objective-

C programs still run the same. To build for 10.1 and earlier you must use version 2 of GCC for C++/Obj-

C++ applications and kernel extensions; version 2.95.2 was the GCC final release that shipped with Mac OS

X v10.1. GCC version 3.1 shipped with Mac OS X v10.2 Jaguar, and 3.3 with Mac OS X v10.3 Panther. Notethat if you mix languages in the application you should rebuild using the appropriate compiler version:

2.95.2 for Mac OS X v10.0 and v10.1, 3.1 for v10.2 Jaguar, and 3.3 for v10.3 Panther.

This list is not exhaustive. Look at the man gcc pages or one of the recommended references at the end of this

article for additional flags.

Makefiles

Makefiles help automate the build process. A makefile is typically named makefile or Makefile , and contains

commands for GCC regarding various targets and their dependencies. You can change the commands in the file

and, once it is working, not worry about forgetting a flag or option. This is very useful in the middle of the night

when you are tired and likely to make mistakes. Since GCC command-line entries can get very long you are lesslikely to invoke it incorrectly.

A makefile contains a set of targets. Each target may be dependent on other targets. Each target also includes a

command-line invocation preceded by a <tab> character. Here is the syntax:

Page 6: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 6/17

# Comments begin with a '#'.

target-name: [dependency_1 dependency_2 ...]

command [flags] input-file(s)

another-target-name: dependency

command [flags] input-file(s)

The following example incorporates the test.c file used to generate the code optimization samples. The first

target, named test, depends on the target test.obj. If the output generated by target test.obj is newer than test, or

is not a file, then the make utility will run the appropriate command-line. In this case, invoke GCC and generate afile named test, using the file test.o as input.

Where does test.o come from? It is the output generated by the test.obj target. The input to target test.obj is

the file test.c. You can specify an output file using the -o option, or let GCC name the output file using the

pattern input-filename .o (lowercase letter 'o').

# The target named test depends on target test.obj.

# The command for target test:

# 1. invokes gcc,

# 2. generates a file named test (no extension) as output, and

# 3. uses file test.o as input.

#test: test.obj

gcc -o test test.o

#

# The next target name is test.obj. That is only its name.

# The name does not have to relate to what the target actually builds.

#

# This target builds object files from source.

# The command for test.obj instructs gcc to:

# 1. stop after compilation (no linking),

# 2. print verbose output, and

# 3. use the file test.c as input.

#

# The default output file name here will be test.o.

#

test.obj: test.c

gcc -c -v test.c

#

# Remove unwanted binaries, both the file named test and any .o files.

#

clean:

rm test *.o

#

# Generate assembly files. Useful for debugging.

#

asm0:

gcc -v -S -O0 -o test.O0.s test.c

asm1:gcc -v -S -O1 -o test.O1.s test.c

asm2:

gcc -v -S -O2 -o test.O2.s test.c

asm3:

gcc -v -S -O3 -o test.O3.s test.c

You invoke the make utility and specify the target, shown here from within a Terminal session. Any messages will

appear in the window.

$ make test

gcc -c -v test.c

Reading specs from /usr/libexec/gcc/darwin/ppc/3.3/specs

Thread model: posix

gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)

Page 7: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 7/17

/usr/libexec/gcc/darwin/ppc/3.3/cc1 -quiet -v -D__GNUC__=3 -D__GNUC_MINOR__=3

-D__GNUC_PATCHLEVEL__=0 -D__APPLE_CC__=1640 -D__DYNAMIC__ test.c -fPIC

-quiet -dumpbase test.c -auxbase test -version -o /var/tmp//ccmr23gL.s

GNU C version 3.3 20030304 (Apple Computer, Inc. build 1640) (ppc-darwin)

compiled by GNU C version 3.3 20030304 (Apple Computer, Inc. build 1640).

GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=131072

ignoring nonexistent directory "/usr/local/include"

ignoring nonexistent directory "/usr/ppc-darwin/include"

ignoring nonexistent directory "/Local/Library/Frameworks"

#include "..." search starts here:

#include <...> search starts here:

/usr/include/gcc/darwin/3.3/usr/include

End of search list.

Framework search starts here:

/System/Library/Frameworks

/Library/Frameworks

End of framework search list.

/usr/libexec/gcc/darwin/ppc/as -arch ppc -o test.o /var/tmp//ccmr23gL.s

gcc -o test test.o

$

If the make script is stored in a file named something other than makefile , pass the filename as a flag. Forexample, if the file was instead named test.mk, use:

make -f test.mk test

GNU Debugger

The GNU debugger (GDB) allows you to step through code, watch values, and monitor execution from the

command-line. Xcode uses GDB as the basis for its debugger. If you are using GCC you will want to also learn to

use GDB.

The first step is to compile your code with the -g flag: this includes GDB information in the object files. Without it

you will get strange errors when you try to use GDB to run your executable.

You invoke GDB using the gdb command along with the name of the executable to debug. GDB prints a banner,

after which it is ready to accept commands. The example used here is the Carbon application discussed earlier.

% gdb test

GNU gdb 5.3-20030128 (Apple version gdb-309) (Thu Dec 4 15:41:30 GMT 2003)

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "powerpc-apple-darwin".Reading symbols for shared libraries ... done

(gdb)

The best thing to start with is a breakpoint. This command sets a breakpoint on line 1.

(gdb) break 1

Breakpoint 1 at 0x1bd8: file test.c, line 1.

(gdb)

Begin execution by typing run . GDB prints information about what it is doing, then proceeds to and stops at the

breakpoint.

(gdb) run

Page 8: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 8/17

Starting program: /ktree/test

[Switching to thread 1 (process 1254 thread 0x1603)]

Reading symbols for shared libraries ......... done

Breakpoint 1, main (argc=795571314, argv=0x65652f74) at test.c:12

12 {

(gdb)

The step command steps into a function.

(gdb) step

MyInit () at test.c:47

47 OSErr err = 0;

(gdb)

Use the print command to view a variable value.

(gdb) print err

$1 = 0

(gdb)

Step over a function using next.

(gdb) next

main (argc=1, argv=0xbffffbb0) at test.c:13

13 MyInit();

(gdb) next

15 while ( false == gQuitFlag ) {

(gdb)

Next, set a breakpoint in the callback (line 28), then continue execution. GDB pauses when execution reaches thebreakpoint. Check the date/time value. Note that GDB does its best when displaying the structure fields. The

structure looks a bit strange, so check the data type of localDateTime using the whatis command. This action

may be performed on any variable that is in scope, and is useful if you do not want to jump back to a code editor

window and look at the source code.

(gdb) break 28

Breakpoint 2 at 0x2b8c: file test.c, line 28.

(gdb) continue

Continuing.

[Switching to process 1080 thread 0x1203]

Breakpoint 2, MyTimerProc (tmTaskPtr=0xbffffd10) at test.c:28

28 GetTime( &localDateTim e );

(gdb) print localDateTime

$3 = {

year = 0,

month = 119,

day = 25967,

hour = 7018,

minute = 0,

second = 0,

dayOfWeek = 0

}

(gdb) whatis localDateTime

type = DateTimeRec(gdb)

Step through the next couple of lines and view the formatted output, which looks correct.

Page 9: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 9/17

(gdb) step

30 printf( "MyTimerProc at %d:%d:%d\n", localDateTime .hour,

localDateTime.minute, localDateTime.second );

(gdb) step

MyTimerProc at 14:45:21

32 gCount++;

(gdb)

Use the where command to view a stack trace:

(gdb) where

#0 MyTimerProc (tmTaskPtr=0x bffffd10) at test.c:32

#1 0x902be7e8 in TimerThread ()

#2 0x900246e8 in _pthread_body ()

(gdb)

Change a variable value using se t. This example sets gCount past its threshold value and cause the program to

terminate prematurely. Notice that the source code following each line number is the next line to be executed,

not the last line executed.

(gdb) print gCount

$4 = 0

(gdb) step

34 if ( gCount > 4 )

(gdb) print gCount

$5 = 1

(gdb) set gCount = 5

(gdb) step

36 gQuitFlag = true;

(gdb) continue

Continuing.

Program exited normally.

(gdb)

Here is the conventional way to stop debugging and exit GDB:

(gdb) stop

(gdb) quit

Optimization

Code optimization may be performed by the programmer, the compiler, or the runtime environment. This section

focuses on optimizations that GCC can perform at build time. The typical tradeoff is to choose smaller code size

over faster execution speed, or vice versa. It is impossible to fully optimize for both at the same time, though

GCC does its best, as do other compilers. When in doubt, it may be better to optimize for size, since smaller code

may execute relatively faster. For example, large functions or loops containing data access patterns that do not

exhibit a strong locality of reference may not fit into a processor's cache lines, which can lead to cache misses

and subsequent fetches from memory. Smaller functions or loops with local data access stand a better chance of 

fitting in a given cache line and requiring fewer memory accesses.

Another reason for looking at optimization settings is because often developers debug without optimization

enabled, then release an optimized version to the public. Being familiar (not necessarily intimate) with the

assembly listing of your program under various optimization settings may help you determine where execution

failed when you receive the occasional crash report.

Remember that optimized code typically bears little resemblance to the original source code. This makes it

difficult to look at an assembly listing for an optimized program and determine the flow of control. It can be

nearly impossible to to look at a crash log and determine the point in an optimized program where a problem

occured, unless you have symbols included, which is not typically the case.

Page 10: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 10/17

Unoptimized code follows the original source code directly, making it easier to debug. In fact, you will have better

luck first debugging the code and then optimizing it, rather than the other way around. Trying to do both

simultaneously is also a bad idea.

You can use the -S GCC option to stop the compilation process before running the assembler. The following

command generates an unoptimized (level 0) output file named test.O0.s from input file test.c . You can then

dissect the assembly code in the file using a text editor.

gcc -S -O0 -o test.O0.s test.c

Several of the common options are discussed here. The GCC manual contains additional information regarding

optimization settings. The source code and assembly listings are available in the Optimization Example (88KB)

folder.

Optimization levels and modes

Level 0

Using an optimization flag of -O0 turns off optimization. This is the best setting when debugging code the

first time, and maybe beyond. You should use this setting to generate a baseline build from which to start

your debugging and subsequent performance analysis efforts. The machine instructions map easily to the

source code, so to twist the WYSIWYG acronym a bit, "what you wrote is what you get" in the debugger.

Several Level 0 examples are provided for reference in the following discussions.

Level 1

GCC attempts to both reduce the code size and execution time. Only certain types of optimizations apply

here. Register allocation attempts to place as many variables in registers as will fit, for faster access and

fewer load/store instruction pairs.

This function generates the accompanying machine instructions under Level 0 and Level 1:

void arrayAssignmentLoop( void ) {

unsigned int count = 10;

unsigned int array[ 10 ], item = 0;

do {array[ item++ ] = count;

count--;

} while ( count > 0 );

}

With no optimization (-O0 ) enabled, the value for count is stored and updated on the stack.

_arrayAssignmentLoop:

stmw r30,-8(r1)

stwu r1,-128(r1)

mr r30,r1li r0,10

stw r0,32(r30) ; count stored at 32 bytes off the SP

li r0,0

stw r0,96(r30)

L11:

addi r11,r30,96

lwz r9,0(r11)

mr r0,r9

slwi r2,r0,2

addi r0,r30,32

add r2,r2,r0

addi r2,r2,16

lwz r0,32(r30)stw r0,0(r2)

addi r9,r9,1

stw r9,0(r11)

lwz r2,32(r30) ; Load count into r2

addi r0,r2,-1 ; Decrement count

Page 11: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 11/17

stw r0,32(r30) ; Store count back on the stack

lwz r0,32(r30) ; Load count for comparison

cmpwi cr7,r0,0

bne cr7,L11

lwz r1,0(r1)

lmw r30,-8(r1)

blr

Enabling Level 1 optimization (-O1) moves those values to registers. It eliminates the need for the variable

count, loading and using the count register instead.

_arrayAssignmentLoop:

li r0,10 ; max stored in r0

mtctr r0 ; Move 10 to count register

; var count has been optimized away

li r2,0

addi r9,r1,-64

L10:

slwi r0,r2,2

mfctr r11

stwx r11,r9,r0

addi r2,r2,1

bdnz L10 ; Decrement count register and branch if not zeroblr

Level 2

GCC applies additional optimizations but excludes loop unrolling and implicit function inlining, both of which

reduce execution time but increase code size. You can use the inline keyword to indicate functions that

should be inlined and GCC will make a determination on whether to perform inlining. Common

subexpression elimination, strength reduction, and loop optimizations are also performed. (See definitions in

the following section, Specific Optimizations .)

For example, this source code generates the accompanying machine instructions under Level 0 and Level 2:

unsigned int doWhileWithReturn( void ) {

unsigned int i = 100;

unsigned int result = 0;

unsigned int a = 31, b = 2, c = 99;

do {

result += a * b;

c = a * b;

} while ( i-- > 0 );

 

c = a * b;

 

return result;}

Here is the unoptimized code (the -O0 option):

_doWhileWithReturn:

stmw r30,-8(r1) ; save non-volatile registers

stwu r1,-80(r1) ; SP update

mr r30,r1 ; i

li r0,100

stw r0,32(r30)

li r0,0 ; resultstw r0,36(r30)

li r0,31 ; a

stw r0,40(r30)

li r0,2 ; b

Page 12: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 12/17

stw r0,44(r30)

li r0,99 ; c

stw r0,48(r30)

L16:

lwz r2,40(r30) ; load a into r2

lwz r0,44(r30) ; load b into r0

mullw r2,r2,r0 ; multiply a and b, store in r2

lwz r0,36(r30) ; load result

add r0,r0,r2 ; add product to result

stw r0,36(r30) ; store new value of result

lwz r2,40(r30)

lwz r0,44(r30)mullw r0,r2,r0 ; multiply a and b, store in r0

stw r0,48(r30) ; store new value of c

lwz r2,32(r30) ; load i

addi r0,r2,-1 ; subtract 1 from i

mr r2,r0

stw r2,32(r30) ; store i

li r0,-1

cmpw cr7,r2,r0 ; compare i to -1, update condition register

bne cr7,L16 ; loop if i > 0 (branch to label l16)

lwz r2,40(r30)

lwz r0,44(r30)

mullw r0,r2,r0 ; multiply a and b, store in r0

stw r0,48(r30) ; store new value of c

lwz r0,36(r30) ; Load result

mr r3,r0 ; Move result to r3

lwz r1,0(r1) ; Restore SP

lmw r30,-8(r1) ; Restore registers

blr ; Return

The -O 2 option optimizes most of the loop and eliminates unused variables:

_doWhileWithReturn:

li r0,101 ; Load count register with 101

mtctr r0

L21: ; Loop has been almost completely optimized away

bdnz L21 ; Decrement count register and branch to label L21

; if not zero

li r3,6262 ; Load result value of 6,262 into r3

blr

Level 3

GCC applies additional optimizations including implicit inlining, or inlining of functions not marked with the

keyword inline . This is a general-purpose speed optimization setting.

Fast

This mode, invoked by -fast (for C and Objective-C; use -fastf for C++ and Objective-C++), packages a

number of optimizations that target the G5. This mode generates faster, though probably larger, code. It will

unroll loops, transpose nested loops (change the access order to improve locality of reference), convert loop

initialization to memset calls, and inline library calls.

This setting aggressively inlines functions. For example, here is a main function that, aside from a few

variable assignments, simply calls other functions.

int main( void ) {

unsigned int result;

double doubleResult;

 

arrayAssignmentLoop();

 

result = doWhileWithReturn();

printf( "doWhileWithReturn returned %d\n", result );

Page 13: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 13/17

doubleResult = doubleTest();

printf( "doubleTest returned %lf\n", doubleResult );

return 0;

}

The unoptimized version calls each function:

_main:mflr r0

stmw r30,-8(r1)

stw r0,8(r1)

stwu r1,-96(r1)

mr r30,r1

bcl 20,31,"L00000000001$pb"

"L00000000001$pb":

mflr r31

bl L_arrayAssignm entLoop$stub ; Branch to arrayAssignme ntLoop

bl L_doWhileWithR eturn$stub ; Branch to doWhileWithRe turn

mr r0,r3

stw r0,64(r30)

addis r3,r31,ha16(LC0-"L00000000001$pb")la r3,lo16(LC0-"L00000000001$pb")(r3)

lwz r4,64(r30)

bl L_printf$stub

bl L_doubleTest$s tub ; Branch to doubleTest

...

The -fast optimized version has inlined the calls to arrayAssignmentLoop and doWhileWithReturn :

_main:

mflr r2

li r3,2 ; Begin inlined and unrolled arrayAssignmen tLoopli r11,10

li r10,9

li r9,8

li r8,7

li r7,6

li r6,5

li r5,4

stw r2,8(r1)

stwu r1,-128(r1)

li r4,3

stw r3,96(r1)

stw r11,64(r1)

stw r10,68(r1)

stw r9,72(r1)

stw r8,76(r1)

stw r7,80(r1)

stw r6,84(r1)

stw r5,88(r1)

stw r4,92(r1) ; End of arrayAssignmen tLoop

li r3,1

li r2,99

stw r3,100(r1)

.p2align 4,,15

L149: ; Top of loop for doWhileWithRet urn

cmpwi cr0,r2,3

addi r2,r2,-4

bne cr0,L149 ; Branch to top of looplis r5,ha16(LC1)

li r4,6262 ; Result of doWhileWithRe turn

la r3,lo16(LC1)(r5)

bl L_printf$stub

Page 14: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 14/17

bl _doubleTest ; Branch to doubleTest

...

Size

You can force smaller code size using the -O s flag. Smaller code may be a good choice because it can reduce

cache misses and paging.

This example compares doubleTest under both -fast and -Os . Here is the source code:

double doubleTest( void ) {const unsigned int limit = 100;

double array[ limit ][ limit ], sum = 0;

unsigned int i, j;

 

for ( i = 0; i < limit; i++ ) {

for ( j = 0; j < limit; j++ ) {

array[ i ][ j ] = i;

sum += array[ i ][ j ];

}

}

return sum;

}

Under -fast the inner loop gets unrolled, resulting in 10 each of the instructions stfd (store double

precision floating-point) and fadd (floating-point add double precision).

_doubleTest:

...

L117: ; Top of outer loop

rldicl r5,r11,0,32

li r9,0

add r2,r10,r8

std r5,32(r30)lfd f2,32(r30)

fcfid f0,f2

.p2align 4,,15

L116: ; Top of inner loop

fadd f11,f1,f0

addi r9,r9,10

stfd f0,0(r2)

stfd f0,8(r2)

stfd f0,16(r2)

stfd f0,24(r2)

cmplwi cr0,r9,99

stfd f0,32(r2)

stfd f0,40(r2)stfd f0,48(r2)

stfd f0,56(r2)

stfd f0,64(r2)

stfd f0,72(r2)

addi r2,r2,80

fadd f10,f11,f0

fadd f9,f10,f0

fadd f8,f9,f0

fadd f7,f8,f0

fadd f6,f7,f0

fadd f5,f6,f0

fadd f4,f5,f0

fadd f3,f4,f0

fadd f1,f3,f0

ble cr0,L116 ; Branch to top of inner loop

addi r11,r11,1

addi r10,r10,800

cmplwi cr1,r11,99

Page 15: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 15/17

ble cr1,L117 ; Branch to top of outer loop

...

Under -O s the inner loop is much tighter, with only 1 store and add pair per iteration. A profiler can help you

determine whether this executes quicker than the -fast version.

_doubleTest:

...

L41: ; Top of outer loop

stw r9,36(r30)li r8,100

stw r10,32(r30)

mtctr r8

lfd f0,32(r30)

add r2,r11,r0

fsub f0,f0,f13

L46: ; Top of inner loop

stfd f0,0(r2) ; Store followed by add

fadd f1,f1,f0

addi r2,r2,8

bdnz L46 ; Branch to top of inner loop

addi r9,r9,1

addi r11,r11,800cmplwi cr7,r9,99

ble+ cr7,L41 ; Branch to top of outer loop

...

Specific optimizations

Loop unrolling

Expand a loop to include two or more iterations before checking the loop conditional. Use the flag -floop-

optimize .

Inlining functions

Functions with a line count below a certain threshold may have their instruction sequence substituted for thecorresponding function call. Since function calls involve overhead for stack frame setup, this may result in

faster (though longer) code. Turn on inlining using -finline-functions .

Strength reduction

Replace expensive operations with simpler operations. Use -fstrength-reduce .

For example, this loop:

for ( i = 0; i < 1000; i++ )

sum += i * 5;

generates this unoptimized code:

li r0,0

stw r0,40(r30) ; sum

li r0,0

stw r0,32(r30) ; i

... ; Top of loop

lwz r0,32(r30) ; Load i into r0

mulli r2,r0,5 ; Multiply r0 by 5, place result in r2

lwz r0,40(r30) ; Load sum

add r0,r0,r2 ; Add r2 to sum

stw r0,40(r30) ; Store new sum... ; Update i and branch to top of loop

This optimized version replaces the multiplication in the loop with an add:

Page 16: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 16/17

li r3,0 ; sum

li r2,0 ; i

L30:

add r3,r3,r2 ; Update sum

addi r2,r2,5 ; Add 5 to r2 each iteration: 5 + 5 + 5 ...

bdnz L30

...

Dead code elimination

Remove unused code from the final image, reducing its size. This is currently an experimental feature in

GCC: use the flag -fssa-dce.

Common subexpression elimination

Replace multiple references to the same expression with the result of that expression (calculated once).

Several variants exist, but the basic version is -fgcse .

Loop invariants

An expression whose value does not change between loop iterations may be move out of the loop. The flag -

floop-optimize handles this and other loop optimizations.

Instruction scheduling

Scheduling for a particular processor may result in faster execution on such a system, though running the

same code on other processors may be less efficient.

Cross-module inlining

In this mode the compiler has the entire application (all compilation units) in view when determining what

and where to inline. Cross module inlining is enabled by two things: -fast and the inclusion of all

compilation units on a single compiler invocation command line.

Feedback-directed-optimization under -fast

With Feedback Directed Optimization (FDO) the compiler uses a runtime profile of the application in order to

make inlining and hot/cold code location decisions. It does this via a three step process:

1. build the app using -fast with -fcreate-profile specified;

2. run the app with a model set of data;

3. rebuild the app using -fast with -fuse-profile to generate the FDO based optimization.

Additional optimization settings are described in the GCC manual.

For More Information

This article touched on the fundamentals of GCC, optimization, make , and GDB. The following resources provide

additional information about these tools on Mac OS X:

 Join or search the darwin-dev mailing list.

The GCC and GDB Release Notes

The GCC and GDB manuals. When you install Xcode, you will also find these on your local drive at:

/Developer/Documentaton/DeveloperTools/

In Terminal, see the ma n pages for the gcc, gdb , and make commands.

See the Compiler documentation under Tools Documentation; also, this documentation is installed with

Xcode, and is found at: /Developer/Documentaton/DeveloperTools/

Also try these non-ADC resources:

Programming with GNU Software and other titles from O'Reilly & Associates, Inc.

Efficient Memory Programming, originally published by McGraw-Hill but now available as an e-book,

discusses code design techniques that can be applied by the programmer in order to improve the compiler's

chances of effectively optimizing the code.

Various compiler books discuss code optimization algorithms and implementation.

If you want to keep up with GCC on other platforms try the GCC home page. Keep in mind that Apple-specific

builds and docs are not available on this site.

Posted: 2004-07-12

Page 17: The GNU Compiler Collection on Mac OS X Development

8/6/2019 The GNU Compiler Collection on Mac OS X Development

http://slidepdf.com/reader/full/the-gnu-compiler-collection-on-mac-os-x-development 17/17

Get information on Apple products.Visit the Apple Store online or at retail locations.

1-800-MY-APPLE

Copyright © 2010 Apple Inc.All rights reserved. | Terms of use | Privacy Notice