[AVR] Incorrect code generated under -O3 for parameter passed by reference

Summary

16 bit sized subroutine parameters passed by reference gets clobbered under certain conditions when optimization level 3 or higher is active.

System Information

  • Operating system: embedded
  • Processor architecture: AVR
  • Compiler version: 3.3.1 (11cf2489), also 3.2.2
  • Device: Microcontroller

Steps to reproduce

Compile and test example project:

Example Project

program testsimavr;

var
  w, r: word;

procedure func(var a: word; var r: word);
begin
  r := a;
  dec(a);
  inc(r);
end;

begin
  w := 1234;
  func(w, r);
  writeln('w = ', w, ' (expected w = 1233)');
  writeln('r = ', r, ' (expected r = 1235)');
end.

What is the current bug behavior?

$ ~/fpc/gitlab/compiler/avr/pp -n @~/fpc/gitlab/fpc.cfg -Wpavrsim  -al -O3 testsimavr.pp

$ ~/LazProjs/fp-avrsim-cc/avrsim testsimavr.bin 
w = 978 (expected w = 1233)
r = 1235 (expected r = 1235)

What is the expected (correct) behavior?

$ ~/fpc/gitlab/compiler/avr/pp -n @~/fpc/gitlab/fpc.cfg -Wpavrsim -al -O2 testsimavr.pp

$ ~/LazProjs/fp-avrsim-cc/avrsim testsimavr.bin 
w = 1233 (expected w = 1233)
r = 1235 (expected r = 1235)

Relevant logs and/or screenshots

The bug manifests in procedure func, on the line dec(a) - specifically when loading the value of variable a from its reference:

# [8] r := a;
	movw	r30,r24
	movw	r26,r22
	ld	r0,Z+
	st	X+,r0
	ld	r0,Z
	st	X,r0
.Ll2:
# [9] dec(a);
	ld	r18,Z
	ldd	r19,Z+1

The bug is that the instruction ld r0, Z+ modifies Z, so Z should be reloaded with the reference to a before the ld r18, Z instruction. With -O2 this does happen:

# [8] r := a;
	movw	r30,r24
	movw	r26,r22
	ld	r0,Z+
	st	X+,r0
	ld	r0,Z
	st	X,r0
.Ll2:
# [9] dec(a);
	movw	r30,r24
	ld	r18,Z
	ldd	r19,Z+1

Since the correct instruction sequence is generated at lower optimization levels it suggests that some optimization is responsible for this bug. It is possible that this optimization check misses that ld r0, Z+ modifies Z and therefore eliminates the required movw r30, r24. Unfortunately the specific optimization responsible for this is not reported by -dDEBUG_AOPTCPU.