* use destination location instead of a temp when constructing sets, resolves #40384

This commit is contained in:
florian 2024-03-22 21:50:42 +01:00
parent 8aca910435
commit 06fc6f1e6b

View File

@ -3616,6 +3616,7 @@ implementation
tempn: tnode;
newstatement : tstatementnode;
temp : ttempcreatenode;
no_temp: Boolean;
begin
result:=nil;
@ -3652,40 +3653,31 @@ implementation
end;
addn:
begin
{ can we directly write into the result? }
no_temp:=assigned(aktassignmentnode) and
(aktassignmentnode.right=self) and
(aktassignmentnode.left.resultdef=self.resultdef) and
valid_for_var(aktassignmentnode.left,false);
{ optimize first loading of a set }
if (right.nodetype=setelementn) and
not(assigned(tsetelementnode(right).right)) and
is_emptyset(left) then
begin
result:=internalstatements(newstatement);
{ create temp for result }
temp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
addstatement(newstatement,temp);
{ adjust for set base }
tsetelementnode(right).left:=caddnode.create(subn,
ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
addstatement(newstatement,ccallnode.createintern('fpc_varset_create_element',
ccallparanode.create(ctemprefnode.create(temp),
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(tsetelementnode(right).left,nil))))
);
{ the last statement should return the value as
location and type, this is done be referencing the
temp and converting it first from a persistent temp to
normal temp }
addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
addstatement(newstatement,ctemprefnode.create(temp));
tsetelementnode(right).left := nil;
end
else
begin
if right.nodetype=setelementn then
if no_temp then
begin
result:=ccallnode.createintern('fpc_varset_create_element',
ccallparanode.create(aktassignmentnode.left.getcopy,
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(tsetelementnode(right).left,nil))));
include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
end
else
begin
result:=internalstatements(newstatement);
@ -3693,43 +3685,96 @@ implementation
temp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
addstatement(newstatement,temp);
{ adjust for set base }
tsetelementnode(right).left:=caddnode.create(subn,
ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
addstatement(newstatement,ccallnode.createintern('fpc_varset_create_element',
ccallparanode.create(ctemprefnode.create(temp),
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(tsetelementnode(right).left,nil))))
);
{ add a range or a single element? }
if assigned(tsetelementnode(right).right) then
begin
{ adjust for set base }
tsetelementnode(right).right:=caddnode.create(subn,
ctypeconvnode.create_internal(tsetelementnode(right).right,sinttype),
cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
addstatement(newstatement,ccallnode.createintern('fpc_varset_set_range',
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(tsetelementnode(right).right,
ccallparanode.create(tsetelementnode(right).left,
ccallparanode.create(ctemprefnode.create(temp),
ccallparanode.create(left,nil))))))
);
end
else
addstatement(newstatement,ccallnode.createintern('fpc_varset_set',
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
ccallparanode.create(ctemprefnode.create(temp),
ccallparanode.create(left,nil)))))
);
{ remove reused parts from original node }
tsetelementnode(right).right:=nil;
tsetelementnode(right).left:=nil;
left:=nil;
{ the last statement should return the value as
location and type, this is done be referencing the
temp and converting it first from a persistent temp to
normal temp }
addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
addstatement(newstatement,ctemprefnode.create(temp));
end;
tsetelementnode(right).left:=nil;
end
else
begin
if right.nodetype=setelementn then
begin
{ adjust for set base }
tsetelementnode(right).left:=caddnode.create(subn,
ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
if no_temp then
begin
{ add a range or a single element? }
if assigned(tsetelementnode(right).right) then
begin
{ adjust for set base }
tsetelementnode(right).right:=caddnode.create(subn,
ctypeconvnode.create_internal(tsetelementnode(right).right,sinttype),
cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
result:=ccallnode.createintern('fpc_varset_set_range',
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(tsetelementnode(right).right,
ccallparanode.create(tsetelementnode(right).left,
ccallparanode.create(aktassignmentnode.left.getcopy,
ccallparanode.create(left,nil))))));
end
else
result:=ccallnode.createintern('fpc_varset_set',
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
ccallparanode.create(aktassignmentnode.left.getcopy,
ccallparanode.create(left,nil)))));
include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
end
else
begin
result:=internalstatements(newstatement);
{ create temp for result }
temp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
addstatement(newstatement,temp);
{ add a range or a single element? }
if assigned(tsetelementnode(right).right) then
begin
{ adjust for set base }
tsetelementnode(right).right:=caddnode.create(subn,
ctypeconvnode.create_internal(tsetelementnode(right).right,sinttype),
cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
addstatement(newstatement,ccallnode.createintern('fpc_varset_set_range',
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(tsetelementnode(right).right,
ccallparanode.create(tsetelementnode(right).left,
ccallparanode.create(ctemprefnode.create(temp),
ccallparanode.create(left,nil))))))
);
end
else
addstatement(newstatement,ccallnode.createintern('fpc_varset_set',
ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
ccallparanode.create(ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
ccallparanode.create(ctemprefnode.create(temp),
ccallparanode.create(left,nil)))))
);
{ the last statement should return the value as
location and type, this is done be referencing the
temp and converting it first from a persistent temp to
normal temp }
addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
addstatement(newstatement,ctemprefnode.create(temp));
end;
{ remove reused parts from original node }
tsetelementnode(right).right:=nil;
tsetelementnode(right).left:=nil;
left:=nil;
end
else
call_varset_helper('fpc_varset_add_sets');