Skip to main content
GameDev.net gamedev.net
🔒 Locked

optimizing if statements

Started by lokki Jun 25, 2004 at 4:34 PM 14 replies 1.8k views
Original Post
lokki
lokki
Hi, I seem to recall reading somewhere a way to perform the following with out branching...(Hopefully useful in tight loop) int val; int x; if (val) x = val; Thanks
ApochPiQ
ApochPiQ
That's a conditional, so it's going to branch; as far as I know, you really can't get around that unless you make some assumptions about val and remove the conditional.

Now, there are cases in loops where you can minimize branching. For example:
while(some_condition){ if(some_condition_which_doesn't_change)  do_something; else  do_something_else;}


This code can be optimized rather nicely to:
if(some_condition_which_doesn't_change){ while(some_condition)  do_something;}else{ while(some_condition)  do_something_else;}


This article has some more techniques that I've found quite useful as well.
TangentZ
TangentZ
See my new sig. [cool]
神はサイコロを振らない!
Extrarius
Extrarius
IIRC there are conditional instructions that don't bransh, but I don't know if they'd be any faster on such a short jump (I don't think there would be any kind of cache bubble which is what can make branching slow).
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Fruny
Fruny
If your compiler optimizes properly, it should issue a conditional move instruction instead of a branch, without you doing anything fancy in the source code.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
hplus0603
hplus0603
Fruny is right.

Make sure you're set to emit code for Pentium Pro and above, as the Pentium didn't have CMOV (Pentium II did). "Blend" isn't good enough, you really have to exclude Pentiums to make the compiler realize it can use CMOV, FCMOV, FCOMI and some other nice instructions that really help.
enum Bool { True, False, FileNotFound };
Anon Mike
Anon Mike
Strictly speaking you can do pretty much anything without conditionals. It's not necessarily performant though.

int val
int x;
int b = (val != 0);
x = val * b + x * !b;

You can fiddle with it to make it use & instead of * in the assignment to x which might be marginally better. But since the whole exercise is marginal to begin with I'll leave that as an exercise to the reader...
-Mike
ApochPiQ
ApochPiQ
Heh, forgot about CMOV. As TangentZ said, though, chances are the compiler is already doing things like that for you. In general unless you know for a fact you've got massive performance problems in specific code (i.e. you've profiled the code in question) it's a bit pointless to optimize it.
Promit
Promit
Does Pentium Pro mean i586 with MMX?
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Zahlman
Zahlman
Quote:
Original post by lokki
Hi,

I seem to recall reading somewhere a way to perform the following with out branching...(Hopefully useful in tight loop)

int val;
int x;
if (val) x = val;


Thanks


Notwithstanding all the (very correct) comments about it not being bloody likely to make a difference and being even less likely to be worth worrying about: in your case, just assign "x = val". If val *was* 0, then you're making an assignment that the original code didn't make, *but* it's to an uninitialized variable anyway, so it doesn't matter. ;P
Fruny
Fruny
Quote:
Original post by Promit
Does Pentium Pro mean i586 with MMX?


The gcc options seem to think not:
Quote:

-march=cpu-type
Generate instructions for the machine type cpu-type. The choices for cpu-type are the same as for -mtune. Moreover, specifying -march=cpu-type implies -mtune=cpu-type.

-mtune=cpu-type
Tune to cpu-type everything applicable about the generated code, except for the ABI and the set of available instructions. The choices for cpu-type are:

  • i386
    Original Intel's i386 CPU.

  • i486
    Intel's i486 CPU. (No scheduling is implemented for this chip.)

  • i586, pentium
    Intel Pentium CPU with no MMX support.

  • pentium-mmx
    Intel PentiumMMX CPU based on Pentium core with MMX instruction set support.

  • i686, pentiumpro
    Intel PentiumPro CPU.

  • pentium2
    Intel Pentium2 CPU based on PentiumPro core with MMX instruction set support.

  • pentium3
    Intel Pentium3 CPU based on PentiumPro core with MMX and SSE instruction set support.

  • pentium4
    Intel Pentium4 CPU with MMX, SSE and SSE2 instruction set support.


So a pentium pro with MMX would actually be a pentium 2.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Promit
Promit
Uh...so it's an i686 without MMX?
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Fruny
Fruny
#include
Sounds like it.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
hplus0603
hplus0603
> Does Pentium Pro mean i586 with MMX?

No, it does not.

Intel family history excerpt:

Pentium Pro is a separate chip, that came out around the same time as Pentium with MMX (plus or minus). It did not have MMX, but it had CMOV, etc, and a great 32-bit implementation. Sucked for 16-bit code, which is why it never took off (this was when Windows 95 and Windows 98 were where it was all at).

Pentium II is pretty much a Pentium Pro, plus MMX, plus better 16-bit performance.

Pentium III is pretty much a Pentium II, plus cache control and SIMD (together SSE) and a faster front side bus.
enum Bool { True, False, FileNotFound };
Charles B
Charles B
Quote:
(Fruny)
If your compiler optimizes properly, it should issue a conditional move instruction instead of a branch, without you doing anything fancy in the source code.


Right but a cabled instruction is not even required in most cases. I have seen compilers able to use conditional move sequences, with standard RISC instructions. It was codewarrior on a Mac if I remember well. the best way to help the compiler trigger this behaviour is to use the conditional affectation that exists in the C syntax. The common min max implementations (stdlib.h) in the C libraries use the ?: operator.

Example :
int val, x;
if (val) x = val;

Is well replaced by x = (val) ? val : x;

An intelligent compiler can find the appropriate cabled instruction if it exists and if allowed by the minimum target hardware you selected. Else on a x86 it can generate code that uses the sign or carry flags.

In your case if you are sure val is a boolean with -1 or 0 values only. Then you can write :

x |= val;

In the general case I must remember which instructions could produce a carry or sign bit. In many cases, the conditional branch can be replaced by conditional moves (direct or simulated) for significant improvements. This is much better for parallelism and code scheduling.

Else of course MMX or other SIMD instructions can greatly help to kick nearly any conditional branch out of a code. I may show it in a paper I prepare about OBBoxes.
"Coding math tricks in asm is more fun than Java"

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.