The switch Conditional Statement

A switch conditional statement makes it possible to select one of the branches of execution, depending on the value of the control expression. The value of the control expression is compared to an integer or character constant in a list. If a coincidence is detected , the statements associated with the constant are executed.

The form of this statement can be represented as follows :

 switch (expression) {        case constant 1:          <statements>          break;        case constant 2:          <statements>          break;       ...        default:    } 

To implement a switch statement in the assembler, you can use a comparison command for each case and a jump to an appropriate label in the program (Listing 4.11).

Listing 4.11: A fragment of assembly code that implements a switch statement
image from book
 ...   mov      EAX, DWORD PTR N    cmp      EAX, VALUE_1    je       BRANCH_1    cmp      EAX, VALUE_2    je       BRANCH_2    cmp      EAX, VALUE_3    je       BRANCH_3      ...    cmp      EAX, VALUE_N    je       BRANCH_N     ...  BRANCH_1:    <statements>  BRANCH_2:    <statements>  BRANCH_N:    <statements>     ... 
image from book
 

It is often convenient to call subroutines processing the condition rather than make conditional jumps (Listing 4.12).

Listing 4.12: A fragment of assembly code that uses condition-processing subroutines
image from book
 ...   mov     EAX, DWORD PTR N    cmp     EAX, VALUE_1    jne     BRANCH_1    call    PROC_1    jmp     EXIT  BRANCH_1:    cmp     EAX, VALUE_2    jne     BRANCH_2    call    PROC_2    jmp     EXIT  BRANCH_2:    cmp     EAX, VALUE_3    jne     BRANCH_3    call    PROC_3    jmp     EXIT  BRANCH_3:    cmp     EAX, VALUE_4    jne     EXIT    call    PROC_4     ...  EXIT:    cmp     EAX, VALUE_2    je      BRANCH_2    cmp     EAX, VALUE_3    je      BRANCH_3     ...    cmp     EAX, VALUE_N    je      BRANCH_N     ... 
image from book
 

Now, we will consider a C++ program that adds, subtracts, or multiplies two integers depending on the selection of one of three cases. The source code of the console application is shown in Listing 4.13.

Listing 4.13: A C++ program that demonstrates the use of the switch statement
image from book
 // SWITCH_EXM.cpp : Defines the entry point for the console application  #include "stdafx.h"  int _tmain(int argc, _TCHAR* argv[])  {   int i1, i2, isw, ires;   while (true)    {     printf("\nEnter first number (i1): ");     scanf("%d", &i1);     printf("Enter second number (i2): ");     scanf("%d", &i2);     printf ("Choice: 1   i1+i2, 2   i1   i2, 3   i1*i2\n");     scanf("%d", &isw);     switch (isw) {        case 1:          ires = i1+i2;          break;        case 2:          ires = i1   i2;          break;        case 3:          ires = i1*i2;          break;        default:          break;        }    printf("Result=%d\n", ires);    }   return 0;  } 
image from book
 

It would be useful to write some effective assembly code for this task. If you got rid of the switch case branching, the program performance would increase significantly. As noted earlier, the command set of Pentium II and higher includes the cmov and fcmov commands that make it possible to implement the switch case algorithm. Modify the previous listing so that the cmov command can be used. Use the C++ .NET inline assembler for this purpose. The source code of the program is shown in Listing 4.14.

Listing 4.14: Eliminating the switch case branching by using the inline assembler in a C++ program
image from book
 // SWITCH_EXM.cpp : Defines the entry point for the console application  #include "stdafx.h"  int _tmain(int argc, _TCHAR* argv[])  {   int i1, i2, isw, ires;   int iadd, isub, im;   while (true)    {     printf("\n");     printf("Enter first number (i1): ");     scanf("%d", &i1);     printf("Enter second number (i2): ");     scanf("%d", &i2);     printf ("Choice: 1   i1+i2, 2   i1   i2, 3   il*i2\n");     scanf("%d", &isw);     iadd = i1+i2;     isub = i1   i2;     im = i1*i2;     _asm {           xor   EDX, EDX           mov   EAX, isw           cmp   EAX, 1           cmove EDX, iadd           cmp   EAX, 2           cmove EDX, isub           cmp   EAX, 3           cmove EDX, im           mov   ires, EDX          }    printf("Result=%d\n", ires);   }  return 0;  } 
image from book
 

As you can see from Listing 4.14, the switch statement is replaced with its assembly analog, a group of commands in the _asm { } block. To implement an assembly version, you should declare a few auxiliary variables in the source code:

 int iadd, isub, im; 

Write the following statements just before the assembly block:

 iadd = i1+i2;  isub = i1   i2;  im = il*i2; 

These statements are necessary for the cmove command. Depending on flags set with the previous command, this command moves the contents of a register or a memory cell to another register. Before you use the cmov command, make sure it is supported by the processor. This is done with the cpuid command.

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

image from book
Fig. 4.2: Window of an application that demonstrates the use of assembly commands for replacing the switch statement

This completes the discussion of C++ .NET logical structures and their optimization with the assembler. You can easily modify any example from this chapter and use it in your own applications.



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