Has my (unused) variable been optimised out of existence?

My code:-

#define pwmPin 5
#define adcPin 5
#define mask 0b1

int8_t counter = 42;


void setup() {
  Serial.begin(57600);
  pinMode(pwmPin, OUTPUT);
  analogWrite(pwmPin, 127);
}



void loop() {
  uint8_t sample = analogRead(adcPin) & mask;
  if (sample == 0) {
    counter++;
  }
  Serial.println(sample);
  delay(10);
}

I am interested in whether the Arduino is actually executing counter++ within the loop() function. I realise that compilers are getting smarter every minute :slightly_frowning_face: , and wonder if it might realise that eventually nothing happens to counter. It is not output or re-used anywhere.

Is there a way that I can check the compiled code to see for myself please? I’m not really familiar with how my source gets into Arduinos.

I've never used it, but you might take a look at avr-objdump.

I would have assumed that the compiler would optimize away the entire if statement, but it looks like it does not. If I comment out the counter++; line the code size decreases by 16 bytes, indicating that the compiler is doing something there, although further commenting out the if statement does not produce any further reduction in code size, implying that once the body of the if statement is gone the compiler is eliminating the if statement entirely.

the code size decreases by 16 bytes, indicating that the compiler is doing something there, although further commenting out the if statement does not produce any further reduction in code size, implying that once the body of the if statement is gone the compiler is eliminating the if statement entirely.

This probably varies per core. I suspect that the variable is optimized out since it is never used, but the compiler may do that after checking for empty conditional code. What happens to the available RAM when you comment out the counter++; ?

Declare counter as volatile and it won't be optimized away. But, it does beg the question --- what are you trying to accomplish?

Deva_Rishi:
This probably varies per core. I suspect that the variable is optimized out since it is never used, but the compiler may do that after checking for empty conditional code. What happens to the available RAM when you comment out the

counter++;

?

I'm compiling for an UNO.

I never saw any change in RAM used, regardless if I commented out the counter++, the entire if statement, or just the if and left the counter++. Even adding a Serial.print of counter didn't change the RAM. Declaring as volatile did not appear to change anything. Declaring without an initial value did increase the RAM used by one byte.

Really would need to look at the compiled code, with only a single byte variable the compiler could be putting it in a register instead of memory.

You can set a flag that instructs the compiler to not optimize anything, or specific blocks of code.

look up gcc #pragma optimize

Also, in platform.txt, somewhere in the Arduino installation directory, you can set the overall optimization level.

So as suggested, I've compiled the code with various bits commented out:-

Program bytes/dynamic memory
2168/188 - all code as posted.
2152/188 - counter++ commented out
2152/188 - entire if statement commented out.

It seems that the counter++ is not optimised out. But once the body of the if statement is removed, the entire if statement including the test is optimised away. For interest, I then declared int32_t counter = 42 and repeated the above:-

Program bytes/dynamic memory
2202/192 - all code as posted except int32_t counter = 42.
2152/188 - counter++ commented out
2152/188 - entire if statement commented out.

Declaring counter as 32 bits seems to add an entire 50 bytes of object code! And 4 bytes of dynamic memory are used. This means that indeed a register was used originally when counter was 8 bits wide. It is clever isn't it?

Thanks all.


P.S. The reason for the incrementalism is a daft attempt to make the run time of the loop() function non-deterministic. The signal on the ADC pin is non deterministic. My adventures with true random number generation :confused:

cossoft:
Declaring counter as 32 bits seems to add an entire 50 bytes of object code! And 4 bytes of dynamic memory are used. This means that indeed a register was used originally when counter was 8 bits wide.

Nope...

    counter++;
 6d2:	90 91 00 01 	lds	r25, 0x0100
 6d6:	9f 5f       	subi	r25, 0xFF	; 255
 6d8:	90 93 00 01 	sts	0x0100, r25

With Arduino 1.8.13 / Uno counter is stored at memory address 0x0100.

If pin A5 is unconnected and has floated up to 1023 (0b1111111111) then that number & 0b1 = 1, never 0.

JCA34F:
If pin A5 is unconnected and has floated up to 1023 (0b1111111111) then that number & 0b1 = 1, never 0.

That would only affect the operation of the code at run-time, the compiler has no knowledge of what the result of an analogRead() would be. The only time that would be optimized away is when the compiler can detect that you never do anything with the value read from the port, and in this case you are printing it so it has to stay.

Note to the OP, adcpin would preferably be A5 instead of 5, the compiler knows enough to assume A5 because analogRead() only works on analog inputs, but other functions such as pinMode, digitalRead, and digitalWrite, would result in using digital pin 5 instead of analog pin A5.

But how do you square that with the first part of my experiment:-

Program bytes/dynamic memory
2168/188 - all code as posted.
2152/188 - counter++ commented out
2152/188 - entire if statement commented out.

which shows that no main memory was used? 188 bytes does not change whether the counter is included or excluded. I too used Arduino 1.8.13 / Uno. david_2018 above saw the same effect. De-compilation is not my strong suite. Shirley the dynamic memory would change if a variable came and went?

JCA34F:
If pin A5 is unconnected and has floated up to 1023 (0b1111111111) then that number & 0b1 = 1, never 0.

It isn't unconnected. It's connected to the PWM output from pin 5 via an RC filter. That creates a rising/falling exponential (but perfectly analogue) signal that is then read by A5. And I'm looking at ADC [quantisation error](https://en.wikipedia.org/wiki/Quantization_(signal_processing)) which is truly random, if sparse. I aim to make the run time of loop() non deterministic as analogRead() and PWM are both synchronised via the system clock. It creates a funny strobe effect otherwise, and that's the reason underlying the question. It's a sad hobby (http://www.reallyreallyrandom.com).

cossoft:
But how do you square that with the first part of my experiment:-

Appears to be alignment granularity, a quirk of the reporting tool, and a coin flip.

From what I can tell the AVR toolset does 16 bit alignment on the data section. If your program uses 187 bytes of SRAM a one byte pad is added so the data section is correctly aligned. That brings the section size up to your 188. The tool used by the IDE to report sizes simply outputs the section size (188) instead of the sum of the SRAM actually used (187 or 188).

I suspect this will be of interest.

cossoft:

It isn’t unconnected. It’s connected to the PWM output from pin 5 via an RC filter.

Well, why didn’t you say that in your OP? Ambiguous questions get ambiguous answers.

JCA34F:
Well, why didn't you say that in your OP? Ambiguous questions get ambiguous answers.

I don't see any ambiguity, the question was concerning the actions of the compiler, and the compiler never knows what is connected to an analog input, only that the value obtained from the input is not known at compile time.

JCA34F:
If pin A5 is unconnected and has floated up to 1023 (0b1111111111) then that number & 0b1 = 1, never 0.

I do not see any reasonable basis on which the compiler could make a determination like that, and therefore optimize away the code. I also see no basis for the assumption that a floating input would always float to a specific value and stay there, if that were the case it would not be floating.

I'm a little surprised as to the apparent randomness of TCNT1L. Strobing a fast clock is a common technique in all digital TRNGs, but they usually require decimation of the samples. I've seen factors of 512x. TCNT1L seems oddly uncorrelated even at 8 bits. I've not performed any analysis on it though...[/quote]

Not odd. Two independent clocks with wildly different attributes. The watchdog's jitter is especially important to getting good results. It's roughly equivalent to a human pressing a button to freeze the display of an atomic clock.

Actually, I should have plotted it. Raw TCNT1L does the following, so decimation is required:-

(Attachment).

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.