Recent

Author Topic: [ARM, LPC1114] Error DIV result  (Read 641 times)

devport

  • New Member
  • *
  • Posts: 14
[ARM, LPC1114] Error DIV result
« on: November 10, 2019, 01:35:10 pm »
I now, i now :P
it's me again

I'm Write code for OLED 1.3" SH1106 driver.
Maybe I found a compiler error

I use code for display string:
Code: Pascal  [Select]
  1.  procedure SH1106_string(x, y : byte; pstring : PChar; size, mode : byte; buffer : PByte);
  2. begin
  3.     while (Ord(pstring^) <> $00) do
  4.     begin
  5.         if (x > (WIDTH - trunc(size / 2))) then
  6.         begin
  7.             x := 0;
  8.             y := y + size;
  9.             if (y > (HEIGHT - size)) then
  10.             begin
  11.                 y := 0;
  12.                 x := 0;
  13.             end;
  14.         end;
  15.  
  16.         SH1106_char(x, y, pstring^, size, mode, buffer);
  17.         x := x + trunc(size / 2);
  18.         Inc(pstring);
  19.     end;
  20. end;

Parametrs:
size := 16

If "trunc(size/2)" change to "(size div 2)" my OLED bad showing string. WHY?
What am I doing wrong?



« Last Edit: November 10, 2019, 01:37:35 pm by devport »

howardpc

  • Hero Member
  • *****
  • Posts: 3210
Re: [ARM, LPC1114] Error DIV result
« Reply #1 on: November 10, 2019, 02:36:11 pm »
Do you get the same display difference between (size div 2) and Trunc(size/2) with the following?
Code: Pascal  [Select]
  1. procedure SH1106_string(x, y : byte; pstring : PChar; size, mode : byte; buffer : PByte);
  2. begin
  3.    size := size div 2;  // size := Trunc(size/2);
  4.    while (Ord(pstring^) <> $00) do
  5.    begin
  6.        if (x > (WID - size)) then
  7.        begin
  8.            x := 0;
  9.            y := y + size*2;
  10.            if (y > (HEI - size*2)) then
  11.            begin
  12.                y := 0;
  13.                x := 0;
  14.            end;
  15.        end;
  16.        SH1106_char(x, y, pstring^, size*2, mode, buffer);
  17.        x := x + size;
  18.        Inc(pstring);
  19.    end;
  20. end;
               

MiR

  • Jr. Member
  • **
  • Posts: 76
Re: [ARM, LPC1114] Error DIV result
« Reply #2 on: November 10, 2019, 03:30:00 pm »
Try simplifying, this makes it a lot easier to get a fix if there is an issue.

What is important, do you use trunc compiler or official compiler, which optimization level do you use?

For the following I am now using trunk compiler from this week and O2 because it makes (in this case) the generated code a little easier to read.
 
Most simple version of a test would be:

program test;
var
  size : byte;
begin
  size := 16;
  size := size div 2;
end.

then compile this and make sure you have assembler output enabled:

/usr/local/bin/ppcarm -O2 -Mobjfpc -Tembedded -al test.pas -WpLPC1114FBD48_302 -CpARMV6M

and then have a look at the generated code:

Code: ASM  [Select]
  1. # Var size located in register r1
  2. # [5] size := 16;
  3.         mov     r1,#16
  4. # [6] size := size div 2;
  5.         mov     r0,r1
  6.         lsr     r0,r0,#31
  7.         add     r0,r1,r0
  8.         asr     r0,r0,#1
  9.         uxtb    r0,r0
  10. # Var size located in register r0
  11.  

You can also run this code in gdb or ozone to see if r0 has correct value in the end. (for me it has)

Compiled with trunk compiler the code seems to do what I'd expect. Not the most optimized code for the situation but technically OK

Look as the assembler code that was generated by your code now, if the code for div looks very differnet then modify the most simple example to match the exact problem.

Then you will be able to properly judge if you found a compiler error or a programming error.
« Last Edit: November 10, 2019, 03:39:56 pm by MiR »

MiR

  • Jr. Member
  • **
  • Posts: 76
Re: [ARM, LPC1114] Error DIV result
« Reply #3 on: November 10, 2019, 04:24:38 pm »
Also this version:

Code: Pascal  [Select]
  1. program test;
  2. var
  3.   x,size : byte;
  4.  
  5. function doit(ax,asize : byte):byte;
  6. begin
  7.   Result := ax+(asize div 2);
  8. end;
  9.  
  10. begin
  11.   size := 16;
  12.   x := 10;
  13.   size := doit(x,size);
  14. end.
  15.  

looks ok, I now brought in the addition I saw in your code

