View Issue Details

IDProjectCategoryView StatusLast Update
0035872FPCCompilerpublic2019-09-17 11:35
ReporterTimm Thaler Assigned ToJeppe Johansen  
Status resolvedResolutionno change required 
Product Version3.3.1 
Summary0035872: AVR: Compiler produces inefficient code when compare 16 bit variables
DescriptionSince some weeks the compiler startet with producing inefficient code when comparing 16 bit variable with possible carry. The variables are expanded to 32 bit and the compare is done with 32 bit.

Adding a constant in the compare is important to reproduce. It does not happen when comparing without adding or adding a variable.
Steps To Reproducevar
  a, b : uint16;
    if a > b + 1 then begin

  until false;

compiles to

# [17] if a > b + 1 then begin
    mov r2,r19
    mov r3,r20
    mov r23,r1
    mov r24,r1
    ldi r21,1
    add r2,r21
    adc r3,r1
    adc r23,r1
    adc r24,r1
    cp r2,r25
    cpc r3,r18
    cpc r23,r1
    cpc r24,r1
    brge .Lj3
Additional InformationCompiler options is -O3, but -O4 or -Os doesn't change behavior.

It may seem to be a good idea to prevent overflow problems, but it puffs the code and doubles execution time - and in most cases it is not necessary.
Fixed in Revision
Attached Files


Christo Crause

2019-07-23 10:58

reporter   ~0117349

I suspect this behaviour is caused by automatic type conversion rules 2 & 3a as can be seen below table 3.2 here: Rule 2 implies (but it is not all that clear to me) that the constant value is interpreted as a shortint. Rule 3a then requires the use of int32 to evaluate the expression.

A type cast of the constant value to an unsigned type may result in the desired code being generated (I don't have FPC for AVR handy at the moment so I cannot test this).

Christo Crause

2019-07-23 21:15

reporter   ~0117364

Last edited: 2019-07-24 13:55

View 2 revisions

Type casting the constant to an unsigned type does reduce generated code size:

function testComparison(a, b: uint16): boolean;
  if a > b + byte(1) then
    Result := true
    Result := false;

Results in the following assembler:
# [11] if a > b + byte(1) then
    ldi r18,1
    add r22,r18
    adc r23,r1
    cp r22,r24
    cpc r23,r25
    brsh .Lj6
# [12] Result := true
    ldi r18,1
    rjmp .Lj7
# [14] Result := false;
    mov r18,r1
# [15] end;

Edit: the type cast in the example code was missing for some reason.

Timm Thaler

2019-07-24 19:25

reporter   ~0117382

I checked this for some operations (add, sub, mul, compare) and it is: Operation of 8 or 16 bit signed with 16 bit unsigned leads to an 32 bit signed result. So this is strange if one have to put an unsigned typecast to a positive constant, but it seems to be according to the conversion rules 3a.

        uint8 uint16 int8 int16
uint8 =uint8 =uint16 =int8 =int16
uin16 =uint16 =uint16 =int32 =int32
int8 =int8 =int32 =int8 =int16
int16 =int16 =int32 =int16 =int16

So better use mostly signed types in calculations or compares.

I guess this can be closed?

Issue History

Date Modified Username Field Change
2019-07-22 00:07 Timm Thaler New Issue
2019-07-23 10:58 Christo Crause Note Added: 0117349
2019-07-23 21:15 Christo Crause Note Added: 0117364
2019-07-24 13:55 Christo Crause Note Edited: 0117364 View Revisions
2019-07-24 19:25 Timm Thaler Note Added: 0117382
2019-07-25 11:39 Jeppe Johansen Assigned To => Jeppe Johansen
2019-07-25 11:39 Jeppe Johansen Status new => resolved
2019-07-25 11:39 Jeppe Johansen Resolution open => no change required
2019-07-25 11:39 Jeppe Johansen FPCTarget => -
2019-09-17 11:35 Dimitrios Chr. Ioannidis Tag Attached: AVR