views:

54

answers:

2

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);
A: 

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.

Baltasarq
I just did that to keep it from being optimized away, since in the example the return value isn't used. I tried removing volatile, adding initial values, and a printf at the end but the same result (compile error on impossible constraint). I was under the impression reading http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html that a volatile asm can still be moved, do you have a link describing optimizations (other than removing unused code) that it impedes?
Tim Hatch
Okay, then maybe the problem has to do with the following topic: http://stackoverflow.com/questions/1478513/linux-assembler-error-impossible-constraint-in-asm
Baltasarq
A: 

Not sure why you're shifting left by 23*4=92, but...

There might be. You can use __builtin_constant_p() and __builtin_choose_expr() to pick the expression to compile; something like

__builtin_choose_expr(__builtin_constant_p(c), SHIFT(h, l, c), slower_code_here);

If it picks slower_code_here, then it "couldn't" determine that c was constant. If it complains about an "impossible constraint", then it knows it's constant but doesn't manage to turn it into an immediate for some reason.

It's sometimes surprising what it thinks is and isn't constant; I was playing around the other day and it complained about something like __builtin_choose_expr(sizeof(char[__builtin_choose_expr(..., 1, -1)]),...).

(I'm assuming the %2,%1,%0 order is intentional; I would've expected %0,%1,%2 but the documentation is vague and I can never remember which asm syntax is being used.)

tc.