Intermediate Optimizations. NXP CodeWarrior Development Studio
Quảng cáo
Quảng cáo
Chapter 18 Intermediate Optimizations
18.1.5.4 Unnamed Structures and Enumerations in C
The C language allows anonymous struct
and enum
definitions in type definitions. Using such definitions prevents the compiler from properly applying program-level interprocedural analysis. Make sure to give names to structures and enumerations in type
definitions. Listing 18-6 on page 315
shows an example of unnamed structures and enumerations and
shows a suggested solution.
Listing 18-6. Unnamed structures and enumerations in C
/* In C, the types x_rec and y_enum each represent a structure
and an enumeration with no name.
In C++ these same statements define a type x_rec and y_enum,
a structure named x_rec and an enumeration named y_enum.
*/ typedef struct { int a, b, c; } x_rec; typedef enum { Y_FIRST, Y_SECOND, Y_THIRD } y_enum;
Listing 18-7. Naming structures and enumerations in C
typedef struct x_rec { int a, b, c; } x_rec; typedef enum y_enum { Y_FIRST, Y_SECOND, Y_THIRD } y_enum;
18.2 Intermediate Optimizations
After it translates a function into its intermediate representation, the compiler may optionally apply some optimizations. The result of these optimizations on the intermediate representation will either reduce the size of the executable code, improve the executable code's execution speed, or both.
•
•
•
Common Subexpression Elimination
•
•
•
•
•
•
18.2.1 Dead Code Elimination
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
Freescale Semiconductor, Inc.
315
Intermediate Optimizations
The dead code elimination optimization removes expressions that are not accessible or are not referred to. This optimization reduces size and increases execution speed.
Table 18-2 explains how to control the optimization for dead code elimination.
Table 18-2. Controlling dead code elimination
Turn control this option from here...
CodeWarrior IDE source code command line
use this setting
#pragma opt_dead_code on | off | reset
-opt [no]deadcode
In
, the call to func1()
will never execute because the if
statement that it is associated with will never be true. Consequently, the compiler can safely eliminate the call to func1()
Figure 18-1. Before dead code elimination
void func_from(void)
{
if (0)
{
func1();
}
func2();
}
Figure 18-2. After dead code elimination
void func_to(void)
{
func2();
}
18.2.2 Expression Simplification
The expression simplification optimization attempts to replace arithmetic expressions with simpler expressions. Additionally, the compiler also looks for operations in expressions that can be avoided completely without affecting the final outcome of the expression. This optimization reduces size and increases speed.
Table 18-3 explains how to control the optimization for expression simplification.
Table 18-3. Controlling expression simplification
Turn control this option from here...
CodeWarrior IDE
Table continues on the next page...
use this setting
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
316 Freescale Semiconductor, Inc.
Chapter 18 Intermediate Optimizations
Table 18-3. Controlling expression simplification (continued)
source code
Turn control this option from here...
command line
use this setting
There is no pragma to control this optimization.
-opt level=1 , -opt level=2 , -opt level=3 , -opt level=4
For example, Figure 18-3 contains a few assignments to some arithmetic expressions:
• addition to zero
• multiplication by a power of 2
• subtraction of a value from itself
• arithmetic expression with two or more literal values
Figure 18-3. Before expression simplification
void func_from(int* result1, int* result2, int* result3, int* result4, int x)
{
*result1 = x + 0;
*result2 = x * 2;
*result3 = x - x;
*result4 = 1 + x + 4;
}
Figure 18-4 shows source code that is equivalent to expression simplification. The
compiler has modified these assignments to:
• remove the addition to zero
• replace the multiplication of a power of 2 with bit-shift operation
• replace a subtraction of x from itself with 0
• consolidate the additions of 1 and 4 into 5
Figure 18-4. After expression simplification
void func_to(int* result1, int* result2, int* result3, int* result4, int x)
{
*result1 = x;
*result2 = x << 1;
*result3 = 0;
*result4 = 5 + x;
}
18.2.3 Common Subexpression Elimination
Common subexpression elimination replaces multiple instances of the same expression with a single instance. This optimization reduces size and increases execution speed.
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
Freescale Semiconductor, Inc.
317
Intermediate Optimizations
Table 18-4 explains how to control the optimization for common subexpression
elimination.
Table 18-4. Controlling common subexpression elimination
Turn control this option from here...
CodeWarrior IDE source code command line
use this setting
#pragma opt_common_subs on | off | reset
-opt [no]cse
For example, in
, the subexpression x * y
occurs twice.
Figure 18-5. Before common subexepression elimination
void func_from(int* vec, int size, int x, int y, int value)
{
if (x * y < size)
{
vec[x * y - 1] = value;
}
}
Figure 18-6 shows equivalent source code after the compiler applies common
subexpression elimination. The compiler generates instructions to compute x * y
and store it in a hidden, temporary variable. The compiler then replaces each instance of the subexpression with this variable.
Figure 18-6. After common subexpression elimination
void func_to(int* vec, int size, int x, int y, int value)
{
int temp = x * y;
if (temp < size)
{
vec[temp - 1] = value;
}
}
18.2.4 Copy Propagation
Copy propagation replaces variables with their original values if the variables do not change. This optimization reduces runtime stack size and improves execution speed.
Table 18-5 explains how to control the optimization for copy propagation.
Table 18-5. Controlling copy propagation
Turn control this option from here...
CodeWarrior IDE
Table continues on the next page...
use this setting
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
318 Freescale Semiconductor, Inc.
Chapter 18 Intermediate Optimizations
Table 18-5. Controlling copy propagation (continued)
source code
Turn control this option from here...
command line
use this setting
#pragma opt_propagation on | off | reset
-opt [no]prop[agation]
For example, in
, the variable j
is assigned the value of x
. But j
's value is never changed, so the compiler replaces later instances of j
with x
, as shown in
.
By propagating x
, the compiler is able to reduce the number of registers it uses to hold variable values, allowing more variables to be stored in registers instead of slower memory. Also, this optimization reduces the amount of stack memory used during function calls.
Figure 18-7. Before copy propagation
void func_from(int* a, int x)
{
int i;
int j;
j = x;
for (i = 0; i < j; i++)
{
a[i] = j;
}
}
Figure 18-8. After copy propagation
void func_to(int* a, int x)
{
int i;
int j;
j = x;
for (i = 0; i < x; i++)
{
a[i] = x;
}
}
18.2.5 Dead Store Elimination
Dead store elimination removes unused assignment statements. This optimization reduces size and improves speed.
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
Freescale Semiconductor, Inc.
319
Intermediate Optimizations
Table 18-6 explains how to control the optimization for dead store elimination.
Table 18-6. Controlling dead store elimination
Turn control this option from here...
CodeWarrior IDE source code command line
use this setting
#pragma opt_dead_assignments on | off | reset
-opt [no]deadstore
For example, in
the variable x
is first assigned the value of y * y
. However, this result is not used before x
is assigned the result returned by a call to getresult()
.
In
Figure 18-10 the compiler can safely remove the first assignment to
x
since the result of this assignment is never used.
Figure 18-9. Before dead store elimination
void func_from(int x, int y)
{
x = y * y;
otherfunc1(y);
x = getresult();
otherfunc2(y);
}
Figure 18-10. After dead store elimination
void func_to(int x, int y)
{
otherfunc1(y);
x = getresult();
otherfunc2(y);
}
18.2.6 Live Range Splitting
Live range splitting attempts to reduce the number of variables used in a function. This optimization reduces a function's runtime stack size, requiring fewer instructions to invoke the function. This optimization potentially improves execution speed.
Table 18-7 explains how to control the optimization for live range splitting.
Table 18-7. Controlling live range splitting
Turn control this option from here...
CodeWarrior IDE source code command line
use this setting
There is no pragma to control this optimization.
-opt level=3 , -opt level=4
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
320 Freescale Semiconductor, Inc.
Chapter 18 Intermediate Optimizations
For example, in
a
, b
, and c
, are defined. Although each variable is eventually used, each of their uses is exclusive to the others. In other words, a is not referred to in the same expressions as b
or c
, b
is not referred to with a
or c
, and c
is not used with a
or b
.
In
Figure 18-12 , the compiler has replaced
a
, b
, and c
, with a single variable. This optimization reduces the number of registers that the object code uses to store variables, allowing more variables to be stored in registers instead of slower memory. This optimization also reduces a function's stack memory.
Figure 18-11. Before live range splitting
void func_from(int x, int y)
{
int a;
int b;
int c;
a = x * y;
otherfunc(a);
b = x + y;
otherfunc(b);
c = x - y;
otherfunc(c);
}
Figure 18-12. After live range splitting
void func_to(int x, int y)
{
int a_b_or_c;
a_b_or_c = x * y;
otherfunc(temp);
a_b_or_c = x + y;
otherfunc(temp);
a_b_or_c = x - y;
otherfunc(temp);
}
18.2.7 Loop-Invariant Code Motion
Loop-invariant code motion moves expressions out of a loop if the expressions are not affected by the loop or the loop does not affect the expression. This optimization improves execution speed.
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
Freescale Semiconductor, Inc.
321
Intermediate Optimizations
Table 18-8 explains how to control the optimization for loop-invariant code motion.
Table 18-8. Controlling loop-invariant code motion
Turn control this option from here...
CodeWarrior IDE source code command line
use this setting
#pragma opt_loop_invariants on | off | reset
-opt [no]loop[invariants]
For example, in
Figure 18-13 , the assignment to the variable
circ
does not refer to the counter variable of the for
loop, i
. But the assignment to circ
will be executed at each loop iteration.
shows source code that is equivalent to how the compiler would rearrange instructions after applying this optimization. The compiler has moved the assignment to circ
outside the for
loop so that it is only executed once instead of each time the for
loop iterates.
Figure 18-13. Before loop-invariant code motion
void func_from(float* vec, int max, float val)
{
float circ;
int i;
for (i = 0; i < max; ++i)
{
circ = val * 2 * PI;
vec[i] = circ;
}
}
Figure 18-14. After loop-invariant code motion
void func_to(float* vec, int max, float val)
{
float circ;
int i;
circ = val * 2 * PI;
for (i = 0; i < max; ++i)
{
vec[i] = circ;
}
}
18.2.8 Strength Reduction
Strength reduction attempts to replace slower multiplication operations with faster addition operations. This optimization improves execution speed but increases code size.
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
322 Freescale Semiconductor, Inc.
Chapter 18 Intermediate Optimizations
Table 18-9 explains how to control the optimization for strength reduction.
Table 18-9. Controlling strength reduction
Turn control this option from here...
CodeWarrior IDE source code
use this setting
command line
#pragma opt_strength_reduction on | off | reset
-opt [no]strength
For example, in
Figure 18-15 , the assignment to elements of the
vec
array use a multiplication operation that refers to the for
loop's counter variable, i
.
In
Figure 18-16 , the compiler has replaced the multiplication operation with a hidden
variable that is increased by an equivalent addition operation. Processors execute addition operations faster than multiplication operations.
Figure 18-15. Before strength reduction
void func_from(int* vec, int max, int fac)
{
int i;
for (i = 0; i < max; ++i)
{
vec[i] = fac * i;
}
}
Figure 18-16. After strength reduction
void func_to(int* vec, int max, int fac)
{
int i;
int hidden_strength_red;
hidden_strength_red = 0;
for (i = 0; i < max; ++i)
{
vec[i] = hidden_strength_red;
hidden_strength_red = hidden_strength_red + fac;
}
}
18.2.9 Loop Unrolling
Loop unrolling inserts extra copies of a loop's body in a loop to reduce processor time executing a loop's overhead instructions for each iteration of the loop body. In other words, this optimization attempts to reduce the ratio of time that the processor executes a loop's completion test and branching instructions compared to the time the processor executes the loop's body. This optimization improves execution speed but increases code size.
CodeWarrior Development Studio for Advanced Packet Processing Build Tools Reference Manual, Rev.
10.2, 01/2016
Freescale Semiconductor, Inc.
323
Tải xuống
Quảng cáo