Is there a way to use expressions evaluated at compile time with inline asm in gcc?


I have some code that basically needs to use a small expression in an assembly statement, where the expression is fairly trivial like i*4, but GCC doesn't seem to realize that at compile time (tried no -O flag, and -O3). Neither "i" nor "n" constraints work in the following snippet for the third usage.

#include <stdint.h>
#include <stdlib.h>

#define SHIFT(h, l, c) __asm__ volatile ( \
    "shld %2, %1, %0\n\t" \
    "sal %2, %1\n\t" \
    : "+r"(h), "+r"(l) : "i"(c))

void main(void) {
  uint64_t a, b;
  SHIFT(a, b, 1); /* 1 */
  SHIFT(a, b, 2*4); /* 2 */
  size_t i;
  for(i=0; i<24; i++) {
    SHIFT(a, b, (i*4)); /* 3 */

Giving this error:

temp.c:15: warning: asm operand 2 probably doesn’t match constraints
temp.c:15: error: impossible constraint in ‘asm’

I also tried

"shld $" #c ", %1...

but that has its own issue, because the parens remain when stringified. It's my intention that the entire loop becomes unrolled, but -funroll-all-loops doesn't seem to be happening early enough in the process to cause i*4 to become a constant. Any ideas? The alternative is quite ugly, but if there was a way to automate this in a macro that'd be better than nothing:

SHIFT(a, b, 1);
SHIFT(a, b, 2);
SHIFT(a, b, 24);

Is there any specific reason to mark the asm block as volatile? It's nearly impossible that any optimization is going to be carried out while volatile is present.