* don't mess with boolean and/or operations in mixed short/full evaluated expressions, resolves #41012

This commit is contained in:
florian 2024-11-16 17:27:16 +01:00
parent ede14da4d2
commit e4af0fc1e9
2 changed files with 23 additions and 5 deletions

View File

@ -356,9 +356,9 @@ unit optcse;
(is_set(n.resultdef))
) then
while (n.nodetype=tbinarynode(n).left.nodetype) and
{ if node (1) is fully boolean evaluated and node (2) not, we cannot do the swap as this might result in B being evaluated always,
the other way round is no problem, C is still evaluated only if needed }
(not(is_boolean(n.resultdef)) or not(n.nodetype in [andn,orn]) or doshortbooleval(n) or not(doshortbooleval(tbinarynode(n).left))) and
{ if not both or none of the nodes is short/full boolean evaluated, we cannot do this optimization as it might change
semantics, there are border cases where this might not apply, but so far it is not worth the effort to check }
(not(is_boolean(n.resultdef)) or not(n.nodetype in [andn,orn]) or (doshortbooleval(n)=doshortbooleval(tbinarynode(n).left))) and
{ the resulttypes of the operands we'll swap must be equal,
required in case of a 32x32->64 multiplication, then we
cannot swap out one of the 32 bit operands for a 64 bit one
@ -374,10 +374,13 @@ unit optcse;
foreachnodestatic(pm_postprocess,tbinarynode(tbinarynode(n).left).right,@searchsubdomain,@csedomain);
if csedomain then
begin
{ move the full boolean evaluation of (2) to (1), if it was there (so it again applies to A and
{
move the full boolean evaluation of (2) to (1), if it was there (so it again applies to A and
what follows) }
{ this cannot happen anymore, see above, so the condition is not needed anymore
if not(doshortbooleval(tbinarynode(n).left)) and
doshortbooleval(n) then
doshortbooleval(n) then }
begin
n.localswitches:=n.localswitches+(tbinarynode(n).left.localswitches*[cs_full_boolean_eval]);
exclude(tbinarynode(n).left.localswitches,cs_full_boolean_eval);

15
tests/webtbs/tw41012.pp Normal file
View File

@ -0,0 +1,15 @@
program test;
{$mode objfpc}
function GetFalse: Boolean;
begin
Result := False;
end;
var
obj: TInterfacedObject;
i: Integer;
begin
if GetFalse and (i >= 0) and (i < obj.RefCount) then;
end.