Sign in to follow this  
dave

Which Is Faster In Assembler, Switch-Case or If-Elseif

Recommended Posts

Only one way to find out!

If I had to guess, I'd say switch is usually faster because the expression in the switch(x) only needs to be evaluated once. Whereas with several if statements x may need to be evaluated once for each if statement because the expressions may be completely different.

Share this post


Link to post
Share on other sites
As there's no "switch" command in assembly, the compiler has to compile it as if/else if/else's. Thus - it should be the same.

EDIT [0]: I'll give you an example [smile]

I usually code my switch statement in Window procedure (win32 assembly) as follows:


WndProc:
hWnd: equ 8
msg: equ 12
wParam: equ 16
lParam: equ 20

;...

;;switch (msg)
cmp dword [ebp + msg], WM_CREATE ;if (msg == WM_CREATE)
jmp .wm_create ; goto wm_create

cmp dword [ebp + msg], WM_DESTROY ;if (msg == WM_DESTROY)
jmp .wm_destroy ; goto wm_destroy

.wm_create:
;;stuff

.wm_destroy:
;;stuff





Oxyd

Share this post


Link to post
Share on other sites
In theory, modern compilers consider such series of conditions the same way. Depending on the constant arguments and the context of your code, they use 4 possible strategies (non exclusive) :

- reorder the ifs in a most favorable probabilistic manner.
- a binary tree.
- a look up table (case 1: case2: etc...)
- replace by conditional moves if possible

Else experiment choices and look at the asm output in your debugger or in a listing file. Maybe choosing switches guides the compiler more towards look up tables in some cases. Ifs more towards binary trees. Just my speculations.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
depends on your range of numbers for the switch.

optomized switchesuse jump tables indexed by the switch case values. so if your switch is say a INT and has spread wide
case values 0 1023 -5222 it probably will use if-then tests internally because the address table would be too big where a short range (max table size depends on compiler) ex- 0 1 2 3 4 5 6 7 8 etc... or even gaps 0 2 4 6 8 10 12 would have a table and jump to the indexed address in the table (may do a little arithmetic to convert to a 0 ofset for the lowest case value.

You compiler may have an ASM listing option that you can turn on and you can look at the code generated (using fairly rufimentary assembly code knowledge...)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
People please stop asking this question!!! Seacrh in the seacrh engine this is like the 2nd one of these in 2 weeks

Share this post


Link to post
Share on other sites
A switch statement and an if-else-else if wouldn't necessarily compile out the same. A switch statement always compares against one expression that can be pre-calculated before any comparisons are made:



/* example one */
switch((x + 100) % 4)
{
case(0):
break;

case(1):
break;

case(2):
break;

default:
break;
}

/* example two */
if(((x + 100) % 4) == 0)
printf("zero\n");
else if(((x + 100) % 4) == 1)
printf("one\n");
else if(((x + 100) % 4) == 2)
printf("two\n");
else
printf("three\n");

/* example three */
if(x - 10 == 100)
printf("one hundred\n");
else if(x + 100 == 10)
printf("ten\n");




Examples one and two could potentially generate the same code. The left hand expression ((x + 100) % 4) doesn't need to be re-evaluated for each if statement, so it would work like a switch statement.

In example three the expression needs to be re-evaluated for each if statement. This would compile differently than a switch statement.

Share this post


Link to post
Share on other sites
Quote:
Original post by smr
A switch statement and an if-else-else if wouldn't necessarily compile out the same. A switch statement always compares against one expression that can be pre-calculated before any comparisons are made:

*** Source Snippet Removed ***

Examples one and two could potentially generate the same code. The left hand expression ((x + 100) % 4) doesn't need to be re-evaluated for each if statement, so it would work like a switch statement.

In example three the expression needs to be re-evaluated for each if statement. This would compile differently than a switch statement.

The compiler is a lot smarter than you think it is. Your third example:

/* example three */
if(x - 10 == 100)
printf("one hundred\n");
else if(x + 100 == 10)
printf("ten\n");

could easily be changed to:

if(x == 110)
printf("one hundred\n");
else if(x == -90)
printf("ten\n");

And the compiler will easily catch such conditions and evaluate them so.

Share this post


Link to post
Share on other sites
Don't forget that it very much depends on how x is defined in the above case. If x is a global non-const variable it will have to be re-evaluated a lot since other code may have updated it. I don't *think* the case does this (thanks to jump tables), while the if probably will. Anyway, there's a lot of factors effecting the assembly output.
The best method is to actually check what is generated and then consider wether it's all good or wether you failed to provide enough information to the compiler for it to optimize your code as much as you would expect it to.
Your compiler probably has a lot better overview of your code than you do ;) It's just a matter of providing it with the correct information. With unspecific input you get unspecific output.

Share this post


Link to post
Share on other sites
Quote:
Original post by asp_
Don't forget that it very much depends on how x is defined in the above case. If x is a global non-const variable it will have to be re-evaluated a lot since other code may have updated it. I don't *think* the case does this (thanks to jump tables), while the if probably will. Anyway, there's a lot of factors effecting the assembly output.
The best method is to actually check what is generated and then consider wether it's all good or wether you failed to provide enough information to the compiler for it to optimize your code as much as you would expect it to.
Your compiler probably has a lot better overview of your code than you do ;) It's just a matter of providing it with the correct information. With unspecific input you get unspecific output.

Uh, it will only need to reevaluate it if x is a volatile variable. Any other case and the compiler only needs to evaluate it once, and in most cases will evaluate it only once.