Code: ASM  [Select]
  1. # Var $result located in register r0
  2.         uxtb    r2,r0
  3. # Var ax located in register r2
  4.         uxtb    r1,r1
  5. # Var asize located in register r1
  6. .Ll2:
  7. # [7] Result := ax+(asize div 2);
  8.         mov     r0,r1
  9.         lsr     r0,r0,#31
  10.         add     r0,r1,r0
  11.         asr     r0,r0,#1
  12.         add     r2,r0
  13. # Peephole UxtbUxtb2Uxtb done
  14.         uxtb    r0,r2
  15. # Var $result located in register r0
  16.  
« Last Edit: November 10, 2019, 04:26:30 pm by MiR »

devport

  • New Member
  • *
  • Posts: 14
Re: [ARM, LPC1114] Error DIV result
« Reply #4 on: November 10, 2019, 04:54:12 pm »
I'll check tomorrow, I'm at work now. 
Substituting a constant value the code works fine.
« Last Edit: November 10, 2019, 04:58:49 pm by devport »

MiR

  • Jr. Member
  • **
  • Posts: 76
Re: [ARM, LPC1114] Error DIV result
« Reply #5 on: November 10, 2019, 05:08:49 pm »
In your case (divide by 2) you can also try:

(size shr 1)

which will create much shorter code:

Code: ASM  [Select]
  1. .Ll2:
  2. # [7] Result := ax+(asize shr 1);
  3.         lsr     r0,r0,#1
  4.         add     r2,r0
  5. # Peephole UxtbUxtb2Uxtb done
  6.         uxtb    r0,r2
  7. # Var $result located in register r0

Thaddy

  • Hero Member
  • *****
  • Posts: 9303
Re: [ARM, LPC1114] Error DIV result
« Reply #6 on: November 10, 2019, 05:18:32 pm »
Code: ASM  [Select]
  1.   size := size div 2;
It does not matter too much here indeed - because the compiler folds it into a shift - but in general a shift would be the better option. (2) as you explained while posts crossed.
also related to equus asinus.

devport

  • New Member
  • *
  • Posts: 14
Re: [ARM, LPC1114] Error DIV result
« Reply #7 on: November 10, 2019, 11:40:17 pm »
Bit shifting result is correct! :)

All compile in -Mfpc (no objfpc)
and using ppcrossarm v 3.3.1 from source.

