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.
ARM RealView Compilation Tools for BREW V1.2
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.