Browse Source

+ implemented thlcgwasm.a_load_regconst_subsetref_intern

Nikolay Nikolov 3 years ago
parent
commit
4120825f50
1 changed files with 239 additions and 0 deletions
  1. 239 0
      compiler/wasm32/hlcgcpu.pas

+ 239 - 0
compiler/wasm32/hlcgcpu.pas

@@ -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);