1

I use macros to code unrolled loops like this: (silly example)

#define foreach_small_prime(p, instr) {   \
  int p;                                  \
  p = 2; instr;                           \
  p = 3; instr;                           \
  p = 5; instr;                           \
  p = 7; instr;                           \
}

foreach_small_prime(pp, cout << pp);

int sum = 0;
foreach_small_prime(pp, {
  sum += pp;
  if (sum >= 10) cout << sum << endl;
});

But in some cases I might use for construct:

#define foreach_small_even(ii) for(int ii = 0; ii < 20; ii += 2)

int sum = 0;
foreach_small_even(pp) {
  sum += pp;
  if (sum >= 10) cout << sum << endl;
}

I like this macros because I can pass a variable name as a parameter.

Question: Is there a way to define loop like the first one in a for-like syntax like the second macro?

5
  • 2
    quick question, do you find that this unrolling actually improves performance? If you haven't profiled to prove that it does. You should consider writing the "obvious" way and letting the compiler be clever for you. Commented May 6, 2009 at 14:08
  • Stop abusing the macro system. It is because of abuses like this that in-lining of functions was such a required feature of C++. Commented May 6, 2009 at 14:39
  • 2
    ACtually I did a very detailed profiling including asm output profiling with various g++ options. And the performance difference is big, mostly due to conditional branch in the loop. Commented May 6, 2009 at 15:13
  • I agree as we have seen that VS200x does bad job of unrolling loops. Specifically if you are accessing some complex structure. I have found templates to be useful in doing such unrolling. Commented Jan 14, 2010 at 3:36
  • How can you use templates for that? Commented Jan 16, 2010 at 14:16

3 Answers 3

7

You could check out the Boost preprocessor library. It can do all sorts of looping things. The syntax isn't great, but I believe it works. I have not used it myself, however.

Sign up to request clarification or add additional context in comments.

Comments

0

Do you have a good reason to avoid using an iterator object? You have to consider your first macro pastes 4x your instr code...

Otherwise, a simple :

#define foreach_smallprime(ii) for(int ii = 0; ii <= 7; ii = next_prime(ii) )

with next_prime(ii) defined in the same file as the macro.

1 Comment

Next_prime would need to determine a prime from the previous one. Iterator object probably won't be unrolled.
0

Question: Is there a way to define loop like the first one in a for-like syntax like the second macro?

I guess you have a relatively small working-set of prime numbers, so creating a look-up for your primes shouldn't be too troublesome. If you need to generate a larger list of primes, I'm sure there is some compile-time template meta-programming magic available in the Boost library. If you have a more complex series of numbers you're generating it might be wise to turn the lookup into a function that caches the results as they are generated.

const int small_primes[MAX_SMALL_PRIMES] = {2, 3, 5, 7, 11, 13};

#define foreach_small_prime(pp) \
  for (int i = 0; i < MAX_SMALL_PRIMES; pp = small_primes[++i])

Used as:

void f() {
  int sum = 0;
  int temp = 0;
  foreach_small_prime(temp) {
    sum += temp;
    if (sum >= 10) cout << sum << endl;
  }
}

Probably want to toss the lookup table and MAX_SMALL_PRIMES theirown namespace to avoid clutter... and using a commonly-used identifier 'i' in the macro is probably a poor choice. I'm sure there are other ways to improve it, but this is fundamentally what you're asking for.

1 Comment

Ah... after re-rereading your question I think I see what you were going after. You wanted loop-unrolling retained, but with the usage syntax of the second construct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.