diff options
author | jonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2019-06-02 18:32:58 +0000 |
---|---|---|
committer | jonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2019-06-02 18:32:58 +0000 |
commit | 48b22f52ffc42a204d58fca15354f5fcc868bb1f (patch) | |
tree | a114136633018a419eba1bf88773e5c8b397a4cd | |
parent | debc92e3d20f279c95035e92fbaaa91689a3bbb2 (diff) | |
download | fpc-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
-rw-r--r-- | compiler/hlcgobj.pas | 105 |
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 |