Fascinating new switch mechanism in assembler

Lionello Lunesu lio at remove.lunesu.com
Mon Mar 20 02:33:16 PST 2006


> ?test@@YAHH at Z:
>  push EBX
>  mov EBX,8[ESP]
>  sub EBX,1
>  cmp EBX,6
>  ja L1A
>  jmp dword ptr FLAT:_DATA[00h][EBX*4]
>  mov EAX,8[ESP]
>  pop EBX
>  ret
> L1A:  mov EAX,8[ESP]
>  inc EAX
>  pop EBX
>  ret
> _TEXT ends
> _DATA segment
> dd offset FLAT:?test@@YAHH at Z[014h]
> dd offset FLAT:?test@@YAHH at Z[014h]
> dd offset FLAT:?test@@YAHH at Z[014h]
> dd offset FLAT:?test@@YAHH at Z[014h]
> dd offset FLAT:?test@@YAHH at Z[014h]
> dd offset FLAT:?test@@YAHH at Z[014h]
> dd offset FLAT:?test@@YAHH at Z[014h]
> _DATA ends

In fact, it's even better. I got this code (dmd -O -release -inline):

00402010 push ebx
00402011 mov ebx,eax
00402013 sub ebx,1
00402016 mov ecx,eax
00402018 cmp ebx,6
0040201B ja 00402026
0040201D jmp dword ptr [ebx*4+411080h]
00402024 pop ebx
00402025 ret
00402026 pop ebx
00402027 lea eax,[ecx+1]
0040202A ret

Although the point is clear (the compiler already uses jump tables) the code 
does not seem optimal. Of course, my assembly knowledge is kind-of rusty 
(instruction pairing for the pentium 1 is the latest optimization I know 
of).

First of all the jmp is useless (in fact, the jump table is useless). The 
code already compares the "default:" case, so there's no need to further 
differentiate between the actual values. I would have written the switch as 
follows:

  push ebx
  mov ebx,eax
  dec ebx
  mov ecx,eax
  cmp ebx,6
  jbe L1A
  lea eax,[ecx+1]
L1A:
  pop ebx
  ret

What's the reason for the "sub ebx, 1", intead of "dec ebx"? Isn't an 
instruction using an immediate value slower (larger instruction => less 
instructions in cache) than one without? (At least that's what I remember 
from the pentium 1).

Would the usage of the instructions setbe/seta improve the above code even 
more? It'll get rid of the conditional jump, but I have no idea what the 
performance of those set* instructions are.

L. 





More information about the Digitalmars-d mailing list