EDIT: in order to better orient what the OP requires and still delete it, this post has been carefully edited.
Of course, I assume you profiled this, and it was shown as a hot spot ... right?
In fact, I'm sure you did not. And that you seriously underestimate your compiler.
For example, here is your code compiled using LLVM:
void f1(char*); void f2(char*); void loop(char* c, int n, int sm) { for (int i = 0; i < n; ++i) { if (sm) f1(c); else f2(c); } }
What gives:
define void @loop(i8* %c, i32 %n, i32 %sm) nounwind uwtable { %1 = icmp sgt i32 %n, 0 br i1 %1, label %.lr.ph, label %._crit_edge .lr.ph: ; preds = %0 %2 = icmp eq i32 %sm, 0 br i1 %2, label %3, label %5 ; <label>:3 ; preds = %3, %.lr.ph %i.01.us = phi i32 [ %4, %3 ], [ 0, %.lr.ph ] tail call void @f2(i8* %c) nounwind %4 = add nsw i32 %i.01.us, 1 %exitcond = icmp eq i32 %4, %n br i1 %exitcond, label %._crit_edge, label %3 ; <label>:5 ; preds = %5, %.lr.ph %i.01 = phi i32 [ %6, %5 ], [ 0, %.lr.ph ] tail call void @f1(i8* %c) nounwind %6 = add nsw i32 %i.01, 1 %exitcond2 = icmp eq i32 %6, %n br i1 %exitcond2, label %._crit_edge, label %5 ._crit_edge: ; preds = %5, %3, %0 ret void }
Even if you don't know IR LLVM, just follow the "sm" variable:
.lr.ph: ; preds = %0 %2 = icmp eq i32 %sm, 0 br i1 %2, label %3, label %5
The compiler generated two different loops (starting with <label>:3 and <label>:5 respectively, and select once for the whole loop that will be executed at the beginning of the selection.
This is a pretty well-known compiler trick: Loop Invariant Code Motion (and derivation), so why bother manually? If it's worth it, the compiler will do it!