mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-01 23:50:23 +02:00
+ implemented thlcgwasm.a_load_regconst_subsetref_intern
This commit is contained in:
parent
7af6e628c8
commit
4120825f50
@ -73,6 +73,7 @@ uses
|
||||
procedure a_load_ref_ref(list : TAsmList;fromsize, tosize : tdef;const sref : treference;const dref : treference);override;
|
||||
procedure a_loadaddr_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister);override;
|
||||
procedure a_load_subsetref_regs_index(list: TAsmList; subsetsize: tdef; loadbitsize: byte; const sref: tsubsetreference; valuereg: tregister); override;
|
||||
procedure a_load_regconst_subsetref_intern(list : TAsmList; fromsize, subsetsize: tdef; fromreg: tregister; const sref: tsubsetreference; slopt: tsubsetloadopt); override;
|
||||
|
||||
{ basic arithmetic operations }
|
||||
procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister); override;
|
||||
@ -1215,6 +1216,244 @@ implementation
|
||||
a_op_const_reg(list,OP_AND,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),valuereg);
|
||||
end;
|
||||
|
||||
procedure thlcgwasm.a_load_regconst_subsetref_intern(list : TAsmList; fromsize, subsetsize: tdef; fromreg: tregister; const sref: tsubsetreference; slopt: tsubsetloadopt);
|
||||
var
|
||||
tmpreg, tmpindexreg, valuereg, extra_value_reg, maskreg: tregister;
|
||||
tosreg, fromsreg: tsubsetregister;
|
||||
tmpref: treference;
|
||||
bitmask: aword;
|
||||
loadsize: torddef;
|
||||
loadbitsize: byte;
|
||||
extra_load: boolean;
|
||||
begin
|
||||
{ the register must be able to contain the requested value }
|
||||
if (fromsize.size*8<sref.bitlen) then
|
||||
internalerror(2006081613);
|
||||
|
||||
get_subsetref_load_info(sref,loadsize,extra_load);
|
||||
loadbitsize:=loadsize.size*8;
|
||||
|
||||
{ load the (first part) of the bit sequence }
|
||||
valuereg:=getintregister(list,osuinttype);
|
||||
a_load_ref_reg(list,loadsize,osuinttype,sref.ref,valuereg);
|
||||
|
||||
{ constant offset of bit sequence? }
|
||||
if not extra_load then
|
||||
begin
|
||||
if (sref.bitindexreg=NR_NO) then
|
||||
begin
|
||||
{ use subsetreg routine, it may have been overridden with an optimized version }
|
||||
tosreg.subsetreg:=valuereg;
|
||||
tosreg.subsetregsize:=def_cgsize(osuinttype);
|
||||
{ subsetregs always count bits from right to left }
|
||||
tosreg.startbit:=sref.startbit;
|
||||
tosreg.bitlen:=sref.bitlen;
|
||||
a_load_regconst_subsetreg_intern(list,fromsize,subsetsize,fromreg,tosreg,slopt);
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (sref.startbit<>0) then
|
||||
internalerror(2006081710);
|
||||
{ should be handled by normal code and will give wrong result }
|
||||
{ on x86 for the '1 shl bitlen' below }
|
||||
if (sref.bitlen=AIntBits) then
|
||||
internalerror(2006081711);
|
||||
|
||||
{ zero the bits we have to insert }
|
||||
if (slopt<>SL_SETMAX) then
|
||||
begin
|
||||
maskreg:=getintregister(list,osuinttype);
|
||||
a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),maskreg);
|
||||
a_op_reg_reg(list,OP_SHL,osuinttype,sref.bitindexreg,maskreg);
|
||||
a_op_reg_reg(list,OP_NOT,osuinttype,maskreg,maskreg);
|
||||
a_op_reg_reg(list,OP_AND,osuinttype,maskreg,valuereg);
|
||||
end;
|
||||
|
||||
{ insert the value }
|
||||
if (slopt<>SL_SETZERO) then
|
||||
begin
|
||||
tmpreg:=getintregister(list,osuinttype);
|
||||
if (slopt<>SL_SETMAX) then
|
||||
a_load_reg_reg(list,fromsize,osuinttype,fromreg,tmpreg)
|
||||
else if (sref.bitlen<>AIntBits) then
|
||||
a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1), tmpreg)
|
||||
else
|
||||
a_load_const_reg(list,osuinttype,-1,tmpreg);
|
||||
if not(slopt in [SL_REGNOSRCMASK,SL_SETMAX]) then
|
||||
a_op_const_reg(list,OP_AND,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),tmpreg);
|
||||
a_op_reg_reg(list,OP_SHL,osuinttype,sref.bitindexreg,tmpreg);
|
||||
a_op_reg_reg(list,OP_OR,osuinttype,tmpreg,valuereg);
|
||||
end;
|
||||
end;
|
||||
{ store back to memory }
|
||||
tmpreg:=getintregister(list,loadsize);
|
||||
a_load_reg_reg(list,osuinttype,loadsize,valuereg,tmpreg);
|
||||
a_load_reg_ref(list,loadsize,loadsize,tmpreg,sref.ref);
|
||||
exit;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ load next value }
|
||||
extra_value_reg:=getintregister(list,osuinttype);
|
||||
tmpref:=sref.ref;
|
||||
inc(tmpref.offset,loadbitsize div 8);
|
||||
|
||||
{ should maybe be taken out too, can be done more efficiently }
|
||||
{ on e.g. i386 with shld/shrd }
|
||||
if (sref.bitindexreg = NR_NO) then
|
||||
begin
|
||||
a_load_ref_reg(list,loadsize,osuinttype,tmpref,extra_value_reg);
|
||||
|
||||
fromsreg.subsetreg:=fromreg;
|
||||
fromsreg.subsetregsize:=def_cgsize(fromsize);
|
||||
tosreg.subsetreg:=valuereg;
|
||||
tosreg.subsetregsize:=def_cgsize(osuinttype);
|
||||
|
||||
{ transfer first part }
|
||||
fromsreg.bitlen:=loadbitsize-sref.startbit;
|
||||
tosreg.bitlen:=fromsreg.bitlen;
|
||||
|
||||
{ valuereg must contain the lower bits of the value at bits [startbit..loadbitsize] }
|
||||
|
||||
{ lower bits of the value ... }
|
||||
fromsreg.startbit:=0;
|
||||
{ ... to startbit }
|
||||
tosreg.startbit:=sref.startbit;
|
||||
case slopt of
|
||||
SL_SETZERO,
|
||||
SL_SETMAX:
|
||||
a_load_regconst_subsetreg_intern(list,fromsize,subsetsize,fromreg,tosreg,slopt);
|
||||
else
|
||||
a_load_subsetreg_subsetreg(list,subsetsize,subsetsize,fromsreg,tosreg);
|
||||
end;
|
||||
{$ifndef cpuhighleveltarget}
|
||||
valuereg:=cg.makeregsize(list,valuereg,def_cgsize(loadsize));
|
||||
a_load_reg_ref(list,loadsize,loadsize,valuereg,sref.ref);
|
||||
{$else}
|
||||
tmpreg:=getintregister(list,loadsize);
|
||||
a_load_reg_reg(list,osuinttype,loadsize,valuereg,tmpreg);
|
||||
a_load_reg_ref(list,loadsize,loadsize,tmpreg,sref.ref);
|
||||
{$endif}
|
||||
|
||||
{ transfer second part }
|
||||
{ extra_value_reg must contain the upper bits of the value at bits [0..bitlen-(loadbitsize-startbit)] }
|
||||
|
||||
fromsreg.startbit:=fromsreg.bitlen;
|
||||
tosreg.startbit:=0;
|
||||
tosreg.subsetreg:=extra_value_reg;
|
||||
fromsreg.bitlen:=sref.bitlen-fromsreg.bitlen;
|
||||
tosreg.bitlen:=fromsreg.bitlen;
|
||||
|
||||
case slopt of
|
||||
SL_SETZERO,
|
||||
SL_SETMAX:
|
||||
a_load_regconst_subsetreg_intern(list,fromsize,subsetsize,fromreg,tosreg,slopt);
|
||||
else
|
||||
a_load_subsetreg_subsetreg(list,subsetsize,subsetsize,fromsreg,tosreg);
|
||||
end;
|
||||
tmpreg:=getintregister(list,loadsize);
|
||||
a_load_reg_reg(list,osuinttype,loadsize,extra_value_reg,tmpreg);
|
||||
a_load_reg_ref(list,loadsize,loadsize,tmpreg,tmpref);
|
||||
exit;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (sref.startbit <> 0) then
|
||||
internalerror(2006081812);
|
||||
{ should be handled by normal code and will give wrong result }
|
||||
{ on x86 for the '1 shl bitlen' below }
|
||||
if (sref.bitlen = AIntBits) then
|
||||
internalerror(2006081713);
|
||||
|
||||
{ generate mask to zero the bits we have to insert }
|
||||
if (slopt <> SL_SETMAX) then
|
||||
begin
|
||||
maskreg := getintregister(list,osuinttype);
|
||||
a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),maskreg);
|
||||
a_op_reg_reg(list,OP_SHL,osuinttype,sref.bitindexreg,maskreg);
|
||||
|
||||
a_op_reg_reg(list,OP_NOT,osuinttype,maskreg,maskreg);
|
||||
a_op_reg_reg(list,OP_AND,osuinttype,maskreg,valuereg);
|
||||
end;
|
||||
|
||||
{ insert the value }
|
||||
if (slopt <> SL_SETZERO) then
|
||||
begin
|
||||
tmpreg := getintregister(list,osuinttype);
|
||||
if (slopt <> SL_SETMAX) then
|
||||
a_load_reg_reg(list,fromsize,osuinttype,fromreg,tmpreg)
|
||||
else if (sref.bitlen <> AIntBits) then
|
||||
a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen) - 1), tmpreg)
|
||||
else
|
||||
a_load_const_reg(list,osuinttype,-1,tmpreg);
|
||||
if not(slopt in [SL_REGNOSRCMASK,SL_SETMAX]) then
|
||||
{ mask left over bits }
|
||||
a_op_const_reg(list,OP_AND,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),tmpreg);
|
||||
a_op_reg_reg(list,OP_SHL,osuinttype,sref.bitindexreg,tmpreg);
|
||||
a_op_reg_reg(list,OP_OR,osuinttype,tmpreg,valuereg);
|
||||
end;
|
||||
tmpreg:=getintregister(list,loadsize);
|
||||
a_load_reg_reg(list,osuinttype,loadsize,valuereg,tmpreg);
|
||||
a_load_reg_ref(list,loadsize,loadsize,tmpreg,sref.ref);
|
||||
|
||||
{ make sure we do not read/write past the end of the array }
|
||||
a_cmp_const_reg_stack(list,osuinttype,OC_A,loadbitsize-sref.bitlen,sref.bitindexreg);
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
|
||||
incblock;
|
||||
decstack(current_asmdata.CurrAsmList,1);
|
||||
|
||||
a_load_ref_reg(list,loadsize,osuinttype,tmpref,extra_value_reg);
|
||||
tmpindexreg:=getintregister(list,osuinttype);
|
||||
|
||||
{ load current array value }
|
||||
if (slopt<>SL_SETZERO) then
|
||||
begin
|
||||
tmpreg:=getintregister(list,osuinttype);
|
||||
if (slopt<>SL_SETMAX) then
|
||||
a_load_reg_reg(list,fromsize,osuinttype,fromreg,tmpreg)
|
||||
else if (sref.bitlen<>AIntBits) then
|
||||
a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen) - 1), tmpreg)
|
||||
else
|
||||
a_load_const_reg(list,osuinttype,-1,tmpreg);
|
||||
end;
|
||||
|
||||
{ generate mask to zero the bits we have to insert }
|
||||
if (slopt<>SL_SETMAX) then
|
||||
begin
|
||||
maskreg:=getintregister(list,osuinttype);
|
||||
|
||||
{ Y-x = -(x-Y) }
|
||||
a_op_const_reg_reg(list,OP_SUB,osuinttype,loadbitsize,sref.bitindexreg,tmpindexreg);
|
||||
a_op_reg_reg(list,OP_NEG,osuinttype,tmpindexreg,tmpindexreg);
|
||||
a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),maskreg);
|
||||
a_op_reg_reg(list,OP_SHR,osuinttype,tmpindexreg,maskreg);
|
||||
|
||||
a_op_reg_reg(list,OP_NOT,osuinttype,maskreg,maskreg);
|
||||
a_op_reg_reg(list,OP_AND,osuinttype,maskreg,extra_value_reg);
|
||||
end;
|
||||
|
||||
if (slopt<>SL_SETZERO) then
|
||||
begin
|
||||
if not(slopt in [SL_REGNOSRCMASK,SL_SETMAX]) then
|
||||
a_op_const_reg(list,OP_AND,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),tmpreg);
|
||||
a_op_reg_reg(list,OP_SHR,osuinttype,tmpindexreg,tmpreg);
|
||||
a_op_reg_reg(list,OP_OR,osuinttype,tmpreg,extra_value_reg);
|
||||
end;
|
||||
{$ifndef cpuhighleveltarget}
|
||||
extra_value_reg:=cg.makeregsize(list,extra_value_reg,def_cgsize(loadsize));
|
||||
a_load_reg_ref(list,loadsize,loadsize,extra_value_reg,tmpref);
|
||||
{$else}
|
||||
tmpreg:=getintregister(list,loadsize);
|
||||
a_load_reg_reg(list,osuinttype,loadsize,extra_value_reg,tmpreg);
|
||||
a_load_reg_ref(list,loadsize,loadsize,tmpreg,tmpref);
|
||||
{$endif}
|
||||
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
|
||||
decblock;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure thlcgwasm.a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister);
|
||||
begin
|
||||
a_op_const_reg_reg(list,op,size,a,reg,reg);
|
||||
|
Loading…
Reference in New Issue
Block a user