AVR assembly statement don't work

hello i'm using an atmega16u2 chip (https://ww1.microchip.com/downloads/en/DeviceDoc/doc7799.pdf) and writing some assembly code but there's one assembly instruction that is not working.

byte on, off;
unsigned int counthigh;

void setup() {
        Serial.begin(9600);
        counthigh = 3;
        on = 3;
        off = 1;
}

void loop() {

  while (1) {
    delay(100);
    Serial.write("\nx = ");
    Serial.write((on/10) + 48);
    Serial.write((on%10) + 48);
    Serial.write("   ");
    Serial.write((off/10) + 48);
    Serial.write((off%10) + 48);
    Serial.write("   ");
    Serial.write((counthigh/10) + 48);
    Serial.write((counthigh%10) + 48);

    asm volatile (
      "dec %2 \n\t"           // <-- this statement executes, (counthigh -= 1)
      "brpl 2f \n\t"          // <-- executes, (branch if counthigh < 0)
      "inc %2 \n\t"           // <-- executes, (counthigh += 1)
      "inc %2 \n\t"           // <-- executes, (counthigh += 1)
      "adiw %2, 7 \n\t"       // <-- does NOT execute, (counthigh += 7)
      "2: \n\t"
      "inc %0 \n\t"          // <-- executes, (on += 1)
      : "+r" (on), "+r" (off), "+r" (counthigh)
      : 
      :
    );
  }
}

output on serial monitor:
x = 03 01 03
x = 04 01 02
x = 05 01 01
x = 06 01 00
x = 07 01 01 // counthigh = 1 when it's supposed to be 8, the "adiw %2, 7" has no effect
x = 08 01 00
...

Why are you using ASM? its short and simple enough in Cxx.

I think you need to use +w (counthigh)to get it to know that it's a 16bit value.
I'm not sure what will happen with +r there; I actually get correct output when running your code on an Uno:


x = 03   01   03
x = 04   01   02
x = 05   01   01
x = 06   01   00
x = 07   01   08

Well what you're seeing is just a snippet from out of a larger program where I'm having to create a soft pwm and i need higher frequency than I can get using delaymicroseconds.

Correct output as written?

Yep. the object code looks OK too.
But since we're in the realm of undefined behavior, it's not horribly surprising that a 16u2 would behave differently. (I don't have a 16u2 core to test with, though.)

ok this is really strange. i compiled again and now it is working with the adiw instruction. Don't really know what's up, but i think i had a typo where there was a "clobber" register in the code that wasn't required. But i can't be sure.
Anyway, THANX i got it goin now.

With things like link-time optimization, I'd somewhat expect the exact behavior of an incorrect width asm argument specifier (+r vs +w) to change (perhaps randomly) depending on what registers were "in use" by the code that the linker ends up in-lining "near" the asm code.

maybe that would explain another error i'm getting. I added a single statement "adiw %3, 6 \n\t" so now it reads:

    asm volatile (
      "dec %2 \n\t"           // <-- this statement executes, (countlow -= 1)
      "brpl 2f \n\t"          // <-- executes, (branch if countlow < 0)
      "inc %2 \n\t"           // <-- executes, (countlow += 1)
      "inc %2 \n\t"           // <-- executes, (countlow += 1)
      "adiw %2, 7 \n\t"       // <-- executes (countlow += 7)
      "adiw %3, 6 \n\t"       // <-- gives assembler error
      "2: \n\t"
      "inc %0 \n\t"          // <-- executes, (on += 1)
      : "+r" (on), "+r" (off), "+r" (countlow), "+r" (counthigh)
      : 
      :
    );

and now i get:
"C:\Users\User\AppData\Local\Temp\cceV29QE.s: Assembler messages:
C:\Users\User\AppData\Local\Temp\cceV29QE.s:1538: Error: register r24, r26, r28 or r30 required"