Search code examples
c++inline-assemblyavr-gcc

Why "Impossible constraint" with a typed 8-bit constant but not with an equivalent #define?


I am getting an error message about an impossible constraint using an 8-bit typed constant that I flag with constraint "M" in my inline assembly code for AVR 8-bit micro-controllers such as ATtiny1634 or ATmega328:

static const uint8_t tail_mask = (uint8_t)((rx1::queue_length-1) << \
    rx1::queue_length_bits) & 0xFF;

asm(
    ...
    "andi r30, %0\n\t"
    ...
:
: "M" (tail_mask)
);

warning: asm operand 1 probably doesn't match constraints

Here rx1 is a class name and both queue_length and queue_length_bits are static const uint8_t class constants. I can use "O", "N", no way. Using static, int8_t or not makes no difference.

If I replace the static const uint8_t definition above with a #define, the error message vanishes!

#define tail_mask ((rx1::queue_length-1) << rx1::queue_length_bits)

asm(
    ...
    "andi r30, %0\n\t"
    ...
:
: "M" (tail_mask)
);

Compiles fine!

That bugs me. Why does using an enforced 8-bit unsigned constant produce an error message over a constraint that forces it to be... an 8-bit unsigned constant?

For the record I'm using avr-gcc version 7.1.0.


Solution

  • The value passed to the constraint should probably be a 32 bit integer here. Which is what you get when you use the #define as it gets promoted to the expected type silently. Likewise using int or unsigned for your tail_mask value will be ok. Weird thing is I went through several versions of the documentation but found no trace of evidence that the M constraint argument cannot be an uint8_t or similar.