Home > Developer > Optimize ARM RVCTB

SophiaFramework : BREW  C++ Class Library & GUI Framework & XML Middleware

Optimize ARM RealView Compilation Tool for BREW

This page goes through the optimization process for the ARM RealView compilation tool, "RVCTB" ( RealView Compilation Tool for BREW v 1.2 ) enabling faster and smaller BREW applications.

Example of Constant Numbers (List 1)

* List 1 : Constant class
class my_rect {
private:
    int _x;
    int _y;
    int _width;
    int _height;
public:
    my_rect(void);
    my_rect(int x, int y, int width, int height);
};

my_rect::my_rect(void)
{
    return;
}

my_rect::my_rect(int x, int y, int width, int height)
    : _x(x), _y(y), _width(width), _height(height)
{
    return;
}

int func(my_rect const &rect)
{
    return reinterpret_cast<int>(&rect);
}

int main(void)
{
    my_rect const rect(0, 0, 100, 100);

    return func(rect);
}

List 1 is the code for a rectangle class. The code is simple, but contains unnecessary parts.

Figure 1 is the compiled code of list 1. (Compile options are set to the default RVCTB settings)

Figuer 1 : List 1 compiled
; generated by ARM C++ Compiler, ADS1.2 [Build 848]

; commandline [-O2 -S -apcs /ropi -fs "-IC:\ARM\RVCT_BREWv1_2\INCLUDE"]
                          CODE32

                          AREA ||.text||, CODE, READONLY

                  __ct__7my_rectFv PROC ; my_rect::my_rect()
;;;13     my_rect::my_rect(void)
;;;14     {
000000  e3500000          CMP      r0,#0
000004  03a00010          MOVEQ    r0,#0x10
000008  0afffffe          BEQ      __nw__FUi
00000c  e1a0f00e          MOV      pc,lr
;;;15       return;
;;;16     }
                          ENDP

          __ct__7my_rectFiN31 PROC ; my_rect::my_rect(int, int, int, int)