I paste 3 options:
this is -O2 optimization
Code: ASM  [Select]
  1. # [325] begin
  2.         push    {r4,r5,r6,r7,r14}
  3.         sub     r13,r13,#36
  4.         mov     r4,r0
  5. # Var x located in register r4
  6.         mov     r5,r1
  7. # Var y located in register r5
  8.         str     r2,[r13, #8]
  9. # Var pString located in register r0
  10.         mov     r6,r3
  11. # Var Size located in register r6
  12.         add     r1,r13,#56
  13.         ldr     r0,[r13, #12]
  14.         ldrb    r0,[r1]
  15.         str     r0,[r13, #12]
  16. # Var Mode located in register r0
  17.         ldr     r7,[r13, #60]
  18. # Var buffer located in register r7
  19. # [326] while (Ord(pstring^) <> $00) do
  20.         bl      .Lj101
  21. .Lj100:
  22. # [328] if (x > (WIDTH - (size div 2))) then
  23.         mov     r1,#128
  24.         sub     r1,r0
  25.         cmp     r1,r4
  26.         bge     .Lj105
  27.         bl      .Lj103
  28. .Lj105:
  29.         bl      .Lj104
  30. .Lj103:
  31. # [330] x := 0;
  32.         mov     r4,#0

this is no optimization:
Code: ASM  [Select]
  1. # [325] begin
  2.         push    {r4,r14}
  3.         sub     r13,r13,#48
  4. # Var x located at r13+8, size=OS_8
  5. # Var y located at r13+12, size=OS_8
  6. # Var pString located at r13+16, size=OS_32
  7. # Var Size located at r13+20, size=OS_8
  8. # Var Mode located at r13+24, size=OS_8
  9. # Var buffer located at r13+28, size=OS_32
  10.         add     r4,r13,#8
  11.         strb    r0,[r4]
  12.         add     r0,r13,#12
  13.         strb    r1,[r0]
  14.         str     r2,[r13, #16]
  15.         add     r0,r13,#20
  16.         strb    r3,[r0]
  17.         add     r0,r13,#56
  18.         add     r1,r13,#24
  19.         ldrb    r0,[r0]
  20.         strb    r0,[r1]
  21.         ldr     r0,[r13, #60]
  22.         str     r0,[r13, #28]
  23. # [326] while (Ord(pstring^) <> $00) do
  24.         bl      .Lj101
  25. .Lj100:
  26. # [328] if (x > (WIDTH - (size div 2))) then
  27.         add     r0,r13,#20
  28.         ldrb    r0,[r0]
  29.         mov     r1,#128
  30.         sub     r1,r0
  31.         add     r0,r13,#8
  32.         ldrb    r0,[r0]
  33.         cmp     r1,r0
  34.         bge     .Lj105
  35.         bl      .Lj103
  36. .Lj105:

this is no optimization, I using SHR:
Code: ASM  [Select]
  1. # [325] begin
  2.         push    {r4,r14}
  3.         sub     r13,r13,#48
  4. # Var x located at r13+8, size=OS_8
  5. # Var y located at r13+12, size=OS_8
  6. # Var pString located at r13+16, size=OS_32
  7. # Var Size located at r13+20, size=OS_8
  8. # Var Mode located at r13+24, size=OS_8
  9. # Var buffer located at r13+28, size=OS_32
  10.         add     r4,r13,#8
  11.         strb    r0,[r4]
  12.         add     r0,r13,#12
  13.         strb    r1,[r0]
  14.         str     r2,[r13, #16]
  15.         add     r0,r13,#20
  16.         strb    r3,[r0]
  17.         add     r0,r13,#56
  18.         add     r1,r13,#24
  19.         ldrb    r0,[r0]
  20.         strb    r0,[r1]
  21.         ldr     r0,[r13, #60]
  22.         str     r0,[r13, #28]
  23. # [326] while (Ord(pstring^) <> $00) do
  24.         bl      .Lj101
  25. .Lj100:
  26. # [328] if (x > (WIDTH - (size shr 1))) then
  27.         add     r0,r13,#20
  28.         ldrb    r0,[r0]
  29.         lsr     r0,r0,#1
  30.         mov     r3,#0
  31.         mov     r1,#128
  32.         mov     r2,#0
  33.         sub     r1,r0
  34.         sbc     r2,r3
  35.         add     r0,r13,#8
  36.         ldrb    r0,[r0]
  37.         mov     r3,#0
  38.         cmp     r2,r3
  39.         bge     .Lj105
  40.         bl      .Lj103
  41. .Lj105:

in 2 example I don't see dividing the number 'size'.
Is only subtraction from a variable 'WIDTH'
« Last Edit: November 10, 2019, 11:54:09 pm by devport »

Thaddy

  • Hero Member
  • *****
  • Posts: 9303
Re: [ARM, LPC1114] Error DIV result
« Reply #8 on: November 11, 2019, 09:08:07 am »
Yes, the shift it correct. It also shows a little thought is still required by the programmer to choose an optimal algorithm.
But in general, the compiler does a good job, even with div.
also related to equus asinus.

MiR

  • Jr. Member
  • **
  • Posts: 76
Re: [ARM, LPC1114] Error DIV result
« Reply #9 on: November 11, 2019, 02:41:19 pm »
Seems you are on to something, from what I can tell the DIV command vanished into thin air.... in both the -O2 and the -O- version of DIV. it is a lot easier to see in the -O2 Version where r6 is not referenced at all.

Can you try to create a very simple sample that shows the issue in one code file?

Sometimes the optimizer plays nasty tricks when it detects something is constant it pre-calculates the result and optimizes out a command like a divide by two completely.

Had this a week or two ago, so it is good to have a simple example where you can overlook the complete generated code.

And beeing able to run the code in a decent debugger also helps a lot.

Laksen

  • Hero Member
  • *****
  • Posts: 624
    • J-Software
Re: [ARM, LPC1114] Error DIV result
« Reply #10 on: November 11, 2019, 05:59:38 pm »
Looks like a bug

devport

  • New Member
  • *
  • Posts: 14
Re: [ARM, LPC1114] Error DIV result
« Reply #11 on: November 12, 2019, 10:10:24 am »
I used this example to check the DIV:

Using Lazarus IDE:
ppcrossarm.exe -Tembedded -Parm -CpARMV6M -MObjFPC -l -vewnhibq  -otestprogram -al -WpLPC1114FBD48_303

Only DIV example not power on my LED (pin)

Code: Pascal  [Select]
  1. program test;
  2. var
  3.   x,size : byte;
  4.  
  5. function doit(ax,asize : byte):byte;
  6. begin
  7.   Result := ax+(asize div 2);
  8. end;
  9.  
  10. begin
  11.    LPC_SYSCON.SYSAHBCLKCTRL := LPC_SYSCON.SYSAHBCLKCTRL or ((1 shl 6) or (1 shl 16));
  12.  
  13.  LPC_GPIO0.DIR := LPC_GPIO0.DIR OR $0002;
  14.  
  15.   size := 16;
  16.   x := 10;
  17.   size := doit(x,size);
  18.   if(size = 18) then
  19.    LPC_GPIO0.MASKED_ACCESS[$0002] := 0;
  20. end.

DIV:
Code: ASM  [Select]
  1. # [6] begin
  2.         push    {r14}
  3.         sub     r13,r13,#40
  4. # Var ax located at r13+0, size=OS_8
  5. # Var asize located at r13+4, size=OS_8
  6. # Var $result located at r13+8, size=OS_8
  7.         mov     r2,r13
  8.         strb    r0,[r2]
  9.         add     r0,r13,#4
  10.         strb    r1,[r0]
  11. # [7] Result := ax+(asize div 2);
  12.         add     r0,r13,#4
  13.         ldrb    r0,[r0]
  14.         mov     r0,r13
  15.         ldrb    r0,[r0]
  16.         add     r0,r1
  17.         uxtb    r0,r0
  18.         add     r1,r13,#8
  19.         strb    r0,[r1]
  20. # [8] end;
  21.         add     r1,r13,#8
  22.         ldrb    r0,[r1]
  23.         add     r13,r13,#40
  24.         pop     {r15}

SHR:
Code: ASM  [Select]
  1. # [6] begin
  2.         push    {r14}
  3.         sub     r13,r13,#40
  4. # Var ax located at r13+0, size=OS_8
  5. # Var asize located at r13+4, size=OS_8
  6. # Var $result located at r13+8, size=OS_8
  7.         mov     r2,r13
  8.         strb    r0,[r2]
  9.         add     r0,r13,#4
  10.         strb    r1,[r0]
  11. # [7] Result := ax+(asize shr 1);
  12.         add     r0,r13,#4
  13.         ldrb    r0,[r0]
  14.         mov     r1,r0
  15.         lsr     r1,r1,#1
  16.         mov     r0,r13
  17.         ldrb    r0,[r0]
  18.         add     r0,r1
  19.         uxtb    r0,r0
  20.         add     r1,r13,#8
  21.         strb    r0,[r1]
  22. # [8] end;
  23.         add     r1,r13,#8
  24.         ldrb    r0,[r1]
  25.         add     r13,r13,#40
  26.         pop     {r15}

all outputs assembly in attachments.


MiR

  • Jr. Member
  • **
  • Posts: 76
Re: [ARM, LPC1114] Error DIV result
« Reply #12 on: November 12, 2019, 11:14:04 am »
How old is your trunk based compiler?

with this version:

Free Pascal Compiler version 3.3.1 [2019/11/10] for arm

the assembler code looks OK
Code: ASM  [Select]
  1. # Var ax located at r13+0, size=OS_8
  2. # Var asize located at r13+4, size=OS_8
  3. # Var $result located at r13+8, size=OS_8
  4.         mov     r2,r13
  5.         strb    r0,[r2]
  6.         add     r0,r13,#4
  7.         strb    r1,[r0]
  8. # [7] Result := ax+(asize div 2);
  9.         add     r0,r13,#4
  10.         ldrb    r0,[r0]
  11.         mov     r1,r0
  12.         lsr     r1,r1,#31
  13.         add     r1,r0,r1
  14.         asr     r1,r1,#1
  15.         mov     r0,r13
  16.         ldrb    r0,[r0]
  17.         add     r0,r1
  18.         uxtb    r1,r0
  19.         add     r0,r13,#8
  20.         strb    r1,[r0]
  21. # [8] end;
  22.         add     r1,r13,#8
  23.         ldrb    r0,[r1]
  24.         add     r13,r13,#40
  25.         pop     {r15}

devport

  • New Member
  • *
  • Posts: 14
Re: [ARM, LPC1114] Error DIV result
« Reply #13 on: November 12, 2019, 11:52:28 am »
3.3.1 [2019/11/03]

If this example compile to x86 on Windows this result is correct.
fault is only cross arm compiler.
« Last Edit: November 12, 2019, 12:43:11 pm by devport »

Thaddy

  • Hero Member
  • *****
  • Posts: 9303
Re: [ARM, LPC1114] Error DIV result
« Reply #14 on: November 12, 2019, 01:48:40 pm »
3.3.1 [2019/11/03]

If this example compile to x86 on Windows this result is correct.
fault is only cross arm compiler.
On arm it is a bug. You should report it. It is also possibly a regression depending on the compiler you used.
If Laksen says it is a possible bug I tend to believe him, specifically since the equivalent shift works as I tested.
also related to equus asinus.