Hi,
Let's say I have the following minimal example code:
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):
.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.
.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?