|
@@ -73,6 +73,7 @@ uses
|
|
procedure a_load_ref_ref(list : TAsmList;fromsize, tosize : tdef;const sref : treference;const dref : treference);override;
|
|
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_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_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 }
|
|
{ basic arithmetic operations }
|
|
procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister); override;
|
|
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);
|
|
a_op_const_reg(list,OP_AND,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),valuereg);
|
|
end;
|
|
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);
|
|
procedure thlcgwasm.a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister);
|
|
begin
|
|
begin
|
|
a_op_const_reg_reg(list,op,size,a,reg,reg);
|
|
a_op_const_reg_reg(list,op,size,a,reg,reg);
|