summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorflorian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2>2019-06-16 21:29:48 +0000
committerflorian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2>2019-06-16 21:29:48 +0000
commitc091377c82543520d8a7024539b995f7a83e598a (patch)
tree607ab1def06d9193fd09faba54380ab5335a218b
parent5ec0a0bc1e60fa88ceeac9ec9f345c32939b7a49 (diff)
downloadfpc-c091377c82543520d8a7024539b995f7a83e598a.tar.gz
+ keep (certain) arrays in registers if they are used with constants indices only
git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@42239 3ad0048d-3df7-0310-abae-a5850022a9f2
-rw-r--r--compiler/defutil.pas11
-rw-r--r--compiler/hlcgobj.pas6
-rw-r--r--compiler/ncgmem.pas69
-rw-r--r--compiler/ncnv.pas1
-rw-r--r--compiler/nmem.pas4
-rw-r--r--compiler/symdef.pas8
6 files changed, 84 insertions, 15 deletions
diff --git a/compiler/defutil.pas b/compiler/defutil.pas
index 6ac905156b..862ff650ea 100644
--- a/compiler/defutil.pas
+++ b/compiler/defutil.pas
@@ -156,6 +156,9 @@ interface
}
function is_special_array(p : tdef) : boolean;
+ {# Returns true, if p points to a normal array, bitpacked arrays are included }
+ function is_normal_array(p : tdef) : boolean;
+
{# Returns true if p is a bitpacked array }
function is_packed_array(p: tdef) : boolean;
@@ -752,6 +755,14 @@ implementation
);
end;
+ { true, if p points to a normal array, bitpacked arrays are included }
+ function is_normal_array(p : tdef) : boolean;
+ begin
+ result:=(p.typ=arraydef) and
+ ((tarraydef(p).arrayoptions * [ado_IsVariant,ado_IsArrayOfConst,ado_IsConstructor,ado_IsDynamicArray])=[]) and
+ not(is_open_array(p));
+ end;
+
{ true if p is an ansi string def }
function is_ansistring(p : tdef) : boolean;
begin
diff --git a/compiler/hlcgobj.pas b/compiler/hlcgobj.pas
index 627b36c0e4..daef6110fe 100644
--- a/compiler/hlcgobj.pas
+++ b/compiler/hlcgobj.pas
@@ -823,9 +823,13 @@ implementation
objectdef,
procvardef,
procdef,
- arraydef,
formaldef:
result:=R_ADDRESSREGISTER;
+ arraydef:
+ if tstoreddef(def).is_intregable then
+ result:=R_INTREGISTER
+ else
+ result:=R_ADDRESSREGISTER;
floatdef:
if use_vectorfpu(def) then
result:=R_MMREGISTER
diff --git a/compiler/ncgmem.pas b/compiler/ncgmem.pas
index a38849f939..a751625835 100644
--- a/compiler/ncgmem.pas
+++ b/compiler/ncgmem.pas
@@ -855,7 +855,9 @@ implementation
paraloc2 : tcgpara;
subsetref : tsubsetreference;
temp : longint;
+ hreg : tregister;
indexdef : tdef;
+ i : Integer;
begin
paraloc1.init;
paraloc2.init;
@@ -936,19 +938,29 @@ implementation
end
else
begin
- { may happen in case of function results }
- case left.location.loc of
- LOC_CSUBSETREG,
- LOC_CREGISTER,
- LOC_CMMREGISTER,
- LOC_SUBSETREG,
- LOC_REGISTER,
- LOC_MMREGISTER:
- hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
- else
- ;
- end;
- location_copy(location,left.location);
+ { may happen in case of function results }
+ case left.location.loc of
+ LOC_CREGISTER,
+ LOC_REGISTER:
+ begin
+ if not(is_constnode(right)) or (tarraydef(left.resultdef).elementdef.size<>alusinttype.size) then
+ hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
+ { we use location here only to get the right offset }
+ location_reset_ref(location,LOC_REFERENCE,OS_NO,1,[]);
+ end;
+ LOC_CSUBSETREG,
+ LOC_CMMREGISTER,
+ LOC_SUBSETREG,
+ LOC_MMREGISTER:
+ begin
+ hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
+ location_copy(location,left.location);
+ end;
+ LOC_INVALID:
+ Internalerror(2019061101);
+ else
+ location_copy(location,left.location);
+ end;
end;
{ location must be memory }
@@ -994,6 +1006,37 @@ implementation
update_reference_offset(location.reference,extraoffset,bytemulsize);
{ adjust alignment after this change }
location.reference.alignment:=newalignment(location.reference.alignment,extraoffset*bytemulsize);
+
+ { actually an array in a register? }
+ if (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) and
+ is_normal_array(left.resultdef) then
+ begin
+{$if defined(cpu64bitalu)}
+ hreg:=left.location.register;
+{$else defined(cpu64bitalu}}
+ if target_info.endian=endian_little then
+ begin
+ if location.reference.offset>3 then
+ hreg:=left.location.register64.reghi
+ else
+ hreg:=left.location.register64.reglo;
+ end
+ else
+ begin
+ if location.reference.offset>3 then
+ hreg:=left.location.register64.reglo
+ else
+ hreg:=left.location.register64.reghi;
+ end;
+{$endif defined(cpu64bitalu)}
+{$if defined(cpu8bitalu) or defined(cpu16bitalu)}
+ { we support only the case that one element fills at least one register }
+ for i:=1 to location.reference.offset mod 4 do
+ hreg:=cg.GetNextReg(hreg);
+{$endif defined(cpu8bitalu) or defined(cpu16bitalu)}
+ location_reset(location,left.location.loc,def_cgsize(tarraydef(left.resultdef).elementdef));
+ location.register:=hreg;
+ end;
end
else
begin
diff --git a/compiler/ncnv.pas b/compiler/ncnv.pas
index 5fd1e9605e..5f69d3a6e6 100644
--- a/compiler/ncnv.pas
+++ b/compiler/ncnv.pas
@@ -3255,6 +3255,7 @@ implementation
begin
first_array_to_pointer:=nil;
+ make_not_regable(left,[ra_addr_regable]);
expectloc:=LOC_REGISTER;
end;
diff --git a/compiler/nmem.pas b/compiler/nmem.pas
index ec36ceead6..4eae7da363 100644
--- a/compiler/nmem.pas
+++ b/compiler/nmem.pas
@@ -1054,7 +1054,9 @@ implementation
that has a field of one of these types -> in that case the record
can't be a regvar either }
if ((left.resultdef.typ=arraydef) and
- not is_special_array(left.resultdef)) or
+ not is_special_array(left.resultdef) and
+ { arrays with elements equal to the alu size and with a constant index can be kept in register }
+ not(is_constnode(right) and (tarraydef(left.resultdef).elementdef.size=alusinttype.size))) or
((left.resultdef.typ=stringdef) and
(tstringdef(left.resultdef).stringtype in [st_shortstring,st_longstring])) then
make_not_regable(left,[ra_addr_regable]);
diff --git a/compiler/symdef.pas b/compiler/symdef.pas
index 12a28dafd1..b4e54b9c7f 100644
--- a/compiler/symdef.pas
+++ b/compiler/symdef.pas
@@ -2225,6 +2225,14 @@ implementation
is_intregable:=(is_implicit_pointer_object_type(self)) and not needs_inittable;
setdef:
is_intregable:=is_smallset(self);
+ arraydef:
+ is_intregable:=not(is_special_array(self)) and
+ (tarraydef(self).size in [1,2,4,8]) and tstoreddef(tarraydef(self).elementdef).is_intregable
+{$ifdef SUPPORT_MMX}
+ and not((cs_mmx in current_settings.localswitches) and
+ is_mmx_able_array(self))
+{$endif SUPPORT_MMX}
+ ;
recorddef:
begin
{$ifdef llvm}