;;;18     my_rect::my_rect(int x, int y, int width, int height)
;;;19       : _x(x), _y(y), _width(width), _height(height)
000010  e92d40f8          STMFD    sp!,{r3-r7,lr}
000014  e59d4018          LDR      r4,[sp,#0x18]
000018  e1a07003          MOV      r7,r3
00001c  e1a06002          MOV      r6,r2
000020  e1a05001          MOV      r5,r1
000024  e3500000          CMP      r0,#0
000028  1a000003          BNE      |L1.60|
00002c  e3a00010          MOV      r0,#0x10
000030  ebfffffe          BL       __nw__FUi
000034  e3500000          CMP      r0,#0
000038  0a000001          BEQ      |L1.68|
;;;20     {
                  |L1.60|
00003c  e580400c          STR      r4,[r0,#0xc]
000040  e88000e0          STMIA    r0,{r5-r7}
;;;21       return;
                  |L1.68|
000044  e8bd80f8          LDMFD    sp!,{r3-r7,pc}
;;;22     }
                          ENDP

                  func__FRC7my_rect PROC ; func(const my_rect&)
;;;24     int func(my_rect const& rect)
;;;25     {
000048  e1a0f00e          MOV      pc,lr
;;;26       return reinterpret_cast<int>(&rect);
;;;27     }
                          ENDP

                  main PROC
;;;29     int main(void)
;;;30     {
00004c  e92d400f          STMFD    sp!,{r0-r3,lr}
000050  e3a00000          MOV      r0,#0                 ;20
000054  e58d0000          STR      r0,[sp,#0]            ;20
000058  e58d0004          STR      r0,[sp,#4]            ;20
00005c  e3a00064          MOV      r0,#0x64              ;20
000060  e58d0008          STR      r0,[sp,#8]            ;20
000064  e58d000c          STR      r0,[sp,#0xc]          ;20
000068  e1a0000d          MOV      r0,sp                 ;26
;;;31       my_rect const rect(0, 0, 100, 100);
;;;32
;;;33       return func(rect);
00006c  e28dd010          ADD      sp,sp,#0x10
000070  e49df004          LDR      pc,[sp],#4
;;;34     }
                          ENDP

        END

In C++, the constructor my_rect const rect (0, 0, 100, 100) will be called during execution even if the class is declared as constant.

Example of Constant POD Structure (List 2)

* List 2 : constant POD structure 
struct pod_rect {
    int x;
    int y;
    int width;
    int height;
};

int func(pod_rect const& rect)
{
    return reinterpret_cast<int>(&rect);
}

int main(void)
{
    pod_rect const rect = {0, 0, 100, 100};

    return func(rect);
}
Figure 2 : List 2 compiled
; generated by ARM C++ Compiler, ADS1.2 [Build 848]

; commandline [-O2 -S -apcs /ropi -fs "-IC:\ARM\RVCT_BREWv1_2\INCLUDE"]
                          CODE32

                          AREA ||.text||, CODE, READONLY

              func__FRC8pod_rect PROC ; func(const pod_rect&)
;;;8      int func(pod_rect const& rect)
;;;9      {
000000  e1a0f00e          MOV      pc,lr
;;;10       return reinterpret_cast<int>(&rect);
;;;11     }
                          ENDP

                  main PROC
;;;13     int main(void)
;;;14     {
000004  e92d400f          STMFD    sp!,{r0-r3,lr}
;;;15       pod_rect const rect = {0, 0, 100, 100};
000008  e59f1014          LDR      r1,|L1.36|
00000c  e08f1001          ADD      r1,pc,r1
000010  e1a0000d          MOV      r0,sp
000014  e891500c          LDMIA    r1,{r2,r3,r12,lr}
000018  e880500c          STMIA    r0,{r2,r3,r12,lr}
;;;16
;;;17       return func(rect);
00001c  e28dd010          ADD      sp,sp,#0x10
000020  e49df004          LDR      pc,[sp],#4
                  |L1.36|
000024  00000010          DCD      ||.constdata$1|| + 16 - {PC}
;;;18     }
                          ENDP

                          AREA ||.constdata||, DATA, READONLY, ALIGN=2

                  ||.constdata$1||
                          DCD      0x00000000
                          DCD      0x00000000
                          DCD      0x00000064
                          DCD      0x00000064

        END

List 2 is better than list 1 in both size and speed.

When initialization is done in POD type ( compatible with C ), a constant is stored in the constants area.
* Constructers can not be defined in this case.

Example of Class Supporting POD Type Initialization (List 3)

* List 3 : Class that supports POD type initialization
class my_rect {
public:
    struct atom {
        int x;
        int y;
        int width;
        int height;
        operator my_rect&(void);
        operator my_rect const&(void) const;
    };

private:
    int _x;
    int _y;
    int _width;
    int _height;

public:
    my_rect(void);
    my_rect(int x, int y, int width, int height);
};

my_rect::my_rect(void)
{
    return;
}

my_rect::my_rect(int x, int y, int width, int height)
    : _x(x), _y(y), _width(width), _height(height)
{
    return;
}

inline my_rect::atom::operator my_rect&(void)
{
    return *reinterpret_cast<my_rect*>(this);
}

inline my_rect::atom::operator my_rect const&(void) const
{
    return *reinterpret_cast<my_rect const*>(this);
}

int func(my_rect const& rect)
{
    return reinterpret_cast<int>(&rect);
}

int main(void)
{
    my_rect::atom const rect = {0, 0, 100, 100};

    return func(rect);
}

List 3 defines both the rectangle class and a POD type structure, but does the initialization as a POD type.

The object "rect" declared as a POD type structure ( "atom" in List 3 ) may be treated as a class object thanks to cast operators like my_rect&() defined in the "atom" structure. Class functions that accept arguments of type my_rect&, such as "func", can act upon this object.

The reinterpret_cast operator is used in cast operations. If the class does not contain any virtual functions or any virtual inheritance, then it is compatible with the POD type.

Figure 3 : List 3 compiled
; generated by ARM C++ Compiler, ADS1.2 [Build 848]

; commandline [-O2 -S -apcs /ropi -fs "-IC:\ARM\RVCT_BREWv1_2\INCLUDE"]
                          CODE32

                          AREA ||.text||, CODE, READONLY

                  __ct__7my_rectFv PROC ; my_rect::my_rect()
;;;23     my_rect::my_rect(void)
;;;24     {
000000  e3500000          CMP      r0,#0
000004  03a00010          MOVEQ    r0,#0x10
000008  0afffffe          BEQ      __nw__FUi
00000c  e1a0f00e          MOV      pc,lr
;;;25       return;
;;;26     }
                          ENDP

        __ct__7my_rectFiN31 PROC ; my_rect::my_rect(int, int, int, int)
;;;28     my_rect::my_rect(int x, int y, int width, int height)
;;;29       : _x(x), _y(y), _width(width), _height(height)
000010  e92d40f8          STMFD    sp!,{r3-r7,lr}
000014  e59d4018          LDR      r4,[sp,#0x18]
000018  e1a07003          MOV      r7,r3
00001c  e1a06002          MOV      r6,r2
000020  e1a05001          MOV      r5,r1
000024  e3500000          CMP      r0,#0
000028  1a000003          BNE      |L1.60|
00002c  e3a00010          MOV      r0,#0x10
000030  ebfffffe          BL       __nw__FUi
000034  e3500000          CMP      r0,#0
000038  0a000001          BEQ      |L1.68|
;;;30     {
                  |L1.60|
00003c  e580400c          STR      r4,[r0,#0xc]
000040  e88000e0          STMIA    r0,{r5-r7}
;;;31       return;
                  |L1.68|
000044  e8bd80f8          LDMFD    sp!,{r3-r7,pc}
;;;32     }
                          ENDP

                  func__FRC7my_rect PROC ; func(const my_rect&)
;;;44     int func(my_rect const& rect)
;;;45     {
000048  e1a0f00e          MOV      pc,lr
;;;46       return reinterpret_cast<int>(&rect);
;;;47     }
                          ENDP

                  main PROC
;;;49     int main(void)
;;;50     {
00004c  e92d400f          STMFD    sp!,{r0-r3,lr}
;;;51       my_rect::atom const rect = {0, 0, 100, 100};
000050  e59f1014          LDR      r1,|L1.108|
000054  e08f1001          ADD      r1,pc,r1
000058  e1a0000d          MOV      r0,sp
00005c  e891500c          LDMIA    r1,{r2,r3,r12,lr}
000060  e880500c          STMIA    r0,{r2,r3,r12,lr}
;;;52
;;;53       return func(rect);
000064  e28dd010          ADD      sp,sp,#0x10
000068  e49df004          LDR      pc,[sp],#4
                  |L1.108|
00006c  00000010          DCD      ||.constdata$1|| + 16 - {PC}
;;;54     }
                          ENDP

                          AREA ||.constdata||, DATA, READONLY, ALIGN=2

                  ||.constdata$1||
                          DCD      0x00000000
                          DCD      0x00000000
                          DCD      0x00000064
                          DCD      0x00000064

        END

The number of instructions in the main function has decreased. ( Caution: the ARM processer it not 1 instruction 1 cycle)

Example of Static Variables (List 4)

Variables of constants classes cannot be regarded as constant static variables, because the constructor will called. But if the value of a constant static variable does not change within the application, it can be used ( see "Practical Development with BREW using C++" ).

If the initialization of the constant class variable of is done in POD type, it can be regarded as a static constant variable. ( See List 4 )

* List 4 : Using static variable 
int main(void)
{
    static my_rect::atom const rect = {0, 0, 100, 100};

    return func(rect);
}

As shown in figure 4, the use of "static" in the code, greatly reduces the size of the main function.

Figure 4 : List 4 compiled (main function is extracted)
; generated by ARM C++ Compiler, ADS1.2 [Build 848]

; commandline [-O2 -S -apcs /ropi -fs "-IC:\ARM\RVCT_BREWv1_2\INCLUDE"]
                          CODE32

                          AREA ||.text||, CODE, READONLY

                  __ct__7my_rectFv PROC ; my_rect::my_rect()
;;;23     my_rect::my_rect(void)
;;;24     {
000000  e3500000          CMP      r0,#0
000004  03a00010          MOVEQ    r0,#0x10
000008  0afffffe          BEQ      __nw__FUi
00000c  e1a0f00e          MOV      pc,lr
;;;25       return;
;;;26     }
                          ENDP

          __ct__7my_rectFiN31 PROC ; my_rect::my_rect(int, int, int, int)
;;;28     my_rect::my_rect(int x, int y, int width, int height)
;;;29       : _x(x), _y(y), _width(width), _height(height)
000010  e92d40f8          STMFD    sp!,{r3-r7,lr}
000014  e59d4018          LDR      r4,[sp,#0x18]
000018  e1a07003          MOV      r7,r3
00001c  e1a06002          MOV      r6,r2
000020  e1a05001          MOV      r5,r1
000024  e3500000          CMP      r0,#0
000028  1a000003          BNE      |L1.60|
00002c  e3a00010          MOV      r0,#0x10
000030  ebfffffe          BL       __nw__FUi
000034  e3500000          CMP      r0,#0
000038  0a000001          BEQ      |L1.68|
;;;30     {
                  |L1.60|
00003c  e580400c          STR      r4,[r0,#0xc]
000040  e88000e0          STMIA    r0,{r5-r7}
;;;31       return;
                  |L1.68|
000044  e8bd80f8          LDMFD    sp!,{r3-r7,pc}
;;;32     }
                          ENDP

                  func__FRC7my_rect PROC ; func(const my_rect&)
;;;44     int func(my_rect const& rect)
;;;45     {

000048  e1a0f00e          MOV      pc,lr
;;;46       return reinterpret_cast<int>(&rect);
;;;47     }
                          ENDP

                  main PROC
;;;49     int main(void)
;;;50     {
00004c  e59f0004          LDR      r0,|L1.88|
000050  e08f0000          ADD      r0,pc,r0              ;41
;;;51       static my_rect::atom const rect = {0, 0, 100, 100};
;;;52
;;;53       return func(rect);
000054  e1a0f00e          MOV      pc,lr
                  |L1.88|
000058  00000000          DCD      ||.constdata$1|| - {PC}
;;;54     }
                          ENDP

                          AREA ||.constdata||, DATA, READONLY, ALIGN=2

                  ||.constdata$1||
                  ||rect@main_0||
                          DCD      0x00000000
                          DCD      0x00000000
                          DCD      0x00000064
                          DCD      0x00000064

        END

*The tricks for optimizing constanst classes may be used for character-string constants as well.