Share this post


Link to post
Share on other sites
Quote:
Original post by washu
The compiler is a lot smarter than you think it is. Your third example:

/* example three */
if(x - 10 == 100)
printf("one hundred\n");
else if(x + 100 == 10)
printf("ten\n");

could easily be changed to:

if(x == 110)
printf("one hundred\n");
else if(x == -90)
printf("ten\n");

And the compiler will easily catch such conditions and evaluate them so.


Thanks for pointing that out. :-) I chose a bad example. Essentially what I was trying demonstrate is that you may have two completely unrelated expressions in an if-elseif-else block. It is possible using that construct that the compiler may have to generate more code.

Also, I don't know how true this is today, but for the if-elseif-else block you should make sure that the most likely possibility is the first in the list, followed by the second most likely and so on until the least likely scenario. This will reduce the number of expressions to evaluate for each iteration.

Share this post


Link to post
Share on other sites

Switch statements can work better for large decisions, specially if the compiler can optimize it to use jump tables (or even multiple jump tables). Look at the assembly output

Another option that gives you advantage is to divide your decisions.


if(a==1) {
} else if(a==2) {
} else if(a==3) {
} else if(a==4) {
} else if(a==5) {
} else if(a==6) {
} else if(a==7) {
} else if(a==8)

{
}



if(a<=4) {
if(a==1) {
} else if(a==2) {
} else if(a==3) {
} else if(a==4) {

}
}
else
{
if(a==5) {
} else if(a==6) {
} else if(a==7) {
} else if(a==8) {
}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by antareus
You won't be able to tell which one is faster, and they may compile down to the same code anyway. Nano-optimization sucks, too.


Hah, that depends on the size of your switch statement, and how often you run it.

I could think of plenty of situations where it'd make a big difference. What if you're emulating a cpu? For every instruction, you need to look up its opcode, and you want that to go damn fast because, well, you do this for *every* emulated cycle.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Just for fun compile time switch....

Quote:



enum Case { value1, value2 };

template
class Switch {
public:
static inline void do_action()
{ /*default-statement*/ }
};

class Switch {
public:
static inline void do_action()
{ /*statement1*/ }
};

class Switch {
public:
static inline void do_action()
{ /*statement2*/ }
};

int main() {

const int I = 2;
Switch::do_action();

return 0;
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Just for fun compile time switch....




enum Case { value1, value2 };

template <Case c>
struct Switch {
static inline void do_action()
{ /*default-statement*/ }
};

struct Switch<value1> {
static inline void do_action()
{ /*statement1*/ }
};

struct Switch<value2> {
static inline void do_action()
{ /*statement2*/ }
};

int main() {

const int I = 2;
Switch<I>::do_action();

return 0;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Spoonster
Quote:
Original post by antareus
You won't be able to tell which one is faster, and they may compile down to the same code anyway. Nano-optimization sucks, too.


Hah, that depends on the size of your switch statement, and how often you run it.

I could think of plenty of situations where it'd make a big difference. What if you're emulating a cpu? For every instruction, you need to look up its opcode, and you want that to go damn fast because, well, you do this for *every* emulated cycle.

Then don't use a switch or an if. There are much better ways of decoding instructions than a switch statement. table lookups combined with shifts for instance. Requires only a few if statements then.

Chances are that if you have a huge switch statement, or a huge set of if/else if/else you are looking at things wrong and may want to consider redesigning. There are, of course, cases where this isn't true, such as the Win32 WndProc.

Share this post


Link to post
Share on other sites
Premature optimisation is the root of all evil!
Everyone here can assume that you have not determined that this is a bottleneck in your code, as you have not told us that you have profiled and found that to be so.

Use whichever is most appropriate. Readability is far more important than saving a few clock cycles when initially developing something.

That said, a lookup table is fastest if it's possible to use it instead of a switch statement. But we can't tell that without seeing some code. Try-it-and-see is about the only way you're going to find out.

Share this post


Link to post
Share on other sites
Quote:
Original post by Washu
Quote:
Original post by Spoonster
Quote:
Original post by antareus
You won't be able to tell which one is faster, and they may compile down to the same code anyway. Nano-optimization sucks, too.


Hah, that depends on the size of your switch statement, and how often you run it.

I could think of plenty of situations where it'd make a big difference. What if you're emulating a cpu? For every instruction, you need to look up its opcode, and you want that to go damn fast because, well, you do this for *every* emulated cycle.

Then don't use a switch or an if. There are much better ways of decoding instructions than a switch statement. table lookups combined with shifts for instance. Requires only a few if statements then.

Chances are that if you have a huge switch statement, or a huge set of if/else if/else you are looking at things wrong and may want to consider redesigning. There are, of course, cases where this isn't true, such as the Win32 WndProc.


Ok, it was just an example... ;)
But basically, I agree with you. Of course there are better ways to do it. The question is whether the compiler can figure them out. If it can, then the switch is definitely better than if-else-if. (although personally, I would probably do like you said, just to make sure.)
If the compiler is clever enough to build a jump table or do a binary search, then switch will be far faster than the if-else-if thing. And in that example, I wouldn't call it "nanooptimization" like someone said earlier. However, as iMalc said, premature optmization is just silly. In many cases, it doesn't matter whether you use switch, if's or build your own jump table or other clever systems, and all you should focus on is the readability of the code. But if you have a big switch in a performance-critical area of the code, then the question is pretty relevant.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this