* * *

Author Topic: Mixing signed expressions hint  (Read 415 times)

Starchild

  • New member
  • *
  • Posts: 11
Mixing signed expressions hint
« on: July 11, 2018, 09:28:49 pm »
Hi,

Let's say I have the following minimal example code:
Code: [Select]
function Decide(rm: Byte): Boolean;
begin
  Result := (rm and $07) = ((rm shr 3) and $07);
end;

When I compile it, I get the hint "Mixing signed expressions and longwords gives a 64bit result". I don't get why - Byte is an unsigned type and there is no other variable involved. It seems as soon as there is a right-shift involved, it starts doing crazy things. My target is IA-32, and I'd expect code like "shr al, 3 ; and al, 7" for the expression on the right-hand side. Both, "shr" and "and" are logical/bitwise operations that have nothing to do with signedness.

The machine code generated for that function is insane (FPC 3.0.4, -O3):
Code: [Select]
.text:00401420                 public P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN
.text:00401420 P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN proc near
.text:00401420                                         ; CODE XREF: _main+7↓p
.text:00401420                 push    ebx
.text:00401421                 movzx   edx, al
.text:00401424                 shr     edx, 3
.text:00401427                 and     edx, 7
.text:0040142A                 mov     ebx, 0
.text:0040142F                 and     ax, 7
.text:00401433                 movsx   eax, ax
.text:00401436                 movsx   eax, ax
.text:00401439                 mov     ecx, eax
.text:0040143B                 sar     ecx, 1Fh
.text:0040143E                 cmp     ebx, ecx
.text:00401440                 jnz     short loc_40144A
.text:00401442                 cmp     edx, eax
.text:00401444                 jnz     short loc_40144A
.text:00401446                 mov     al, 1
.text:00401448                 jmp     short loc_40144C
.text:0040144A ; ---------------------------------------------------------------------------
.text:0040144A
.text:0040144A loc_40144A:                             ; CODE XREF: P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN+20↑j
.text:0040144A                                         ; P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN+24↑j
.text:0040144A                 mov     al, 0
.text:0040144C
.text:0040144C loc_40144C:                             ; CODE XREF: P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN+28↑j
.text:0040144C                 pop     ebx
.text:0040144D                 retn
.text:0040144D P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN endp

When I add a Byte cast around rm shr 3 (totally unintuitive that I'd have to do such a thing), it gets a bit better. But still not exactly what I would expect.
Code: [Select]
.text:00401420                 public P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN
.text:00401420 P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN proc near
.text:00401420                                         ; CODE XREF: _main+7↓p
.text:00401420                 movzx   edx, al
.text:00401423                 shr     edx, 3
.text:00401426                 and     dx, 7
.text:0040142B                 and     ax, 7
.text:0040142F                 cmp     dx, ax
.text:00401432                 setz    al
.text:00401435                 retn
.text:00401435 P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN endp

It seems the codegen doesn't want to use the SHR r/m8,imm8 instruction and avoids 8-bit registers in general. The "and ax, 7" looks a bit fishy as well since only al is being passed into the function, but I guess it doesn't matter in the case of "and". In Delphi I don't get any hint and the code it generates looks better too. It does a 32-bit shift as well, but the code looks more like the second example here (without requiring a Byte-cast).

Is this a bug? Am I wrong that this behavior is unexpected?
« Last Edit: July 11, 2018, 09:39:18 pm by Starchild »

440bx

  • Sr. Member
  • ****
  • Posts: 256
Re: Mixing signed expressions hint
« Reply #1 on: July 11, 2018, 10:10:08 pm »
Hello Starchild,

This in no way answers your question but, I have noticed that FPC seems to generate 64bit code that is significantly better than the 32bit code.  I'm curious to find out if the problem you mentioned also happens in 64bit.

It would be nice if you could compile your code for a 64bit target and report on the code it generated.

Thanks.

Gammatester

  • Jr. Member
  • **
  • Posts: 58
Re: Mixing signed expressions hint
« Reply #2 on: July 11, 2018, 10:11:08 pm »
Even though it looks surprising, this is not a bug, because shr works on integers ('Logical operators require operands that are of an integer type, and produce an integer type result', see https://freepascal.org/docs-html/ref/refsu46.html). I had a similar observation and discussion here: http://forum.lazarus.freepascal.org/index.php/topic,41563.0.html
« Last Edit: July 11, 2018, 10:12:49 pm by Gammatester »

Nitorami

  • Sr. Member
  • ****
  • Posts: 344
Re: Mixing signed expressions hint
« Reply #3 on: July 11, 2018, 10:14:06 pm »
Gammatester was quicker than me...
You can avoid that behaviour by using an arithmetic instead of logical shift sarshortint (rm,3), or simply div 8 instead of shr 3.

Starchild

  • New member
  • *
  • Posts: 11
Re: Mixing signed expressions hint
« Reply #4 on: July 11, 2018, 10:53:15 pm »
It would be nice if you could compile your code for a 64bit target and report on the code it generated.

You're right, it is indeed better, but adding the Byte cast still yet makes it better (it drops the movsx and does cmp ax, cx).
Code: [Select]
.text:0000000100001460 P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN proc near
.text:0000000100001460                                         ; CODE XREF: main+11↓p
.text:0000000100001460                 movzx   eax, cl
.text:0000000100001463                 shr     eax, 3
.text:0000000100001466                 and     eax, 7
.text:0000000100001469                 and     cx, 7
.text:000000010000146E                 movsx   rcx, cx
.text:0000000100001472                 cmp     rax, rcx
.text:0000000100001475                 setz    al
.text:0000000100001478                 and     eax, 0FFh
.text:000000010000147D                 retn
.text:000000010000147D P$PROJECT1_$$_DECIDE$BYTE$$BOOLEAN endp

Even though it looks surprising, this is not a bug, because shr works on integers ('Logical operators require operands that are of an integer type, and produce an integer type result', see https://freepascal.org/docs-html/ref/refsu46.html). I had a similar observation and discussion here: http://forum.lazarus.freepascal.org/index.php/topic,41563.0.html
Gammatester was quicker than me...
You can avoid that behaviour by using an arithmetic instead of logical shift sarshortint (rm,3), or simply div 8 instead of shr 3.

That sucks. I guess {$mode delphi} doesn't affect stuff like basic types and their interactions in expressions. I don't think an arithmetic shift is equivalent to a logical shift in all situations where I have code like this. For divisions it also produces crazy code (multiple arithmetic right shifts). I'll go with adding Byte casts...

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus