The if Statement

A single if statement is used for execution of a statement or a block of statements depending on whether the specified condition is true. In a general form, this statement looks like this:

 if (condition)    statements 

In C++, it can be written as follows :

 if (condition)  {    <statements>  } 

A more complex variant of the statement, if else , makes it possible to selectively execute one of two actions depending on the condition. Here is its syntax in C++:

 if (condition)   {    <statements 1>   { else   {    <statements 2>   } 

There are no such constructions in assembly language, but they can be implemented easily with certain sequences of commands.

For example, we will consider an algorithm that checks two operands for equality and jumps to one or the other branch depending on the result.

In Visual C++ .NET, the expression will look like this:

 if (operand1 = operand2)  {      ...  }  else  {      ...  } 

Assembly language allows you to implement the if else construction quite simply:

 cmp     operand1, operand2    je      YES    <commands 1>    jmp     EXIT  YES:    <commands 2>  EXIT:     ... 

Another variant is also possible:

 cmp     operand1, operand2    jne     NO    <commands 2>  EXIT:     ... NO:    <commands 1>    jmp     EXIT 

Develop a code fragment that compares two integers, X and Y . Depending on the result of comparison, the X variable takes the value of Y if X is greater than Y , and remains unchanged if X is less or equal to Y .

In C++, this code fragment looks like this:

 if (X > Y)      X = Y; 

Here is its implementation in the assembler:

 mov    EAX, DWORD PTR Y    cmp    EAX, DWORD PTR X    jge    EXIT    mov    DWORD PTR X, EAX  EXIT: 

Since 32-bit operands are used, all variables and registers are declared appropriately. The cmp comparison command cannot be executed if both its operands are located in the memory, so one of them ( Y in this case) is put to the EAX register. The result is stored in the X variable.

The following fragment of code computes the sum of two integers, X and Y , if both are within the range from 1 to 100.

In Visual C++, this fragment of code looks like this:

 if ((X <= 100 && X >= 1) && (Y <= 100 && Y >= 1))      X = X + Y 

The code in the assembler is shown in Listing 4.1.

Listing 4.1: A fragment of an assembly program, with an analog of the if statement, that adds up two integers
image from book
 . . .    cmp     DWORD PTR X, 1    jge     check_x100    jmp     EXIT  check_x100:    cmp     DWORD PTR X, 100    jle     check_y1    jmp     EXIT  check_y1:    cmp     DWORD PTR Y, 1    jge     check_y100    jmp     EXIT  check_y100:    cmp     DWORD PTR Y, 100    jg      EXIT    mov     EAX, DWORD PTR Y    add     DWORD PTR X, EAX  EXIT:    . . . 
image from book
 

As you can see from the algorithm, in order to find the sum of X and Y , you need to check at least four conditions:

  • X is greater or equal to 1

  • Y is greater or equal to 1

  • X is less or equal to 100

  • Y is less or equal to 100

Only if these four conditions are true simultaneously can you assign the X variable the value of the X + Y expression. To implement such a task, you should break the condition

 (X <= 100 && X >= 1) && (Y <= 100 && Y >= 1) 

into the following four simpler constructions:

 X <= 100, X >= 1, Y <= 100, Y >= 1 

The task is simpler now. Each of the four conditions can be checked easily with the cmp command. For example, checking the X < = 100 condition and the subsequent jump is done as follows:

 cmp    DWORD PTR X, 100  jle    check_y1 

The other checks can be done with similar combinations of commands.

It is important to note that an assembly analog of a high-level language construction is not necessarily obvious, and this is illustrated in the following example.

Develop some code to compute the absolute value of the X integer. A possible variant of implementing such a task involves the if else construction.

In Visual C++, it will look like this:

 if (X >= 0)      AbsX = X  else      AbsX =   X 

where AbsX is a variable that stores the absolute value of X . Here is an implementation of this construction in the assembler:

 cmp    DWORD PTR X, 0     jl     NOT_X     jmp    EXIT  NOT_X:    neg     DWORD PTR X  EXIT:    mov     EAX, DWORD PTR X    mov     DWORD PTR AbsX, EAX 

An assignment statement is executed in both the if and else branch. These two assignments can be combined and put at the end of the fragment of code:

 mov    EAX, DWORD PTR X  mov    DWORD PTR AbsX, EAX 

The else branch is implemented in the assembler with the command:

 NOT_X:    neg     DWORD PTR X 

The result is stored in the Absx variable.

Now, we will solve a simple problem. Find the maximum of two integers and assign it to a third variable. An appropriate C++ .NET console application would consist of a few lines of code, and its code is shown in Listing 4.2.

Listing 4.2: Computing the maximum of two numbers and displaying it
image from book
 // IF_ELSE_SETCC.cpp : Defines the entry point  // for the console application  #include "stdafx.h"    int _tmain(int argc, _TCHAR* argv[])  {   int i1, i2, ires;   while (true)    {     printf("\n");     printf("Enter first number (i1): ");     scanf("%d", &i1);     printf("Enter second number (i2): ");     scanf("%d", &i2);     if (i1 >= i2) ires = i1;     else ires = i2;     printf("Maximum = %d\n", ires);   }  return 0; } 
image from book
 

As you can see from the listing, a comparison is made with the following statements:

 if (i1 >= i2) ires = i1;  else ires = i2; 

Now, we will try to optimize the code fragment that contains the if else statement. It will be convenient to use the Visual C++ .NET inline assembler for this purpose. An assembly language analog of a conditional statement will look like this:

 _asm {            mov  EAX, i1            mov  EBX, i2            cmp  EAX, EBX            jge  set_ires            xchg EAX, EBX   set_ires:            mov ires, EAX          } 

This fragment of code is simple and does not require additional explanation. You can create even more effective code if you get rid of branches and jumps in the program or at least minimize their number. Processors such as Pentium II and higher include a number of commands that allow you to effectively implement branches in a program. Among these commands are setcc (set conditionally) and the cmov and fcmov commands. By combining these, you can achieve significant results, while improving the performance of your applications.

An assembly analog of the if else statement that uses the setge and cmovl commands looks like this:

 _asm {        xor   EBX, EBX        mov   EAX, i1        mov   EDX, i2        cmp   EAX, EDX        setge BL        mov   ires, EAX        cmp   BL, 1        cmovl EAX, EDX        mov   ires, EAX      } 

First, the EBX register is zeroed because it will be used as a greater than or less than indicator. The first number ( i1 ) is put to the EAX register, and the second number ( i2 ) to the EDX register. If the contents of the EAX register are greater than or equal to those of the EDX register, the setge BL command writes a one to the low order part of EBX ; otherwise , zero will remain in EBX . If BL=0 , the contents of EDX are put to the EAX register. Before the last command, the EAX register contains the maximum, which is stored in the ires variable. As you can see from this fragment of code, there are no branches and jumps. Before you use the cmov command, you should make sure that your processor supports it. The check can be done with the cpuid command.

The complete code of the console application is shown in Listing 4.3.

Listing 4.3: A modified variant of the program that includes the if else statement
image from book
 // IF_ELSE_SETCC.cpp : Defines the entry point  // for the console application  #include "stdafx.h"  int _tmain(int argc, _TCHAR* argv[])  {   int i1, i2, ires;   while (true)    {     printf("\n");     printf("Enter first number (i1): ");     scanf("%d", &i1);     printf("Enter second number (i2): ");     scanf("%d", &i2);     _asm {            xor   EBX, EBX            mov   EAX, i1            mov   EDX, i2            cmp   EAX, EDX            setge BL            mov   ires, EAX            cmp   BL, 1            cmovl EAX, EDX            mov   ires, EAX          }     printf("Maximum=%d\n", ires);    }  return 0;  } 
image from book
 
image from book
Fig. 4.1: Window of an application that uses optimized code for computing the maximum of two integers

The window of the application is shown in Fig. 4.1.



Visual C++ Optimization with Assembly Code
Visual C++ Optimization with Assembly Code
ISBN: 193176932X
EAN: 2147483647
Year: 2003
Pages: 50
Authors: Yury Magda

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net