summaryrefslogtreecommitdiff
path: root/compiler/hlcgobj.pas
diff options
context:
space:
mode:
authorjonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2>2019-06-02 18:32:58 +0000
committerjonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2>2019-06-02 18:32:58 +0000
commit48b22f52ffc42a204d58fca15354f5fcc868bb1f (patch)
treea114136633018a419eba1bf88773e5c8b397a4cd /compiler/hlcgobj.pas
parentdebc92e3d20f279c95035e92fbaaa91689a3bbb2 (diff)
downloadfpc-48b22f52ffc42a204d58fca15354f5fcc868bb1f.tar.gz
* support for handling subsetrefs with bitlen > AIntBits in a_load_subsetref_reg() and
a_load_const/reg_subsetref() (needed for handling 32 bit platforms using a purely high level code generator like LLVM's, and may also improve the situation for 16 bit platforms) o can probably be optimized to split them into parts that cover partial word loads and complete word loads (to reduce useless merging) git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@42165 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'compiler/hlcgobj.pas')
-rw-r--r--compiler/hlcgobj.pas105
1 files changed, 104 insertions, 1 deletions
diff --git a/compiler/hlcgobj.pas b/compiler/hlcgobj.pas
index 0a1b7f5704..627b36c0e4 100644
--- a/compiler/hlcgobj.pas
+++ b/compiler/hlcgobj.pas
@@ -1416,12 +1416,57 @@ implementation
procedure thlcgobj.a_load_subsetref_reg(list: TAsmList; fromsubsetsize, tosize: tdef; const sref: tsubsetreference; destreg: tregister);
var
tmpref: treference;
- valuereg,extra_value_reg: tregister;
+ valuereg,extra_value_reg, tmpreg: tregister;
tosreg: tsubsetregister;
loadsize: torddef;
loadbitsize: byte;
extra_load: boolean;
+ tmpsref: tsubsetreference;
begin
+ if sref.bitlen>AIntBits then
+ begin
+ tmpsref:=sref;
+ tmpsref.bitlen:=AIntBits;
+ valuereg:=hlcg.getintregister(list,tosize);
+ a_load_subsetref_reg(list,sinttype,tosize,tmpsref,valuereg);
+ tmpsref.bitlen:=sref.bitlen-AIntBits;
+ inc(tmpsref.ref.offset,AIntBits div 8);
+ extra_value_reg:=hlcg.getintregister(list,tosize);
+ a_load_subsetref_reg(list,sinttype,tosize,tmpsref,extra_value_reg);
+ { can't use a_load_reg_subsetreg to merge the results, as that one
+ does not support sizes > AIntBits either }
+ tmpreg:=hlcg.getintregister(list,tosize);
+ if target_info.endian=endian_big then
+ begin
+ a_op_const_reg_reg(list,OP_SHL,tosize,sref.bitlen-AIntBits,valuereg,tmpreg);
+ if is_signed(fromsubsetsize) then
+ begin
+ valuereg:=tmpreg;
+ tmpreg:=hlcg.getintregister(list,tosize);
+ a_op_const_reg_reg(list,OP_AND,tosize,(tcgint(1) shl (sref.bitlen-AIntBits))-1,extra_value_reg,tmpreg);
+ valuereg:=tmpreg;
+ end
+ end
+ else
+ begin
+ a_op_const_reg_reg(list,OP_SHL,tosize,AIntBits,extra_value_reg,tmpreg);
+ if is_signed(fromsubsetsize) then
+ begin
+ extra_value_reg:=hlcg.getintregister(list,tosize);
+ a_op_const_reg_reg(list,OP_AND,tosize,(tcgint(1) shl AIntBits)-1,valuereg,extra_value_reg);
+ valuereg:=extra_value_reg;
+ end
+ end;
+ if is_signed(fromsubsetsize) then
+ begin
+ extra_value_reg:=hlcg.getintregister(list,tosize);
+ a_op_const_reg_reg(list,OP_AND,tosize,(tcgint(1) shl AIntBits)-1,valuereg,extra_value_reg);
+ valuereg:=extra_value_reg;
+ end;
+ a_op_reg_reg_reg(list,OP_OR,tosize,valuereg,tmpreg,destreg);
+ exit;
+ end;
+
get_subsetref_load_info(sref,loadsize,extra_load);
loadbitsize:=loadsize.size*8;
@@ -1512,7 +1557,37 @@ implementation
end;
procedure thlcgobj.a_load_reg_subsetref(list: TAsmList; fromsize, tosubsetsize: tdef; fromreg: tregister; const sref: tsubsetreference);
+ var
+ tmpsref: tsubsetreference;
+ fromreg1: tregister;
begin
+ if sref.bitlen>AIntBits then
+ begin
+ if ((sref.bitlen mod AIntBits)<>0) then
+ internalerror(2019052901);
+ tmpsref:=sref;
+ tmpsref.bitlen:=AIntBits;
+ fromreg1:=hlcg.getintregister(list,uinttype);
+ a_load_reg_reg(list,fromsize,uinttype,fromreg,fromreg1);
+ if target_info.endian=endian_big then
+ begin
+ inc(tmpsref.ref.offset,sref.bitlen-AIntBits);
+ end;
+ a_load_reg_subsetref(list,uinttype,uinttype,fromreg1,tmpsref);
+ if target_info.endian=endian_big then
+ begin
+ tmpsref.ref.offset:=sref.ref.offset;
+ end
+ else
+ begin
+ inc(tmpsref.ref.offset,AIntBits div 8);
+ end;
+ tmpsref.bitlen:=sref.bitlen-AIntBits;
+ fromreg1:=hlcg.getintregister(list,fromsize);
+ hlcg.a_op_const_reg_reg(list,OP_SHR,fromsize,AIntBits,fromreg,fromreg1);
+ a_load_reg_subsetref(list,fromsize,tosubsetsize,fromreg1,tmpsref);
+ exit;
+ end;
a_load_regconst_subsetref_intern(list,fromsize,tosubsetsize,fromreg,sref,SL_REG);
end;
@@ -1545,9 +1620,37 @@ implementation
procedure thlcgobj.a_load_const_subsetref(list: TAsmlist; tosubsetsize: tdef; a: tcgint; const sref: tsubsetreference);
var
+ tmpref: treference;
+ tmpsref: tsubsetreference;
tmpreg: tregister;
slopt: tsubsetloadopt;
+ newdef: tdef;
+ newbytesize: longint;
+ loval, hival: longint;
begin
+ if sref.bitlen>AIntBits then
+ begin
+ if ((sref.bitlen mod AIntBits)<>0) then
+ internalerror(2019052901);
+ tmpsref:=sref;
+ tmpsref.bitlen:=AIntBits;
+ if target_info.endian=endian_big then
+ begin
+ inc(tmpsref.ref.offset,sref.bitlen-AIntBits);
+ end;
+ a_load_const_subsetref(list,tosubsetsize,aint(a),tmpsref);
+ if target_info.endian=endian_big then
+ begin
+ tmpsref.ref.offset:=sref.ref.offset;
+ end
+ else
+ begin
+ inc(tmpsref.ref.offset,AIntBits div 8);
+ end;
+ tmpsref.bitlen:=sref.bitlen-AIntBits;
+ a_load_const_subsetref(list,tosubsetsize,a shr AIntBits,tmpsref);
+ exit;
+ end;
{ perform masking of the source value in advance }
slopt:=SL_REGNOSRCMASK;
if (sref.bitlen<>AIntBits) then